Setting Up Cloudflare Tunnel: Secure Access Without Opening Router Ports
A step-by-step guide to setting up Cloudflare Tunnel with Docker. Securely expose your local services to the internet without configuring your router.
Cloudflare Tunnel (also known as cfd or cloudflared) is a revolutionary solution for exposing local services to the internet securely - without needing to open any ports on your router.
In this tutorial, I'll show you how to set up and configure Cloudflare Tunnel using Docker.
Why Cloudflare Tunnel?
Traditionally, exposing services to the internet required port forwarding on your router (NAT). This comes with several drawbacks:
- Insecure - anyone can potentially access your services
- Cumbersome - every change requires router configuration
- Problematic - with dynamic IPs, you need DDNS
Cloudflare Tunnel solves all these problems:
- 🔒 Secure - only allowed domains can access your services
- 🌐 No router setup - no port forwarding needed
- ⚡ Fast - QUIC protocol for low latency
- 🛡️ DDoS protection - Cloudflare filters malicious traffic
- 🔑 Free - for most use cases
Prerequisites
- A Cloudflare account with a domain
- Docker and Docker Compose on your server
- A service you want to expose
Step 1: Create a Tunnel
First, create a new Cloudflare Tunnel. The easiest way is via the Cloudflare Dashboard:
- Go to Zero Trust Dashboard → Networks → Tunnels
- Click Add tunnel
- Choose Cloudflare Tunnel as the type
- Give your tunnel a name (e.g.,
my-server) - Save the generated token
Step 2: Set Up Docker Compose
Create a docker-compose.yml file:
services:
cloudflared:
image: cloudflare/cloudflared:latest
container_name: cloudflared
network_mode: host
restart: unless-stopped
environment:
- TUNNEL_TOKEN=your_tunnel_token_here
command: tunnel run
Replace your_tunnel_token_here with the token from Step 1.
network_mode: host, you can reach services via localhost. This is simpler than host.docker.internal.
Step 3: Configure Ingress Rules
Ingress rules determine which domain points to which service. You can configure this in the Dashboard or via the API.
Example configuration:
ingress:
- hostname: example.com
service: http://localhost:3000
originRequest:
noTLSVerify: false
- hostname: admin.example.com
service: http://localhost:8080
originRequest:
noTLSVerify: false
- service: http_status:404
The last rule http_status:404 catches all undefined requests.
Step 4: Create DNS Records
For each subdomain you want to use, create a CNAME record:
- Type: CNAME
- Name: example.com (or subdomain)
- Content: {tunnel-id}.cfargotunnel.com
- Proxy status: Proxied
Step 5: Test
Start the container:
docker compose up -d
Check the logs:
docker logs cloudflared
If everything works, you should see:
INF Registered tunnel connection connIndex=0
INF Updated to new configuration
Your domain should now be accessible through Cloudflare!
Advanced Options
Multiple Services
You can configure as many subdomains as you need. Remember to create a CNAME record for each one.
SSL/TLS
Cloudflare handles SSL certificates automatically. No extra configuration needed.
Websocket Support
Cloudflare Tunnel supports websockets out of the box. No special configuration for most applications.
Conclusion
Cloudflare Tunnel is an elegant solution for exposing self-hosted services securely and easily. No router configuration, no security risks from open ports, and you get Cloudflare's DDoS protection and caching for free.
Need help with setup? Contact us - we're happy to assist with Cloudflare Tunnel and other self-hosted solutions!
Need Help with Setup?
We'd be happy to assist you with Cloudflare Tunnel and other self-hosted solutions.
Get in TouchArticle updated on February 26, 2026