If you self-host services, you face a dilemma: you want them accessible from the internet, but opening ports invites attacks. Port scanners find open SSH (22), HTTP (80), and custom ports within minutes.
Cloudflare Tunnel solves this elegantly: no open ports at all.
How Cloudflare Tunnel Works
Instead of opening a firewall port, your server establishes an outbound connection to Cloudflare's edge. Traffic comes into Cloudflare, goes through their network, and is forwarded to your server via this tunnel.
User → Cloudflare Edge → Encrypted Tunnel → Your Server (port closed)
Your ISP sees only an outbound connection to Cloudflare. No incoming ports. No port scans. No DDoS on your IP.
Step 1: Install cloudflared
# Linux (amd64)
curl -L https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64 -o /usr/local/bin/cloudflared
chmod +x /usr/local/bin/cloudflared
# Or via package manager
apt install cloudflared # Debian/Ubuntu
Step 2: Authenticate
cloudflared tunnel login
This opens a browser to authenticate with your Cloudflare account. In headless environments, use an API token instead:
cloudflared tunnel login --token YOUR_TOKEN
Step 3: Create a Tunnel
cloudflared tunnel create my-tunnel
This creates a tunnel with a unique ID and downloads a credentials file.
Step 4: Configure DNS
cloudflared tunnel route dns my-tunnel service.yourdomain.com
This creates a CNAME record in your Cloudflare DNS pointing to the tunnel.
Step 5: Configure and Run
Create a config file:
# ~/.cloudflared/config.yaml
tunnel: your-tunnel-uuid
credentials-file: /path/to/credentials.json
ingress:
- hostname: service.yourdomain.com
service: http://localhost:8080
- hostname: docs.yourdomain.com
service: http://localhost:3000
- service: http_status:404
Run:
cloudflared tunnel run my-tunnel
For production, install as a system service:
cloudflared service install
Use Cases I Run
Here's what I expose through Cloudflare Tunnel:
| Service | Local Port | Public URL |
|---------|-----------|------------|
| Vikunja (task manager) | 3456 | todo.yourdomain.com |
| Vaultwarden (password manager) | 8087 | vault.yourdomain.com |
| EasyImage (image hosting) | 8080 | images.yourdomain.com |
| Home Assistant | 8123 | home.yourdomain.com |
All of these have zero open ports on my firewall. The tunnel handles everything.
Security Features
Cloudflare Tunnel provides several security benefits out of the box:
- **No open ports** — Port scanners find nothing
- **Free TLS/SSL** — Automatic certificate management
- **DDoS protection** — Cloudflare's network absorbs attacks
- **Access policies** — Require Google login or one-time PIN for sensitive services
- **Audit logging** — See who accessed what
Troubleshooting Common Issues
ISP Throttling UDP (QUIC)
Cloudflare Tunnel defaults to QUIC (UDP). Some ISPs throttle UDP. Force HTTP2 (TCP):
ingress:
- hostname: service.yourdomain.com
service: http://localhost:8080
tunnel: your-tunnel-uuid
credentials-file: /path/to/credentials.json
protocol: http2 # Force TCP instead of QUIC
Connection Drops
Add auto-restart to your tunnel service:
# In systemd service file
Restart=always
RestartSec=5
Multiple Tunnels
Each tunnel can serve multiple services. Just add more ingress rules. Use one tunnel per server.
Cost
Cloudflare Tunnel is free for unlimited tunnels and traffic. The only cost is your domain (Cloudflare DNS must be active on your domain, which is also free).
Verdict
Cloudflare Tunnel is the safest way to expose self-hosted services. It's free, secure, and takes 10 minutes to set up. For anyone running services at home, it's non-negotiable.