~/ziphub — zsh
ZipHub·~/catalog~/articles~/feed~/sellers~/hire
auth login
[article]category · new-cat

Cloudflare Tunnel with Docker Compose: secure access to containers without exposing ports

@dignezzz · author2 min read2026-03-15free

TL;DR: How to set up Cloudflare Tunnel with Docker Compose and provide secure HTTPS access to your containers without port forwarding.

Introduction

Cloudflare Tunnel lets you safely publish your local services to the internet without opening ports and without handling HTTPS manually. In this guide you'll learn how to set up a tunnel together with Docker Compose to automatically proxy access to the required containers, as if it were a regular public site.

Why this is useful

  • No public IP required — and you don't need one.
  • No port forwarding on the router or firewall.
  • Cloudflare provides HTTPS, WAF, DDoS and bot protection.
  • Everything can run in containers — no extra nginx, certbot, or other configuration.

Example: publishing a web app through a tunnel

Suppose we have a container my-app running at http://my-app:3000. We want it to be accessible at https://app.example.com.

Step 1. Prepare Cloudflare

  1. Sign up and add your domain to Cloudflare.

  2. Install cloudflared locally and authenticate:

    bash
    1cloudflared login
    
  3. Create a tunnel:

    bash
    1cloudflared tunnel create my-tunnel
    
  4. Bind DNS:

bash
1    cloudflared tunnel route dns my-tunnel app.example.com
  1. Copy the credentials .json file (usually located in ~/.cloudflared/) into your project directory, for example ./cloudflared.

Step 2. Project structure

yaml
1project/
2├── docker-compose.yml
3├── cloudflared/
4   ├── config.yml
5   └── <your-tunnel-id>.json
6

Step 3. config.yml — tunnel config

yaml
1tunnel: my-tunnel
2credentials-file: /etc/cloudflared/<your-tunnel-id>.json
3
4ingress:
5  - hostname: app.example.com
6    service: http://my-app:3000
7  - service: http_status:404

Step 4. docker-compose.yml

yaml
1version: '3.8'
2
3services:
4  my-app:
5    image: your-image
6    container_name: my-app
7    expose:
8      - 3000
9    networks:
10      - app-network
11
12  cloudflared:
13    image: cloudflare/cloudflared:latest
14    container_name: cloudflared
15    restart: always
16    command: tunnel --config /etc/cloudflared/config.yml run
17    volumes:
18      - ./cloudflared:/etc/cloudflared
19    networks:
20      - app-network
21
22networks:
23  app-network:
24    driver: bridge

Step 5. Run

bash
1docker compose up -d

Now, when you visit https://app.example.com you'll reach your my-app container without exposing ports externally.

Conclusion

Using Cloudflare Tunnel together with Docker Compose allows you to:

  • Simplify service publishing.
  • Remove the need to configure HTTPS manually.
  • Improve security without fiddling with iptables and nginx.

Everything runs in containers — transparent and hassle-free. A great way to proxy admin panels, dashboards, or APIs that you don't want to expose directly.

~2 min read · scroll to continue ↓

## discussion

$ topics --entity=article0
sign in to start or join a discussion
No discussions yet — start one to break the ice.
↑↓ nav open⌘K palettei install? help