Understanding Cloudflare Tunnels
Safely Exposing Services Without Opening Ports
Learning Cloudflare Tunnels: Safely Exposing Services Without Opening Ports
As a backend engineer, I’ve spent a long time dealing with the “classic” way of exposing services to the internet: opening ports, configuring firewalls, managing TLS certificates, and hoping nothing breaks or gets exploited.
Recently, I decided to properly understand Cloudflare Tunnels, a concept I had heard about often but never deeply explored. What started as curiosity quickly turned into a “why didn’t I learn this earlier?” moment.
This post documents my learning journey from zero intuition to a clear mental model written for anyone who wants to understand Cloudflare Tunnels without a deep networking background.
The Traditional Way
Let’s start with a very common setup.
You have:
- A web app running on your laptop or a private server
- It’s accessible at
http://localhost:8000 - You want to access it from the internet
Traditionally, this means:
Internet
|
| (open port 8000)
v
┌─────────────────┐
│ Router/Firewall │
└─────────────────┘
|
v
┌─────────────────┐
│ Your Server │
│ localhost:8000 │
└─────────────────┘This approach has problems:
- You must open ports (security risk)
- Your public IP is exposed
- TLS certificates must be managed manually
- Many networks (home ISPs, offices) block inbound traffic
First Intuition: What Is a Cloudflare Tunnel?
The key idea that changed everything for me:
You never expose your server to the internet. Your server connects outward to Cloudflare instead.
You run a lightweight agent called cloudflared on your machine. That agent establishes a secure outbound connection to Cloudflare.
Since outbound connections are almost always allowed:
- No ports need to be opened
- NAT and firewalls stop being a problem
- Your origin server stays private
The Mental Model That Made It Click
Here’s the analogy that finally made it intuitive:
- Your app lives inside a locked house
- The internet is outside
- Cloudflare is a guarded checkpoint
Instead of opening your door to everyone:
- Your app walks out and establishes a private tunnel to Cloudflare
- Visitors talk only to Cloudflare
- Cloudflare forwards approved traffic through the tunnel
Diagram: Traditional vs Cloudflare Tunnel
Traditional (Port Forwarding)
Internet Users
|
| (public IP + open port)
v
┌─────────────────┐
│ Your Server │ <- Directly exposed
│ localhost:8000 │
└─────────────────┘With Cloudflare Tunnel
Internet Users
|
v
┌─────────────────┐
│ Cloudflare Edge │ <- Public-facing
└─────────────────┘
|
| (encrypted tunnel)
v
┌─────────────────┐
│ cloudflared │
│ daemon │
└─────────────────┘
|
v
┌─────────────────┐
│ Local App │ <- Private
│ localhost:8000 │
└─────────────────┘Your server never directly faces the internet.
How Traffic Flows
- A user visits
https://myapp.ak.com - DNS routes the request to Cloudflare
- Cloudflare handles HTTPS and security checks
- Cloudflare forwards the request through the tunnel
- Your local app receives it on
localhost:8000 - The response travels back the same way
All traffic is encrypted end-to-end.
Setting Up a Cloudflare Tunnel
Below is the minimum set of commands needed to get a tunnel running.
1. Install cloudflared
macOS
brew install cloudflaredLinux (Debian/Ubuntu)
curl -L https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb \
-o cloudflared.deb
sudo dpkg -i cloudflared.deb2. Authenticate with Cloudflare
cloudflared tunnel loginThis opens a browser and asks you to log in and select a domain. Cloudflare now trusts this machine.
3. Create a Tunnel
cloudflared tunnel create my-tunnelThis creates:
- A tunnel ID
- A credentials JSON file on your machine
4. Configure the Tunnel
Create ~/.cloudflared/config.yml:
tunnel: my-tunnel
credentials-file: /Users/amish/.cloudflared/<tunnel-id>.json
ingress:
- hostname: myapp.ak.com
service: http://localhost:8000
- service: http_status:404This means:
- Requests to
myapp.ak.comgo tolocalhost:8000 - Everything else returns 404
5. Route DNS to the Tunnel
cloudflared tunnel route dns my-tunnel myapp.ak.comCloudflare automatically creates the DNS record.
6. Run the Tunnel
cloudflared tunnel run my-tunnelNow your local app is live at: https://myapp.ak.com
No open ports. No public IP exposure.
What Problems This Solves Instantly
- No port forwarding
- No public IP exposure
- No manual TLS setup
- Automatic HTTPS
- DDoS protection
- Works behind NAT, CGNAT, hotel Wi-Fi
Common Use Cases
Cloudflare Tunnels are perfect for:
- Local development demos
- Internal dashboards
- Home-lab services
- Receiving webhooks on localhost
- Temporary or experimental apps
Anything that should be reachable but not exposed.
How This Changed My Mental Model
Before learning Cloudflare Tunnels, I believed:
“To expose a service, I must open a port.”
After learning this, my default became:
“I should avoid opening ports unless there’s no alternative.”
That’s a meaningful shift in how I think about security and infrastructure.
Final Takeaway
Cloudflare Tunnels feel like a modern default:
- Secure by design
- Simple to reason about
- Friendly for developers
- Powerful enough for production use