Files
fancy-dns/deploy/compose
mats 66f36cfac6
build / build-push (push) Successful in 1m11s
more stuff
2026-10-16 14:49:50 +02:00
..
2026-10-16 11:13:13 +02:00
2026-10-16 11:13:13 +02:00
2026-10-16 11:13:13 +02:00
2026-10-16 14:49:50 +02:00
2026-10-16 14:49:50 +02:00

Run fancy-dns outside Kubernetes

This Compose deployment follows deploy/k8s/00-config.yaml and deploy/k8s/10-deployment.yaml. It builds the image from this checkout instead of pulling registry.k6n.net/fancydns, avoiding a bootstrap dependency on the cluster registry DNS.

Following the cluster's configuration. This Compose setup is configured by files and has no link to the cluster's ClientGroup, DNSZone and other objects. To run a backup resolver that reads them (and keeps serving a saved copy when the cluster is down), see ../OUTSIDE-CLUSTER.md.

Prepare and start

From the repository root:

mkdir -p deploy/compose/{data,zones,rpz,tls}
cp deploy/compose/.env.example deploy/compose/.env

Edit deploy/compose/.env (keep it private) and set a random API key as FANCYDNS_API_KEY=<long-random-value>. Install the certificate and private key for dns.k6n.net as deploy/compose/tls/fullchain.pem and deploy/compose/tls/privkey.pem. Add the same zone files used by the cluster to deploy/compose/zones/. Keep private key and .env out of source control.

The container runs as UID/GID 65532 with a read-only root filesystem, so make the persistent directory writable first, for example:

sudo chown -R 65532:65532 deploy/compose/data
docker compose --env-file deploy/compose/.env -f deploy/compose/compose.yaml build
docker compose --env-file deploy/compose/.env -f deploy/compose/compose.yaml run --rm fancy-dns -config /etc/fancy-dns/config.yaml -check
docker compose --env-file deploy/compose/.env -f deploy/compose/compose.yaml up -d

The DNS ports publish on all host interfaces: UDP/TCP 53, TCP 853, and TCP 443. The admin API is published only on 127.0.0.1:8080; the embedded UI is disabled by default for backup-resolver use. To enable it, set api.ui: true in config.yaml and restart. Use an authenticated TLS reverse proxy for remote access. Check that nothing already owns host port 53 before starting. The sample mounts TLS files and enables DoT and DoH, so the files must exist before startup.

How configuration is shared

The repository is the source of truth, but there is currently no automatic config distribution between Kubernetes and the bare-metal Compose host. Kubernetes GitOps reconciles deploy/k8s from main (see gitops/README.md); the bare-metal host must get the updated checkout and have Compose restarted. Kubernetes gets its config from the ConfigMap in deploy/k8s/00-config.yaml; Compose reads the checked-in deploy/compose/config.yaml and files under deploy/compose/. Treat these as two deployment configs: commit reviewed changes to both when a shared resolver setting changes. The Compose config now includes the same local. forward zone to 10.10.0.1:53 as Kubernetes.

The shared inputs to keep aligned are upstreams/forward zones, resolver policy, cache sizing/TTL, blocklist sources and actions, ACLs, local zone files, RPZ rules, and the DoT/DoH certificate for the same public DNS name. Deployment specific settings intentionally differ: listener container ports/storage paths must match each deployment, and Compose uses API-key auth with the UI disabled while Kubernetes uses OIDC. On bare metal the YAML, zone and RPZ files are bind-mounted; Kubernetes stores config, zones and RPZ in ConfigMaps and TLS in a Secret. Secrets should be provisioned separately on each system, not copied into Git. The Compose API key is in its private .env file.

Do not share the data/ directory or copy its bbolt files while either server is running. Cache snapshots and query logs are instance-local state. The managed zones written by the console also live under this directory; edits made on one instance do not appear on the other automatically. Make operator zone changes in the source of truth and deploy them to both, or designate one instance as the writer. Valkey clustering syncs cluster events/list leadership, not these files or bbolt state.

The private forwarding target must remain reachable from both the Kubernetes pods and the bare-metal host. Verify that the bare-metal resolver has outbound access to its configured public upstreams before making it the cluster's registry resolver.

For registry recovery, configure the Kubernetes nodes' OS resolver and the container runtime's registry DNS path to use this host's static IP directly as a DNS server (with another independent resolver as fallback). Do not rely on a hostname for the backup resolver, and do not make pulling this Compose image depend on registry.k6n.net: this Compose file builds the image locally from the repository checkout. A working route from the cluster nodes to the bare-metal host on UDP/TCP 53 is required; allow it through the host firewall.

To update the local build after code changes, rebuild and recreate the container. The running server can hot-reload its YAML on SIGHUP, but Compose does not automatically send SIGHUP when bind-mounted files change.