CloudFlare Tunnels can be used as a reverse proxy with TLS termination in place of something like nginx with acme. This also avoids exposing your home IP address via DNS or needing any NAT / port forwarding on your home router.

Create a Tunnel at CloudFlare

  1. Using the CloudFlare web dashboard navigate to Zero Trust > Access > Tunnels.
  2. Click “Create a tunnel”
  3. Name the tunnel. I recommend using the same name as the service being hosted.
  4. Copy the generated tunnel token

This token should be kept secret. If lost, it can be rotated later so there is little reason to store it anywhere other than the .env file of our docker-compose setup.

Establish a Tunnel Connection

In your docker-compose setup on your home server add the cloudflared container and set the TUNNEL_TOKEN from the previous step.

In docker-compose.yml:

services:
  tunnel:
    image: cloudflare/cloudflared
    restart: unless-stopped
    command: tunnel run
    environment:
      - TUNNEL_TOKEN=${TUNNEL_TOKEN}

In .env:

TUNNEL_TOKEN="<CloudFlare Tunnel Token>"

Then bring up the cluster with docker-compose up. You should see the connection in the CloudFlare dashboard.

Add Reverse Proxy Rules

In the CloudFlare dashboard you should see the ability to route traffic from a public DNS entry to the docker-compose cluster. To get back to the routing configuration in CloudFlare navigate to Zero Trust > Access > Tunnels, click on the tunnel name, click “Configure” and navigate to the Public Hostname tab.

Similar to nginx you can now route subdomain (and optional path prefix) to other containers in the same docker compose cluster. Note you do not need to expose ports in the docker-compose. For the host name, simply use the container name defined in the docker-compose.yml. You can even route the domain apex to a specific container.