Synchronize Docker/Moby container A and PTR records through RFC 2136.
  • Go 98.9%
  • Dockerfile 1.1%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Kyle Mendell 42665cbfa5
All checks were successful
Build image / Build and publish (push) Successful in 14s
ci: publish latest tag only
2026-09-02 17:26:58 -05:00
.forgejo/workflows ci: publish latest tag only 2026-09-02 17:26:58 -05:00
.dockerignore feat: add moby-dns 2026-09-02 17:16:14 -05:00
.env.example feat: add moby-dns 2026-09-02 17:16:14 -05:00
.gitignore feat: add moby-dns 2026-09-02 17:16:14 -05:00
compose.yaml feat: add moby-dns 2026-09-02 17:16:14 -05:00
Dockerfile feat: add moby-dns 2026-09-02 17:16:14 -05:00
go.mod feat: add moby-dns 2026-09-02 17:16:14 -05:00
go.sum feat: add moby-dns 2026-09-02 17:16:14 -05:00
main.go feat: add moby-dns 2026-09-02 17:16:14 -05:00
main_test.go feat: add moby-dns 2026-09-02 17:16:14 -05:00
README.md feat: add moby-dns 2026-09-02 17:16:14 -05:00

moby-dns

moby-dns keeps authoritative DNS synchronized with containers running on a Docker/Moby network. It discovers containers through the Docker Engine API and sends TSIG-signed RFC 2136 updates directly to an existing DNS server.

It manages:

  • one IPv4 A record per running container;
  • the matching reverse PTR record;
  • IP-address changes; and
  • safe cleanup when a managed container stops, is removed, or leaves the monitored network.

It does not run a DNS server and does not create CNAME records.

Container image

Forgejo Actions builds AMD64 and ARM64 images from main:

forgejo.ofkm.us/ofkm/moby-dns:latest

Configuration

Copy .env.example to .env and set these values:

Variable Required Description
DNS_SERVER yes RFC 2136 server address
DNS_PORT no DNS update and query port; defaults to 53
DNS_ZONE yes Forward zone, as a fully qualified name
DNS_REVERSE_ZONE yes IPv4 reverse zone, as a fully qualified name
TSIG_KEY_NAME yes TSIG key name
TSIG_SECRET yes Base64-encoded TSIG secret
DOCKER_NETWORK no Docker network to inspect; defaults to vlan25
RECORD_TTL no Managed record TTL; defaults to 60
SYNC_INTERVAL no Reconciliation interval; defaults to 30s

Only running containers attached to DOCKER_NETWORK are considered. Container names are lowercased, underscores and other invalid characters become hyphens, and the forward zone is appended.

For example, immich_server becomes immich-server.containers.example.com..

Labels

Override a container's record name:

labels:
  - "moby-dns.hostname=custom-name"

Exclude a container:

labels:
  - "moby-dns.ignore=true"

The label keys can be changed with HOSTNAME_LABEL and IGNORE_LABEL.

Run with Compose

The included OFKM deployment uses an existing Docker network and an external state volume. Compose does not create either resource.

docker volume create moby-dns-state
cp .env.example .env
chmod 600 .env
# Edit .env, and adjust vlan25/IP settings in compose.yaml when needed.
docker compose up -d

The state volume records which values moby-dns owns. On cleanup, it removes only the previously owned A address and PTR target rather than deleting an unrelated record set.

BIND example

Both zones must allow updates from the configured key:

key "moby-dns." {
    algorithm hmac-sha256;
    secret "base64-secret-here";
};

zone "containers.example.com" {
    type primary;
    file "pri/containers.example.com.zone";
    allow-update { key "moby-dns."; };
};

zone "2.0.192.in-addr.arpa" {
    type primary;
    file "pri/2.0.192.in-addr.arpa.zone";
    allow-update { key "moby-dns."; };
};

Security

The updater only issues read requests to the Docker API, but access to the Docker socket is inherently privileged even when the socket is mounted read-only. Run the image only on a trusted host and protect the TSIG secret.

The runtime image is scratch, read-only, has all Linux capabilities dropped, and persists only /data/state.json.

Development

go test ./...
go vet ./...
docker build -t moby-dns:local .