dnz CLI, DNS UPDATE, a Caddy or Traefik
sync, an ACME challenge) reaches the others within a second. Clients reach them through plain NS
records or one anycast address, and any of them serves the dashboard and the API.
There is nothing to switch on: every DNZ server that uses the same database.url joins. SQLite stays
one server; move to Postgres or MySQL first.
A cluster shares everything: zones, users, filtering, forwarding, proxies, settings and query logs.
Replication is the other way to run more nameservers: each server keeps its own
database and copies zones over AXFR/IXFR, and the secondaries may be any DNS server.
How it works
- Change feed. Each server keeps zones, forwarding, blocklists and its other answer data in
memory. Whenever one of them changes it, the server also writes a row to the database’s change
feed, and the others load that part again. On Postgres they are woken at once with
LISTEN/NOTIFY; on MySQL they poll four times a second (Postgres also polls every 2 seconds, in case itsLISTENconnection drops). A node that was away for more than a day loads everything. - Leader. Jobs that write shared state run on one node at a time, the holder of a lease in the database. The leader renews it every 5 seconds; when it stops (crash, lost network), another node takes over after 15 to 20 seconds. A node that shuts down cleanly hands the lease over at once. Every new leader raises the lease’s generation, so a node that was cut off and comes back finds it has lost the lease.
- Nodes. Each server has a stable node id (made on first start and kept in the data folder as
node-id, or set withDNZ_NODE_ID) and reports its address, version and the last change it loaded every 5 seconds.
Set it up
You need a Postgres 13+ or MySQL 8.0.13+ database every node can reach, with its own backups (a managed database or a Postgres primary with a replica is a good fit: the cluster can’t run without it), the same DNZ version on every node, and clocks in sync (NTP). Each node keeps up to 16 connections open, 17 on Postgres.1
Create the database
On the database server (Postgres):Let the nodes connect: in For MySQL, create the user for the nodes’ addresses (
pg_hba.conf, for nodes in 10.0.0.0/24:'dnz'@'10.0.0.%'); see
Database.2
Start the first node
On the first machine (here Open the dashboard and create the first admin (First run).
10.0.0.11). To bring an existing SQLite install along, run
dnz db migrate-from-sqlite first.- Docker
- systemd
DNZ_CLUSTER_ADDRESS is what the Cluster page shows as the node’s address, and the host of its
DNS address when DNS listens on 0.0.0.0.3
Add more nodes
On each other machine, the same with its own name and address. On Settings → Cluster has these commands filled in under Add a node.
10.0.0.12:4
Check
Clients: NS records or anycast
- NS records
- Anycast
For authoritative zones, give each node a name and list them all as the zone’s nameservers, at
your registrar (with glue when the names are inside the zone) and in the zone itself:Resolvers try another nameserver when one doesn’t answer, so a node that is down costs a retry,
not an outage. Set
DNZ_NAMESERVER=ns1.example.com so DNZ’s SOA records name it. For a resolver
on a LAN (forwarding, filtering), hand out both addresses over DHCP
(option domain-name-servers 10.0.0.11, 10.0.0.12;).dnz CLI can talk to any node.
Watching it
- Settings → Cluster (superadmin): each node’s address, DNS address, version, last heartbeat, whether it leads, and the change it has loaded against the feed’s last one. A node is down after 30 seconds without a heartbeat and behind when it hasn’t loaded a change that is 30 seconds old. Nodes gone for good can be removed from the list.
dnz clustershows the same in the terminal.- Alerts: the leader sends one when a node goes down or falls behind, and again when it is back,
to the notification providers subscribed to
cluster_node. - The topology map shows the other nodes next to the DNZ box, colored by state.
GET /api/clusterreturns it as JSON;GET /api/healthon each node is the liveness check for load balancers and Docker.
Upgrading
Upgrade one node at a time. The first one on the new version upgrades the database’s tables when it starts; the others keep running meanwhile. A change from a newer node that an older one doesn’t know makes the older one load everything again, so mixed versions stay correct, but finish the upgrade soon after.Good to know
- Query logs and statistics are in the shared database: the Overview and the logs show the traffic of all nodes together.
- GeoIP: each node keeps its own GeoIP database in its data folder; automatic updates download it on every node.
- dnz-proxy: each dnz-proxy node streams its configuration from the DNZ node it connects to. ACME HTTP-01 challenges are handed out by the leader, which runs the issuance: point dnz-proxy nodes at the leader’s address, or use DNS-01 through DNZ’s own zones, which works from any node.
- NOTIFY from a primary may arrive at any node; the leader transfers the zone within seconds.
- Removing a node: stop it, then remove it under Settings → Cluster (or
dnz cluster forget). Nodes not seen for 7 days are removed by themselves. - Containers without a data volume get a new node id on every start unless
DNZ_NODE_IDis set.