[Chapter 2] Serving Subdomains with Cloudflare
Let's walk through this with some concrete examples.
Here's the home lab setup used throughout:
Example environment:
- hr106 → blog
- hr107 → playground
- hr109 → geny
- Domain: hrletsgo.me
1. Overall Architecture
Internet
│
Cloudflare
│
┌───────┼────────┐
│ │ │
hr106 hr107 hr109
(blog) (playground) (geny)
│ │ │
cloudflared cloudflared cloudflared
│ │ │
nginx nginx nginx
│ │ │
frontend/backend services (docker)
Key characteristics:
- Each server runs its own independent tunnel
- No external port forwarding
- All traffic routed through Cloudflare
2. Why This Architecture Works
Traditional approach
인터넷 → 공유기 → 서버
Problems:
- Exposed ports
- Exposed IP
- Larger attack surface
Tunnel approach
서버 → Cloudflare (outbound)
Benefits:
- No inbound ports
- Server IP is hidden
- DDoS / WAF protection
3. Per-Server Tunnel Strategy
Recommended approach
- One tunnel per server
Example:
hr106 → hr106 tunnel → hrletsgo.me
hr107 → hr107 tunnel → playground.hrletsgo.me
hr109 → hr109 tunnel → geny.hrletsgo.me
This approach offers:
- Easier debugging
- Fault isolation
- Simpler operations
4. nginx + Docker Layout
Recommended structure for each server:
cloudflared
↓
nginx (reverse proxy)
↓
docker services
Example port assignments:
- backend: 8000
- frontend: 3000
- nginx: 80
- host: 58443 → 80
5. HTTP vs HTTPS Design
Principle
- External: HTTPS (Cloudflare)
- Internal: HTTP (localhost)
Rationale
Cloudflare → cloudflared → localhost
This path is:
- On the same server
- Not exposed externally
HTTP is sufficient here.
6. When to Use an HTTPS Origin
Use HTTPS when the target is not localhost:
- cloudflared → a different server
- cloudflared → NAS
- cloudflared → VM
7. Cloudflare Access (Highly Recommended)
Apply this to any sensitive service:
- admin panels
- AI servers
- internal APIs
Flow:
사용자 → 로그인 → Cloudflare → 서버
Supported identity providers:
- Google login
- GitHub login
- OTP
8. SSH Tunnel
Eliminates the need for port forwarding entirely.
ssh → Cloudflare → tunnel → 서버
Benefits:
- Port 22 can be closed
- Blocks external attacks
9. Operational Tips
1. Check running services
docker ps
ss -tlnp
2. Determine HTTP vs HTTPS
curl http://localhost:포트
curl -vk https://localhost:포트
3. Check logs
journalctl -u cloudflared -f
10. Common Failure Types
502 Bad Gateway
- Origin is down
- Wrong port
1033
- Tunnel is not running
TLS error
- Connecting via HTTPS to an HTTP-only origin
11. Scaling Patterns
Option 1: Per-server tunnels
- Simple
- Recommended
Option 2: Centralized reverse proxy
Cloudflare → 1 tunnel → nginx → 여러 서비스
- Easier to manage centrally
- Adds complexity
12. Recommended Operating Principles
- One tunnel per server
- Single nginx entry point
- Use Docker internal networks
- Remove all external port forwarding
- Apply Cloudflare Access
13. Real-World Configuration Examples
blog
hrletsgo.me → hr106 → nginx → blog
playground
playground.hrletsgo.me → hr107 → nginx → app
geny
geny.hrletsgo.me → hr109 → nginx → AI agent
14. Key Takeaways
- Tunnel = outbound connection
- No port forwarding needed
- HTTP to localhost is safe
- DNS resolves through the tunnel
- Use systemd to keep it always running