In my last article, I looked at what happens when several coding agents work in parallel. This time, I am stepping away from AI and opening up a piece of infrastructure I have been building for myself: my authoritative DNS platform.
DNS is one of those systems that disappears when it works and takes everything with it when it does not. Most sensible people delegate it to a managed provider. I decided to run it myself — not because it is cheaper or easier, but because authoritative DNS is a compact way to learn about delegation, DNSSEC, replication, automation, and failure domains with very real consequences.
The result is matdns.net: one hidden master in Geneva and six public nameservers spread across four continents, all configured from a Git repository with Ansible.
AI-generated image via Google Gemini
Table of contents
Open Table of contents
The architecture
The infrastructure contains seven Debian servers. The hidden master runs at Infomaniak in Geneva. It holds the editable zone files, signs them with DNSSEC, and sends changes to the six public secondaries.
Those secondaries are deliberately distributed across three providers and six locations:
- Vultr in Frankfurt and Silicon Valley;
- DigitalOcean in London and Singapore;
- Linode in Newark and Sydney.
Every provider operates two servers, but never on the same continent. Europe is also covered by two different providers. A provider outage therefore cannot remove an entire region, and the hidden master sits with a fourth provider.
Git + Ansible
│
▼
Hidden master — Geneva
zone source + DNSSEC signer
│
NOTIFY + IXFR/AXFR
│
┌────────┬────────┬──┴─────┬────────┬────────┐
▼ ▼ ▼ ▼ ▼ ▼
Frankfurt London Newark California Singapore Sydney
Vultr DO Linode Vultr DO Linode
Only the six secondaries appear in public delegations. The master is not listed as a nameserver, and its DNS port is reachable only from the secondary IP addresses. If a public node is attacked or misconfigured, the source of truth remains out of the direct serving path.
Why Knot DNS and a hidden master
I chose Knot DNS because it is an authoritative-only server with first-class support for DNSSEC, zone transfers, automatic signing, and modern operational tooling. I do not need recursive resolution on these hosts, so running software focused on authoritative DNS keeps the design easier to reason about.
The hidden-master pattern separates two jobs that are often combined. The master owns zone data and signing keys. The secondaries answer public queries. A change is loaded on the master, which sends DNS NOTIFY messages to the secondaries; they then retrieve the new version through incremental or full zone transfers.
Transfers and notifications are authenticated with a shared TSIG key stored in an encrypted Ansible Vault. An unauthenticated AXFR request to a public server is refused. The master is protected twice: Knot only authorises transfers with TSIG, and the firewall only permits DNS traffic from the known secondaries.
This does add a server, but it gives the signing and editing side of the system a much smaller attack surface.
One nameserver domain for every zone
All hosted domains delegate to ns1.matdns.net through ns6.matdns.net. The matdns.net zone therefore has a special role: it is the nameserver domain and is served by the nameservers it names.
That circular dependency is resolved with glue records. Its registrar publishes the IPv4 and IPv6 address of every nameserver in the parent .net zone, allowing resolvers to find ns1.matdns.net before they can query matdns.net itself.
Other hosted domains do not need glue because their nameservers live outside their own zones. Adding a new domain means setting the same six NS records at its registrar and, once delegation works, publishing its DNSSEC DS record.
Centralising the nameserver names has an operational advantage: if a server address changes, I update the matdns.net zone and glue at one registrar rather than touching every hosted domain. It also creates a critical dependency, so I treat changes to that delegation carefully. I learned why after one registrar silently removed the DS records when I added a nameserver. The fix was simple, but the lesson stuck: after changing glue or the NS set, always query the parent directly and confirm the DS is still there.
Zones as code
The complete configuration lives in the dns-infra Git repository. Zone files are versioned, the inventory describes every server, and Ansible roles configure Knot, the firewall, SSH hardening, and automatic security updates.
Day-to-day changes use one command:
ansible-playbook zones.yml --ask-vault-pass
Before a zone reaches the master, kzonecheck validates it. Ansible also renders knot.conf and runs Knot’s configuration check before replacing the live file. If either validation fails, deployment stops before the bad configuration is applied.
Knot manages SOA serials using Unix time, so I do not manually increment a number in every edited zone. After a successful reload, the master signs the new data, notifies the secondaries, and the playbook waits until every public server reports the same serial as the master.
This is the part I value most about the setup. A DNS edit is not an SSH session followed by a hopeful service restart. It is a versioned change with validation, a repeatable deployment, and an automated check that the fleet converged.
DNSSEC without manual signing
Every zone is signed automatically by Knot using ECDSA P-256 and NSEC3. Zone-signing keys rotate every 30 days, while the key-signing key remains stable because its DS record is published manually at the parent.
There is still one deliberately manual step for a new domain. I first configure the delegation and confirm that the unsigned path works. Only then do I retrieve the DS record from the master, publish it at the registrar, and tell Knot that the key has been submitted.
The order matters. Publishing a DS before the authoritative servers return valid signatures turns an ordinary setup mistake into a DNSSEC validation failure. From a validating resolver’s perspective, a broken chain of trust is worse than no DNSSEC at all: the domain becomes unreachable.
I verify the result with DNSViz and with dig +dnssec, looking for the authenticated-data flag from a validating resolver.
Updating without taking DNS down
Security updates install daily, but servers never reboot automatically. Reboots run through a separate maintenance playbook so availability remains part of the process.
The six public servers are upgraded one at a time. Before touching a node, Ansible confirms that the other public nameservers still answer. After an upgrade or reboot, it checks that Knot is active and that every local zone serial matches the master. Any failed check stops the run. The hidden master is updated last, after the public fleet is healthy.
A read-only health playbook provides the regular overview: Knot service state, serial consistency, pending reboots, and disk usage across all seven servers. It is intentionally boring, which is exactly what I want from DNS operations.
Was self-hosting DNS worth it?
For a business that simply needs reliable DNS, a good managed provider remains the obvious choice. My setup has seven virtual machines, several registrar configurations, DNSSEC state, encrypted secrets, monitoring, and a maintenance procedure. I now own every failure mode that a provider would normally absorb.
But that ownership is also the point. Building this forced me to understand the complete path from a parent-zone delegation to an authoritative answer. I had to think about provider diversity, IPv6 stability, authenticated transfers, signing-key lifecycles, safe rollouts, and what “redundant” actually means when all servers depend on the same operator.
The final architecture is not complicated because DNS needs fashionable infrastructure. It is complicated only where failure demands it: multiple providers, isolated authority, authenticated replication, validation before deployment, and health checks after every change.
Everything else is a zone file and an Ansible playbook.
Thanks for reading. If you run your own authoritative DNS — or have a good reason never to do so — I would love to hear about your setup via email or LinkedIn.
See you in two weeks.