DockRoute

Quickstart

Run DockRoute next to your services and watch it reconcile — dry run first, real records after.

Prefer a form to a blank file?

The compose generator builds a compose.yaml and .env for your setup — provider, optional Cloudflare Tunnel, optional example service — entirely in your browser.

Requirements

DockRoute runs on linux/amd64 and linux/arm64. On x86-64, the Bun runtime needs a CPU that reports SSSE3, SSE4.1, SSE4.2 and POPCNT (the x86-64-v2 microarchitecture level) — true for Intel CPUs since Nehalem (2008) and AMD since Bulldozer (2011), but not for older Atoms (pre-2013), Core 2 or Phenom II/Athlon II, nor for a VM pinned to a generic model such as QEMU's kvm64/qemu64. arm64 is not affected.

dockroute: unsupported CPU, missing ssse3 sse4_1 sse4_2 popcnt

Without SSSE3/SSE4.1/SSE4.2/POPCNT, Bun usually hangs at 100% CPU with no log output (or crashes with SIGILL) instead of exiting cleanly — so the entrypoint checks /proc/cpuinfo before starting the app and exits right away with this message, listing only the flags that are actually missing. In a VM (Proxmox, libvirt, generic QEMU), set the CPU type to host (host-passthrough in libvirt) or x86-64-v2 or newer, then restart the VM.

1. Dry run — no credentials needed

DockRoute defaults to the log provider, which runs the whole pipeline and prints the desired state it computes instead of touching a zone. It is the safest way to check your labels.

compose.yaml
services:
  whoami:
    image: traefik/whoami
    labels:
      dockroute.enabled: "true"
      dockroute.hostname: "whoami.example.com"

  dockroute:
    image: ghcr.io/dockroute/dockroute:latest
    environment:
      DOCKROUTE_DEFAULT_TARGET: 192.168.1.10
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
docker compose up

You should see the desired state logged: an A record for whoami.example.com pointing at 192.168.1.10.

Docker socket permissions

Handled automatically: the entrypoint detects the socket's group, grants it to the app user and drops privileges before starting — the process itself runs as non-root. If you set an explicit user: override, add the socket's group yourself with group_add: ["<gid>"] (stat -c '%g' /var/run/docker.sock).

2. Go live with Cloudflare

Switch the provider and add a token with Zone → Zone → Read and Zone → DNS → Edit permissions:

compose.yaml
  dockroute:
    image: ghcr.io/dockroute/dockroute:latest
    environment:
      DOCKROUTE_PROVIDER: cloudflare
      DOCKROUTE_OWNER_ID: home-lab
      DOCKROUTE_DEFAULT_TARGET: 192.168.1.10
      CLOUDFLARE_API_TOKEN: ${CLOUDFLARE_API_TOKEN}
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro

Restart the stack. DockRoute lists your running containers, computes the desired records and reconciles them. From now on, every container start and stop triggers a reconcile, and a full resync runs every 60 seconds.

3. Publish through a Cloudflare Tunnel (optional)

If you already run cloudflared with a tunnel, one extra label publishes a service through it — no port forwarding at all:

  whoami:
    image: traefik/whoami
    labels:
      dockroute.enabled: "true"
      dockroute.hostname: "whoami.example.com"
      dockroute.tunnel.service: "http://whoami:80"

The tunnel needs two more environment variables on the DockRoute container (CLOUDFLARE_ACCOUNT_ID and CLOUDFLARE_TUNNEL_ID) and the token needs Account → Cloudflare Tunnel → Edit. See the Cloudflare Tunnel guide for the full setup.

Verify

  • docker compose logs dockroute shows every create, update, delete and skipped conflict.
  • Your zone now contains the record and a companion TXT like _dockroute-a.whoami.example.com — that TXT is DockRoute's proof of ownership.
  • Stop the whoami container: under the default sync policy both records are removed once it has been gone for DOCKROUTE_DELETE_GRACE_SECONDS (60 by default), so a restart never takes the hostname down.

On this page