Building Resilient Local DNS: Pi-hole, Unbound, and Managing Cache Stagnation

In a default home network, DNS resolution is handled entirely by the ISP or a public provider like Google or Cloudflare. While functional, this completely surrenders control over network traffic, privacy, and local domain routing. To take ownership of my network’s name resolution, I deployed a redundant DNS stack utilizing Pi-hole and Unbound.

The Pi-hole and Unbound Architecture

Pi-hole serves as the primary DNS sinkhole, intercepting and blocking requests to known ad-serving and tracking domains before they ever leave the local network. However, instead of forwarding the legitimate, unblocked traffic to a public upstream provider, I configured Pi-hole to forward requests directly to Unbound.

Unbound acts as a validating, recursive, and caching DNS resolver running entirely on my own hardware. Instead of asking a single server (like 8.8.8.8) where a domain is located, Unbound queries the internet’s root servers directly and walks down the chain to find the authoritative answer. This means my ISP can no longer log my DNS requests, providing a significant boost to local network privacy.

Furthermore, this stack allows me to create custom local DNS records, ensuring that internal traffic to my homelab services (like my DokuWiki or Snipe-IT instances) routes efficiently via the LAN IP rather than bouncing out to the public internet and relying on NAT loopback.

The Problem with Stale Caches

While this setup is highly secure and customizable, maintaining a complex local DNS architecture introduces unique troubleshooting challenges—particularly regarding cache stagnation.

If my external public IP address changes (such as during an ISP DHCP lease renewal or a router reboot), the DNS records stored in the various caches across the network can quickly fall out of sync, causing local routing to fail. Because DNS resolution on this network involves multiple layers—the client device, the Pi-hole cache, the Unbound cache, and occasionally the hardware router itself—pinpointing where the stale record lives requires a systematic approach.

Systematic Troubleshooting and Resolution

When a DNS resolution failure occurs, I execute a specific sequence to clear the caches across the stack, starting from the core out to the edge.

First, I access the DNS server via SSH and forcefully clear the Unbound resolver cache by restarting the service: sudo systemctl restart unbound

Next, I flush the Pi-hole cache. While this can be done via the web UI, executing it via the command line ensures the DNS engine immediately dumps its tables and rebuilds: pihole reloaddns

Finally, if the issue persists, the culprit is almost always the edge hardware router holding onto a stale, intercepted IP address. Rebooting the router clears its internal DNS cache. Once the router comes back online, issuing an ipconfig /flushdns (or equivalent command) on the client machine forces it to pull the newly resolved, correct IP address from the freshly cleared Pi-hole stack.

By understanding the exact path a DNS query takes through the homelab architecture, these routing issues can be diagnosed and resolved in seconds, ensuring the local infrastructure remains highly available.

Read more