The usual homelab DNS setup is one box — Pi-hole, or AdGuard, or a single Unbound — doing everything: recursion for the internet, answers for your internal names, and ad-blocking on the side. It works. But it merges two jobs that are genuinely different, and merging them means a bug or an upgrade in one takes down the other.
I split internal DNS into two layers, each with its own high-availability VIP.
Layer 1 — recursive (the only thing clients see)#
Clients get exactly one DNS address: a floating virtual IP shared by three small VMs, each running dnsdist in front of Unbound.
- Unbound does the actual recursion — walking from the root servers down — with qname-minimisation and caching. It’s the engine.
- dnsdist sits in front as the client-facing front door: it’s where per-client rules, logging, and (later) filtering live, and it’s built to be the thing exposed.
- keepalived floats a VIP across the three so one VM can die without clients noticing.
That VIP is the address DHCP hands out. Clients never know there are three boxes.
Layer 2 — authoritative (owns the internal zone)#
A separate trio serves the internal zone (*.int.example.net) and reverse DNS — and it
does no recursion and no forwarding at all. Ask it about google.com and it says “not
my domain,” full stop. One node is the primary; the other two are secondaries that pull
the zone over TSIG-signed transfers with NOTIFY. Standard, boring, correct — no
proprietary clustering.
The recursive layer forwards only the internal zones to this authoritative VIP, and recurses everything else.
Why bother splitting them?#
Three reasons that earned their keep:
- Different blast radii. A cache-poisoning class of bug lives in the recursive layer; a zone-transfer or record-management bug lives in the authoritative layer. Keeping them apart means one failure mode can’t become the other.
- Upgrade independently. I can restart or rebuild the resolvers without touching the authority for my internal names, and vice versa.
- Recursion is a big attack surface; authority is a small one. The thing that reaches the whole internet (Unbound) and the thing that holds my private records don’t need to be the same process.
It also maps to a clean firewall story, which matters once you’re doing zone-based firewalling: every VLAN may reach the resolver VIP on port 53, and nothing else. One sentence.
The honest caveat#
All six of these VMs run on repurposed old laptops that my own tiering policy classifies as expendable hardware. That’s a deliberate, documented accepted-risk: three instances plus a VIP per layer buys enough redundancy for a family, and there’s a planned exit to proper always-on hardware later. Writing that trade-off down — rather than pretending the laptops are Tier-0 — is the point.
What I’d tell past-me#
- “One DNS box” is fine until it isn’t; the split costs a little now and saves a bad day later.
- The recursive VIP is the only DNS address anything should ever be handed. If you find a client pointed at the authoritative layer, that’s a bug — it can’t resolve the internet.
- Keepalived with all nodes as
BACKUP+nopreemptmeans the VIP moves on failure and stays put when the failed node returns — no flapping.
Next up: time. It sounds trivial until a service host’s NTP replies start leaving by the wrong door.