How to Safely Expose Docker Containers to the Internet via Cloudflare Tunnel (No Port Forwarding)

Docker tutorial - IT technology blog
Docker tutorial - IT technology blog

Why I Switched from Port Forwarding to Cloudflare Tunnel

Are you running a Home Lab or VPS but hesitant to open ports 80/443 for fear of hackers “snooping around”? Cloudflare Tunnel is the solution that lets you put your apps online while keeping your front door locked. Previously, every time I wanted to make a service public, I had to deal with the hassle of configuring Port Forwarding on my modem. Not to mention, constantly changing ISP IPs made DDNS unstable at times.

After over 6 months of moving my entire system to Cloudflare Tunnel, here are the 3 most valuable advantages I’ve found:

  • Bypassing CGNAT: You can still publish websites even if you’re using 4G or an apartment network where you don’t have router access.
  • Complete Anonymity: Hackers cannot scan for your real IP. All traffic is filtered through Cloudflare’s firewall before reaching your server.
  • “Turnkey” SSL: No need to install Certbot or worry about renewing Let’s Encrypt certificates every 3 months.

Quick Start: Expose Docker Apps in 5 Minutes

To get started, you need a Cloudflare account and a domain name with its Nameservers pointed there.

Step 1: Create a Tunnel on the Dashboard

Go to the Zero Trust Dashboard -> Networks -> Tunnels. Select Create a Tunnel, give it a memorable name like home-server and click Save.

Step 2: Run the Connector with Docker

Cloudflare will provide you with a token. Run the command below on your server (make sure to replace YOUR_TOKEN_HERE with your actual token):

docker run -d --name cloudflared cloudflare/cloudflared:latest tunnel --no-autoupdate run --token YOUR_TOKEN_HERE

As soon as it runs, this container establishes an outbound connection to Cloudflare. You no longer need to open any ports on your Router or VPS Firewall.

Step 3: Configure the Public Hostname

Back in the web interface, under the Public Hostname tab, click Add a public hostname and fill in the details:

  • Subdomain: app
  • Domain: select your domain
  • Service Type: HTTP
  • URL: localhost:8080 (Your application’s port)

Try accessing https://app.yourdomain.com. The green padlock has appeared; your app is online!

Professional Deployment with Docker Compose

In practice, I always use docker-compose.yml for management. This allows containers to connect via a Docker internal network. You don’t even need to expose ports to the host (no ports: line required).

version: "3.9"
services:
  my-app:
    image: nginx:alpine
    container_name: web_app
    networks:
      - internal_network

  tunnel:
    image: cloudflare/cloudflared:latest
    restart: always
    command: tunnel run --token ${CF_TUNNEL_TOKEN}
    networks:
      - internal_network

networks:
  internal_network:
    driver: bridge

Pro Tip: In the Dashboard configuration, instead of entering localhost:80, enter http://web_app:80. Cloudflare Tunnel will route directly to the web_app container within the same network.

Layer 2 Security with Cloudflare Access

For management tools like Portainer or Adminer, I often add Cloudflare Access. Instead of leaving the login page exposed, you can set a policy that only allows your own email to gain access. Cloudflare will then send an OTP via email to verify your identity. This completely blocks 100% of brute-force attacks on application passwords.

A Few “Hard-Learned” Lessons to Avoid Trouble

While powerful, Cloudflare Tunnel isn’t a silver bullet. Here is what I’ve learned after long-term use:

1. Upload Size Limits

Cloudflare’s Free plan defaults to a file upload limit of around 100MB. If you’re using Nextcloud to back up 4K videos, you’ll run into 413 errors. Consider this carefully if your application needs to transfer large files frequently.

2. Latency

Traffic must route through Cloudflare’s infrastructure, so ping will increase by about 20ms – 50ms. This is fine for typical web apps, but if you’re running a game server that requires low latency, it might be an issue.

3. Token Security

The CF_TUNNEL_TOKEN is extremely sensitive. Anyone with it can “poke around” your system. Save it in a .env file and never push it to public GitHub repositories.

In summary, Cloudflare Tunnel is a major step up from traditional port forwarding. It’s fast, secure, and incredibly easy to deploy. If you’re building a Home Lab, try switching to Tunnel today.

Share: