- Go 92.7%
- Shell 3.9%
- Nix 1.8%
- Just 0.9%
- Dockerfile 0.7%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
The /homeless-shelter error is nix building the go-modules fixed-output derivation without a sandbox; pre-removing the directory doesn't stick because the build itself recreates it. cachix/install-nix-action falls back to sandbox=false in the container runner. Switch to the DeterminateSystems installer, which sets the sandbox up reliably in containerized CI. |
||
| .forgejo | ||
| cmd/dhcpd-ddns | ||
| deploy | ||
| examples | ||
| internal | ||
| nix | ||
| packaging | ||
| tools | ||
| .editorconfig | ||
| .gitattributes | ||
| .gitignore | ||
| .golangci.yml | ||
| .goreleaser.yaml | ||
| Dockerfile | ||
| flake.lock | ||
| flake.nix | ||
| go.mod | ||
| go.sum | ||
| justfile | ||
| LICENSE | ||
| README.md | ||
dhcpd-ddns
A drop-in reimplementation of ISC Kea's DHCP-DDNS server (D2)
in Go. It accepts NameChangeRequests (NCRs) from Kea DHCP4/DHCP6 over the same
JSON-over-UDP wire format as kea-dhcp-ddns, then applies the DNS updates to a
configured backend.
Backends
- RFC 2136 dynamic DNS updates (wire-compatible with Kea D2's
dns-servers), with TSIG (incl.digest-bitsMAC truncation per RFC 4635) and per-server retry/failover. - PowerDNS Authoritative HTTP API.
- Technitium DNS Server HTTP API.
Features
- Full RFC 4703 conflict-resolution modes (
check-with-dhcid,no-check-with-dhcid,check-exists-with-dhcid,no-check-without-dhcid), with an application-level DHCID ownership store for the HTTP-API backends. - Durable NCR queue: in-memory, Redis, or SQLite.
- Optional record reaper that removes stale DNS records when leases expire.
- Live configuration reload on
SIGHUP(zones, TSIG keys, backends, and listen address) without dropping the queue.
Quick start
# Build (injects version metadata):
just build
# Run with a config file:
./dhcpd-ddns -config /etc/dhcpd-ddns.conf
# Print version:
./dhcpd-ddns -version
With no -config, the daemon runs on built-in defaults (127.0.0.1:53001,
in-memory queue) identical to kea-dhcp-ddns.
See examples/ for rfc2136, powerdns, and technitium
configurations. The config file is the standard kea-dhcp-ddns DhcpDdns block,
plus an optional dhcpd-ddns extensions block for the non-RFC-2136 backends and
durable queues.
Installation
Releases ship several formats (see the repository's Releases page):
-
Debian/Ubuntu —
.deb(amd64/arm64). Installs the binary, a systemd unit, and a default config at/etc/dhcpd-ddns/dhcpd-ddns.conf. Edit it, thensystemctl enable --now dhcpd-ddns. -
RHEL/Rocky/EL9 —
.rpm(amd64/arm64), same layout. -
OpenBSD — a binary tarball (amd64/arm64); install the binary and run it under your own rc/supervision (there is no native OpenBSD package).
-
Nix / NixOS — a flake. Build with
nix build github:erestodo/dhcpd-ddns, or use the NixOS module:{ inputs.dhcpd-ddns.url = "git+https://scm.nullnetwork.cc/erestodo/dhcpd-ddns"; # in your configuration: imports = [ dhcpd-ddns.nixosModules.default ]; services.dhcpd-ddns = { enable = true; configFile = ./dhcpd-ddns.conf; }; }
Container
docker run --rm \
-p 53001:53001/udp \
-v /etc/dhcpd-ddns.conf:/etc/dhcpd-ddns.conf:ro \
scm.nullnetwork.cc/erestodo/dhcpd-ddns:latest
The image is distroless and runs as a nonroot user. Set ip-address to
0.0.0.0 in the config so the listener is reachable from outside the container.
Persist the SQLite queue/store with a volume on /var/lib/dhcpd-ddns.
Development
just # list tasks
just test # lint + race tests
just fmt # gofmt
CI (lint, race tests, snapshot build) and releases (multi-arch OCI images +
archives) run on Forgejo Actions; see .forgejo/workflows/.
License
MIT — see LICENSE.