[Chapter 1] Serving Subdomains with Cloudflare
Lately I've needed multiple domains — spinning up several AI agents and deploying various libraries as services.
I've been using Cloudflare as my domain provider, and tunneling makes serving extremely convenient without having to deal with a home router.
Let's take a look.
1. Why Cloudflare Tunnel
Traditional approach:
- Router port forwarding
- Public IP exposure
- Security vulnerabilities
Cloudflare Tunnel approach:
- Server → Cloudflare outbound connection
- No direct external access to the server
- IP hidden
- HTTPS applied automatically
2. Overall Architecture
User → Cloudflare → Tunnel → Server → Service
Internet traffic is HTTPS; internal server traffic can be HTTP.
3. Installation
wget https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb
sudo dpkg -i cloudflared-linux-amd64.deb
4. Login
cloudflared tunnel login
5. Create a Tunnel
cloudflared tunnel create my-tunnel
6. Connect DNS
cloudflared tunnel route dns my-tunnel app.example.com
7. Write the Config
cat > ~/.cloudflared/config.yml <<EOF
tunnel: my-tunnel
credentials-file: ~/.cloudflared/xxxxx.json
ingress:
- hostname: app.example.com
service: http://localhost:3000
- service: http_status:404
EOF
8. Run
cloudflared tunnel run my-tunnel
9. Register as a Service
mkdir -p /etc/cloudflared
cp ~/.cloudflared/* /etc/cloudflared/
cat > /etc/systemd/system/cloudflared.service <<EOF
[Unit]
Description=Cloudflare Tunnel
After=network-online.target
[Service]
ExecStart=/usr/bin/cloudflared tunnel --config /etc/cloudflared/config.yml run
Restart=always
User=root
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable --now cloudflared
10. Key Checklist
- Verify the JSON credentials path
- Distinguish between HTTP and HTTPS
- Check for duplicate DNS entries
Follow this guide and you can expose your server publicly without any port forwarding.