Get Started with Docker - Part 6a: Secure Remote Access with Cloudflare Tunnel
Learn how to deploy cloudflared in Docker to bypass CGNAT and dynamic IPs for zero-trust remote access without opening inbound router ports
With a short break from Homelab duties while we took a detour with AZ-802 let's take a look again at the Get Started with Docker Series
You've installed some self-hosted applications and containers on your server, and you've learned how to proxy them locally using Pi-Hole and Nginx Proxy Manager. But what happens when you want to access your homelab services securely from outside your home network?
Traditionally, people used router port forwarding (opening ports 80 and 443), but exposing open ports to the public internet attracts automated port scanners, botnets, and DDoS attacks.
This is where Cloudflare Tunnel (cloudflared) comes in. It allows you to expose your web services securely to the internet through an outbound connection to Cloudflare's global edge network—without opening a single inbound port on your home router!
We're going to:
- Look at what Cloudflare Tunnel and Cloudflare Zero Trust are
- Set up your persistent Docker Config folders (
Files/AppData/Config/cloudflared) - Create a Cloudflare Tunnel in the Cloudflare Zero Trust Dashboard
- Create our Docker Compose file using Nano Text Editor
- Spin up the
cloudflareddaemon in Docker Compose - Create a Zero-Trust Access Policy with Email OTP MFA and Geo-IP filtering
- Test accessing a local container service securely from the internet
What's Cloudflare Tunnel (cloudflared)?
Cloudflare Tunnel establishes an encrypted, outbound-only connection between a lightweight daemon running in a Docker container on your server (cloudflared) and Cloudflare's edge network.
Because the connection is initiated outbound from inside your network:
- No Inbound Open Ports: You don't need to touch your router's port forwarding settings.
- Hide Your Home IP Address: Public DNS queries point to Cloudflare's proxy IP addresses, masking your residential WAN IP address completely.
- Built-in DDoS Protection: Traffic is filtered by Cloudflare before it ever reaches your home server.
Bypassing CGNAT & No Static IP Required
Many modern ISPs (especially fiber providers, 5G home broadband, Starlink, and mobile networks) use Carrier-Grade NAT (CGNAT) to conserve IPv4 addresses.
Under CGNAT, your ISP shares a single public IP address across hundreds of customers. Because you don't have a unique public IPv4 address, traditional port forwarding is impossible—inbound connections are blocked by your ISP!
Furthermore, even on standard broadband, ISPs assign dynamic IP addresses that change periodically—or charge extra monthly fees for a Static IP.
Cloudflare Tunnel solves both problems effortlessly:
- 💡 Bypasses CGNAT Completely: Because
cloudflaredmakes an outbound connection from inside your network to Cloudflare, it works seamlessly through CGNAT, 5G, and cellular connections. - 💡 No Static IP Needed: You don't need to buy a Static IP from your ISP or manage Dynamic DNS (DDNS) scripts. Cloudflare automatically routes traffic to your container no matter how often your home IP changes!
How a Zero-Trust Access Tunnel Differs from a Traditional VPN
It's common to confuse a Zero-Trust Access Tunnel with a traditional VPN (Virtual Private Network), but they operate on fundamentally different security models:
-
Traditional VPN (Full Network Access):
A traditional VPN joins a remote client device directly into your home network at the network layer (Layer 3). Once connected, your client gets a local IP address (192.168.0.x) and can communicate with every single device, NAS, and server on your LAN. If a remote laptop is infected, malware can spread laterally across your network. VPNs also require installing client software on every device you use. -
Zero-Trust Access Tunnel (Isolated Application Access):
A Zero-Trust Tunnel operates under the strict principle of "Never Trust, Always Verify" at the application layer (Layer 7). Instead of giving users access to your entire network, it only exposes a single, isolated web application. Remote users never gain access to your internal LAN or IP range. Access is completely clientless (running in any web browser), and every request is verified at Cloudflare's edge with MFA before reaching your server.
What's Cloudflare Access?
Cloudflare Access adds an enterprise Zero-Trust authentication barrier in front of your public hostnames:
- Email One-Time Password (OTP) MFA: Anyone trying to visit your site must enter a single-use PIN code sent to your approved email address.
- Geo-IP Fencing: Restrict access so only connections originating from specific countries (e.g. United Kingdom) are allowed through.
💡 Previous Series Guides:
If you haven't set up Docker yet, check out our previous install guides:
Where can I install this?
In this guide, we'll be using our Linux Docker host. You can run the exact same steps on a Raspberry Pi, an Ubuntu server, or inside WSL2 on Windows 11.
Set up your persistent Docker Config folders
In this guide and throughout our Get Started with Docker series, we'll be using the following folder structure to store all of our persistent configuration files:
/home/$yourusername/Files/AppData/Config
It's best practice to keep a structured folder setup to make organizing, updating, and backing up your Docker data volumes easy.
Create our cloudflared Config folder
First, we're going to create a folder to store our Cloudflare Tunnel configuration files and credentials.
- SSH into your Docker server installation.
- Check you are in your home folder by running
pwd. - Copy and paste the below command and press Enter to create the folder:
mkdir -p Files/AppData/Config/cloudflared
- Change into the newly created folder:
cd Files/AppData/Config/cloudflared
- You should now be in
/home/$yourusername/Files/AppData/Config/cloudflared.
Creating your Cloudflare Tunnel in the Dashboard
Before creating our Docker Compose file, we need to create a tunnel in the Cloudflare Zero Trust Dashboard and grab our unique Tunnel Token.
- Log in to the Cloudflare Zero Trust Dashboard.
- Navigate to Networks > Tunnels on the left menu.
- Click Add a tunnel.
- Select Cloudflared as the connector type and click Next.
- Give your tunnel a name (e.g.,
Homelab-Tunnel) and click Save tunnel. - Under Install and run a connector, select Docker.
- Look at the generated run command. Copy the long base64 string after
--token. This is yourTUNNEL_TOKEN.
Creating our Docker Compose file
Now that we're inside /home/$yourusername/Files/AppData/Config/cloudflared, open your text editor to create your compose file:
nano docker-compose.yml
💡 Tip: If you don't have
nanoinstalled on your system, runsudo apt-get install nano.
Copy and paste the below code block into your terminal window:
version: '3.8'
services:
cloudflared:
container_name: cloudflared
image: cloudflare/cloudflared:latest
restart: unless-stopped
command: tunnel --no-autoupdate run
environment:
- TUNNEL_TOKEN=${TUNNEL_TOKEN}
Next, create a .env file in the same folder (nano .env) to store your tunnel token securely:
TUNNEL_TOKEN=PasteYourLongCloudflareTunnelTokenHere
- Press Ctrl + X, type Y, and press Enter to save the file.
Starting up cloudflared
With your docker-compose.yml and .env files created, spin up the connector:
docker compose up -d
Docker will download the cloudflared image and establish the outbound tunnel.
Head back to your Cloudflare Zero Trust dashboard. You will see your tunnel status turn to Active with a healthy green indicator!
Routing Public Hostnames to Local Containers
Click Next in the Cloudflare Tunnel wizard to configure a Public Hostname:
- Subdomain:
app(e.g.,app.yourdomain.com) - Domain: Select your domain from the dropdown.
- Service Type:
HTTP - URL:
http://192.168.0.23:81(The local IP address and port of the container or service you want to expose).
Click Save hostname.
Adding Zero-Trust Edge MFA (Cloudflare Access)
To prevent unauthenticated users from reaching your public hostname:
- In the Zero Trust Dashboard, go to Access > Applications.
- Click Add an application and select Self-hosted.
- Set Application name to
My Local Appand Application domain toapp.yourdomain.com. - Under Policies, create an access policy:
- Action:
Allow - Include Rule: Selector =
Emails, Value =[email protected](Enforces Email OTP MFA). - Require Rule: Selector =
Country, Value =United Kingdom(Geo-IP fencing).
- Action:
- Click Save application.
Now, when you open app.yourdomain.com in your web browser, Cloudflare will display a secure login screen prompting for a single-use code sent to your email. Once entered, traffic is securely tunneled directly to your home server!
🔒 Automatic Managed SSL/TLS Protection
One of the biggest added bonuses of routing your traffic through Cloudflare Tunnel is automatic HTTPS encryption.
Normally, setting up SSL certificates for a home server requires running Certbot / Let's Encrypt containers, configuring complex DNS API keys, opening port 80 for HTTP-01 validation challenges, or manually renewing certificate files every 90 days.
Cloudflare Tunnel handles all of this automatically:
- 💡 Zero SSL Maintenance: Cloudflare automatically issues, attaches, and renews trusted Universal SSL/TLS certificates for your public hostnames (
https://app.yourdomain.com). - 💡 End-to-End Encryption: Traffic from the client browser to Cloudflare Edge is encrypted over HTTPS (TLS 1.3), and the connection from Cloudflare Edge to your Docker container is encrypted through your outbound
cloudflaredtunnel. - 💡 No Expired Certificate Outages: You never have to worry about an expired SSL certificate breaking your remote access!
Next Steps
Congratulations! You've deployed Cloudflare Tunnel in Docker using our standard Files/AppData/Config folder structure, protecting your services with Zero-Trust edge MFA and Geo-IP filtering without opening any router ports.
Now that your Zero-Trust tunnel foundation is ready, move on to Part 6b where we'll leverage this tunnel to deploy Apache Guacamole for clientless browser-based RDP and SSH remote desktop access!
Don't forget to explore the rest of our website as we build out more content. Stay tuned for more tutorials, tips, and tricks to help you make tech work for you.
If you want to stay up-to-date with regular updates, make sure to subscribe to our free mailing list.