01
Label your containers
Add dockroute.enabled and dockroute.hostname to any service in your Compose file. That label is the whole contract — no sidecar config, no templates.
External-DNS for plain Docker hosts
DockRoute watches your Docker containers, reads dockroute.* labels and keeps your DNS provider in sync. Your Compose file is the source of truth. No Kubernetes required.
MIT licensed · single container · Cloudflare DNS + Tunnel today, more providers on the route
services:
whoami:
image: traefik/whoami
labels:
dockroute.enabled: "true"
dockroute.hostname: "whoami.example.com"
dockroute.tunnel.service: "http://whoami:80"create CNAME whoami.example.com → tunnel
create TXT _dockroute-cname.whoami.example.com
● route published — in sync
Docker Compose
your labels
DockRoute
watch + reconcile
DNS provider
records + routes
Your domain
live
How it works
01
Add dockroute.enabled and dockroute.hostname to any service in your Compose file. That label is the whole contract — no sidecar config, no templates.
02
It streams container lifecycle events — start, die, stop, destroy — from the Docker socket, with a periodic full resync as a safety net. Desired state always comes from what is actually running.
03
The provider diffs desired against actual and creates, updates or removes records — plus Cloudflare Tunnel ingress routes when you ask for them.
Safety model
Your DNS zone usually holds more than your containers. DockRoute treats everything it did not create as someone else's — including records made by another DockRoute instance.
Every record DockRoute creates gets a companion TXT record carrying its owner id — the same registry model as Kubernetes ExternalDNS.
A record without proof of ownership is never modified, deleted or adopted. Conflicts are logged and skipped, under every policy.
Orphaned records are removed only under the default sync policy, and only when ownership is proven. upsert-only and create-only never delete.
Tunnel ingress rules DockRoute did not create are preserved verbatim, in their original order, ahead of managed rules.
Configuration
DockRoute runs as a single container next to your services. Point it at the Docker socket, pick a provider, and it starts reconciling. Start with the log provider for a zero-credential dry run.
services:
dockroute:
image: ghcr.io/dockroute/dockroute:latest
environment:
DOCKROUTE_PROVIDER: cloudflare
DOCKROUTE_OWNER_ID: home-lab
CLOUDFLARE_API_TOKEN: ${CLOUDFLARE_API_TOKEN}
volumes:
- /var/run/docker.sock:/var/run/docker.sock:roHomelab
Publish through an existing Cloudflare Tunnel with one label — no port forwarding, no dynamic-DNS scripts, no hand-edited zone files. Take a service down and its records follow.
Small teams
Sync policies, per-instance owner ids and a domain allowlist let several stacks share one zone without stepping on each other — or on the records you manage by hand.
Open source
DockRoute borrows its safety model from Kubernetes ExternalDNS and applies it where most homelabs actually live: plain Docker hosts. Providers are pluggable behind one interface — Cloudflare works end to end today, and the planner, ownership rules and tests are provider-agnostic so new ones slot in cleanly.
Eating our own dog food
This site runs from a Docker Compose stack in a homelab, and the DNS record you used to reach it was published by DockRoute itself — from a dockroute.hostname label on the site's own container.
Start with the dry-run provider — no credentials, no risk — and see the records DockRoute computes before it ever touches a zone.