Cloudflare Tunnel: expose your home server without opening ports
I have a Mac mini M4 at home serving this website, the blog, Moodle and several tools. For a long time I assumed that exposing anything to the internet meant opening ports on the router, dealing with dynamic IPs and hoping the ISP wouldn’t block incoming traffic. Cloudflare Tunnel solved all of that at once.
What is Cloudflare Tunnel
Cloudflare Tunnel is a free service that creates an outbound encrypted connection between your server and the Cloudflare network. Instead of the internet reaching your server, it’s your server that reaches out to Cloudflare. Result: no open ports, no exposed IP, no router headaches.
Traffic flows like this:
User → Cloudflare (CDN + SSL) → Tunnel → Your home server
All encrypted, with SSL certificates managed automatically by Cloudflare.
Why it’s better than the alternatives
- No dynamic IP issues: it doesn’t matter if your ISP changes your IP every day
- No open ports: your router doesn’t even know you have a server
- Automatic SSL: Cloudflare manages certificates, no Let’s Encrypt or manual renewals
- DDoS protection included: the free plan already absorbs basic attacks
- Zero Trust: you can restrict access to entire subdomains to specific users
Requirements
- A Cloudflare account (free)
- A domain managed by Cloudflare
cloudflaredinstalled on the server
On macOS with Homebrew:
1brew install cloudflared
Step by step setup
1. Authenticate
1cloudflared tunnel login
Opens a browser, you select the domain and you’re done.
2. Create the tunnel
1cloudflared tunnel create my-server
Save the UUID it returns — you’ll need it.
3. Create the configuration file
1# ~/.cloudflared/config.yml
2tunnel: <tunnel-UUID>
3credentials-file: /Users/youruser/.cloudflared/<UUID>.json
4
5ingress:
6 - hostname: web.yourdomain.com
7 service: http://localhost:80
8 - hostname: moodle.yourdomain.com
9 service: http://localhost:80
10 - service: http_status:404
4. Create DNS records
1cloudflared tunnel route dns my-server web.yourdomain.com
2cloudflared tunnel route dns my-server moodle.yourdomain.com
This automatically creates CNAME records in Cloudflare pointing to the tunnel.
5. Start the tunnel
1cloudflared tunnel run my-server
To start it automatically at system boot:
1sudo cloudflared service install
2sudo launchctl start com.cloudflare.cloudflared
How I use it
In my case several subdomains go through the tunnel: the main website, Moodle at aula.sergiocomeron.com and the development environment. Apache receives all requests on localhost:80 and routes them by VirtualHost based on the ServerName.
One important thing: Cloudflare acts as a reverse proxy, so the IP Apache receives is Cloudflare’s, not the visitor’s. To get the real IP you need to tell Apache to use the CF-Connecting-IP header:
1RemoteIPHeader CF-Connecting-IP
2RemoteIPTrustedProxy 127.0.0.1 ::1
Without this, all access appears in the logs with Cloudflare’s IP and IP-based rate limiting won’t work correctly.
Zero Trust: restricted access by user
If you have a subdomain you only want yourself to access — an admin panel, an internal service — Cloudflare Zero Trust lets you protect it with Google, GitHub or email login without touching the application code. Configure it in the Cloudflare dashboard and the tunnel does the rest.
Conclusion
I’ve had this setup in production for over a year without a single problem. The free Cloudflare plan covers everything a personal or small business server needs. If you have a home server and you’re still opening ports on the router, Cloudflare Tunnel is the easiest and most secure change you can make.