Cloudflare Tunnels let you expose any web service to the internet without opening firewall ports, configuring NAT, or dealing with ISP blocks. They're free, fast, and dead simple to set up.
Why Tunnels?
Traditional hosting involves port forwarding, static IPs, and DNS propagation waits. Tunnels bypass all of that:
- No open ports — The tunnel initiates outbound. Your firewall stays closed.
- Random ports work — Running something on port 8897? The tunnel doesn't care.
- HTTPS automatically — Cloudflare handles the cert.
- Free — Up to 100 tunnels, no charge.
The One-Liner
The quickest way to get started on any machine:
curl -sL https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64 -o cloudflared
chmod +x cloudflared
./cloudflared tunnel --url http://localhost:8897
This creates a random *.trycloudflare.com URL pointing to your local service. For development and demos, that's all you need.
Permanent Tunnels
For a permanent tunnel (like a production site), you need to authenticate once:
cloudflared tunnel login
This opens a browser to authorize your Cloudflare account. Then create a tunnel:
cloudflared tunnel create my-project
This generates a credentials file and a tunnel ID. Now configure it:
# ~/.cloudflared/config.yaml
tunnel: <tunnel-id>
credentials-file: /root/.cloudflared/<tunnel-id>.json
ingress:
- hostname: myproject.com
service: http://localhost:8897
- service: http_status:404
Point your DNS at the tunnel:
cloudflared tunnel route dns my-project myproject.com
Then run it:
cloudflared tunnel run my-project
Running as a Service
For production, run it as a systemd service:
cloudflared service install
It auto-restarts on failure, logs to journald, and stays out of your way. Check status with:
systemctl status cloudflared
Per-Project Ports
A useful pattern: run each project on a different local port, then point a separate tunnel at each one:
| Project | Local Port | Tunnel Hostname | |---|---|---| | handycanadian.ca | 8897 | handycanadian.ca | | unofficialtutorials.com | 8898 | unofficialtutorials.com | | flashmart.ca | 8899 | flashmart.ca |
This keeps everything isolated. If one project crashes, it doesn't affect the others. You just restart that single cloudflared tunnel.
The One Catch
Since Cloudflare acts as a reverse proxy, your access logs show Cloudflare's IPs, not the visitor's real IP. You need to configure your web server to read the CF-Connecting-IP header for real visitor IPs.
In Apache, add to your config:
RemoteIPHeader CF-Connecting-IP
RemoteIPTrustedProxy 173.245.48.0/20
In PHP:
$realIp = $_SERVER['HTTP_CF_CONNECTING_IP'] ?? $_SERVER['REMOTE_ADDR'];
Tear Down
When you're done with a project:
cloudflared tunnel delete my-project
cloudflared tunnel route dns remove my-project myproject.com
That's it. No stale DNS records, no orphaned ports, no lingering infrastructure.
Summary
Cloudflare Tunnels are the simplest way to put a project online. One curl command for quick tests, a few config lines for permanent setups. Free, secure, and works with anything running on any port.