Ramblings of an aging IT geek
← Ramblings of an aging IT geek
networking

i fired my ISP's DNS and ran my own resolver instead

Why I stopped pointing the house at someone else's DNS and stood up my own recursive resolver with Unbound, and what it actually fixed.

Coils of network cabling on a rack

For years the whole house resolved DNS through whatever my ISP handed out over DHCP, with a brief flirtation with 1.1.1.1 when I felt clever. Both work. Both are fine, mostly. But "mostly" is the word that kept nagging at me, because every now and then a lookup would hang for a second or two, or a captive-portal-shaped error would appear, or I'd notice that every device in the house was telling a third party every domain it ever touched. None of that is a crisis. All of it is avoidable. So over a wet weekend I stood up my own recursive resolver, and I've not looked back.

This is not a story about being faster than Cloudflare. It isn't. It's a story about owning the resolution path end to end, knowing exactly where my queries go, and getting a few genuinely nice properties out of it along the way.

forwarder versus resolver

The first thing worth being precise about, because people muddle it constantly: a forwarder and a recursive resolver are not the same thing.

A forwarder takes your query and hands it on to someone else's resolver: 1.1.1.1, 8.8.8.8, your ISP. You've moved the question, not answered it. You're still trusting an upstream to do the actual recursion, and you're still telling that upstream every name you look up.

A recursive resolver answers the question itself. It starts at the root, asks the root servers who handles .pm, asks them who handles i0.pm, and walks the delegation chain down until it has the answer, caching everything it learns on the way. No upstream resolver sees your traffic. The root and the authoritative servers see individual queries, but nobody gets the full picture of what your house is doing.

I wanted the second one.

A rack of servers in a small datacentre

Unbound, because it does one thing well

I went with Unbound. It's a validating, recursive, caching resolver, it's been around long enough to be boring in the best sense, and the config is readable. I run it on a small box that also does a couple of other low-stakes jobs, bound to the LAN interface only.

The core of the config is unremarkable, which is exactly what you want from infrastructure:

server:
    interface: 0.0.0.0
    access-control: 192.168.0.0/16 allow
    access-control: 127.0.0.0/8 allow

    # validate DNSSEC
    auto-trust-anchor-file: "/var/lib/unbound/root.key"

    # be a good neighbour to the cache
    cache-min-ttl: 300
    cache-max-ttl: 86400
    prefetch: yes
    prefetch-key: yes

    # privacy and hygiene
    hide-identity: yes
    hide-version: yes
    qname-minimisation: yes

    # don't leak RFC1918 reverse lookups to the root
    private-address: 192.168.0.0/16
    private-address: 10.0.0.0/8
    private-address: 172.16.0.0/12

A few of those lines earn their keep. prefetch: yes means popular records get refreshed before they expire, so the common stuff is almost always a warm cache hit rather than a cold recursion. qname-minimisation: yes is the quietly important one: instead of sending the full name to every server in the chain, Unbound only sends each server as much of the name as it needs to make the next delegation. The root doesn't need to know you're asking for mail.internal.example.com; it only needs to be asked about com. It's a small thing that closes a real information leak.

private-address stops Unbound from ever forwarding reverse lookups for my internal ranges out to the public root servers, which is both polite and a tidy way to avoid embarrassing leaks of internal hostnames.

DNSSEC, finally on by default

Running my own resolver meant DNSSEC validation became trivial rather than a thing I kept meaning to enable. Unbound ships the root trust anchor and keeps it current, and validation is on. The practical effect is that a tampered answer gets dropped rather than returned. I'll be honest, the day-to-day visible benefit of this is approximately zero, right up until the day it isn't, and that's rather the point of it.

The only DNSSEC gotcha I hit was the usual one: a couple of badly maintained domains that publish broken signatures and then resolve fine everywhere else because everyone else is forwarding to a resolver that's quietly lenient. When you validate properly, broken is broken. I keep a very short list of permissive overrides for the handful that aren't worth the argument, and I treat needing to add to that list as a sign the other end has a problem, not me.

what it actually fixed

The honest accounting, because I promised no fairy tales about speed:

Latency is a wash on cold lookups and a clear win on warm ones, which is most of them. A populated cache serving a busy household means the overwhelming majority of queries never leave the box. The p50 is excellent. The tail, the genuinely-cold first lookup of an obscure domain, is occasionally a hair slower than a giant shared resolver that had it cached already. I can live with that trade entirely.

The privacy story is the real prize. No third party gets a running log of every domain anyone in the house resolves. That was the itch.

And the operational story is nicer than I expected. I can see my own query logs when I'm debugging something, I can add local overrides for my homelab names without running a separate split-horizon hack, and when something DNS-shaped breaks I now know precisely which box to blame. It's me. It's always me. But at least I know where to look.

Another angle on the same small datacentre rack

the one caveat worth stating

If you do this, the resolver becomes a single point of failure for your entire network's ability to do anything. Name resolution down means the internet is, functionally, down. So run two. I have a second Unbound on a different box with the same config, handed out as the secondary via DHCP, and I've actually tested that pulling the primary doesn't take the house offline. An untested failover is just a story you tell yourself, and a resolver you can't lose is the whole reason to bother owning it in the first place.

Would I recommend everyone do this? No. If you don't enjoy this sort of thing, a reputable forwarder is perfectly sensible and you should go and do something nicer with your weekend. But if you like knowing exactly how your own infrastructure answers a question, running the resolver yourself is one of the more satisfying small projects in the homelab. It's mostly cache hits and quiet, which is the highest praise I can give a piece of infrastructure.