docker-cloudflare-tunnel-sync

Automatically reconcile Cloudflare Tunnel ingress routes from Docker container labels.

View on GitHub

Docker labels → Cloudflare Tunnel

Release Tests Container

No dashboard drift. Containers are the source of truth.

Expose your Docker services through Cloudflare Tunnel using labels — and nothing else. Add a label, get a route. Remove the container, the route disappears. Cloudflare stays clean and in sync automatically.

Disclaimer: Use a dedicated Cloudflare Tunnel for this controller. If you attach it to an existing tunnel that already has published application routes, enabling managed sync can delete those routes.

The problem

Cloudflare Tunnel configuration can drift when container routes are added or removed but dashboard settings are not kept in sync. That mismatch leads to stale ingress rules, outdated Access apps, or DNS records that no longer reflect what is actually running. Over time, manual cleanup becomes a reliability risk.

The idea

Treat Docker containers as the single source of truth. Opt in explicitly with namespaced labels so only intended services are reconciled, and the controller translates those labels into Cloudflare resources. When containers are removed or no longer labeled, their managed Cloudflare resources should be removed as well.

How it works

flowchart LR
  A[Docker labels] --> B[docker-cloudflare-tunnel-sync]
  B --> C[Cloudflare Tunnel]
  B --> D[Cloudflare DNS]
  B --> E[Cloudflare Access]

One example

Minimal labels on a container:

labels:
  cloudflare.tunnel.enable: "true"
  cloudflare.tunnel.hostname: "app.example.com"
  cloudflare.tunnel.service: "http://app:8080"

Resulting Cloudflare resources:

Design principles

Non-goals

Who this is for

Contributing

Issues and pull requests are welcome. Build locally with docker build -t docker-cloudflare-tunnel-sync:local ., then run gofmt and go test ./... with Go 1.24+ before submitting.