OPNsense DHCP — The DNS Handout Decision
DHCP is the mechanism that makes every other DNS decision actually take effect. You can configure Unbound perfectly, deploy AdGuard with a clean compose file, and have a solid filtering policy — and none of it matters if clients are still pointing at whatever the router handed out six months ago. The DHCP DNS server configuration is the last link in the chain, and it's also where the resilience of the whole stack either gets built in or gets forgotten.
Primary DNS: AdGuard, Not the Router
The instinct when configuring DNS on a router is to hand out the router's own IP as the DNS server. OPNsense even does this by default when the DNS servers field is left blank — clients get the router IP, queries go to Unbound, resolution works. For a setup without a separate filtering layer, that's correct.
When AdGuard is in the stack, the router-as-primary approach bypasses the entire filtering layer. Clients resolve fine, but blocklists never apply, query logging never fires, and the whole reason AdGuard was deployed is silently not happening. The fix is explicit: put AdGuard's IP in DNS Server 1, and mean it.
The tradeoff is that primary DNS now lives on a host that has a different availability profile than the router. The router is always on. The Docker host is on when it's on. Acknowledging that asymmetry honestly — and building around it rather than pretending it doesn't exist — is what makes the secondary DNS field matter.
Secondary DNS: Local, Not Public
The default instinct for secondary DNS is a public resolver — 8.8.8.8, 1.1.1.1, whatever comes to mind. That choice feels safe because public resolvers are reliable. It's actually the wrong call for two reasons.
First, a public secondary means that when AdGuard is unavailable, clients resolve through an external service that knows nothing about your internal network. Internal hostnames stop working. Services sitting behind a local reverse proxy become unreachable by hostname. Depending on how services are configured, some may stop working entirely. The fallback state is worse than it needs to be.
Second, a public secondary bypasses local filtering entirely. When AdGuard is down and clients fall back to 8.8.8.8, every query from that point forward goes to Google — unfiltered, unlogged, with no blocklist enforcement. That might be acceptable in a homelab, but it's worth being deliberate about it rather than defaulting into it.
The better secondary is the router IP — Unbound, already configured with host overrides for every internal service. Clients in fallback mode lose the filtering layer but keep everything else. Internal services stay reachable. The network stays functional. The degraded state is genuinely just degraded, not quietly broken in ways you won't notice until someone goes looking.
In an enterprise context, the secondary might be a second AdGuard instance, or a separate DNS server on dedicated infrastructure. In a homelab where the router is the most reliable device on the network, the router IP as secondary is the right answer. Same principle — pick the secondary based on its availability profile and what it can do for clients in fallback mode, not just based on whether it resolves public hostnames.
What DHCP Doesn't Do
DHCP hands out a DNS server list. It doesn't control how clients use it, how long they cache the old list before requesting a new lease, or what they do when the primary is slow to respond versus fully unreachable. DNS failover behaviour varies across operating systems — Windows, macOS, and Linux all handle it differently, and none of them are guaranteed to switch back to the primary immediately when it becomes available again after a gap.
This means the secondary DNS is not a hot standby with clean failover. It's more like a safety net — catches clients that genuinely can't reach the primary, keeps them functional, and gets out of the way when the primary comes back. Building the secondary with that expectation in mind produces a better design than building it as if it were a fully equivalent replica of the primary.
For this stack, that means the secondary doesn't need AdGuard. It needs Unbound, host overrides, and reliable upstream forwarding. Clients in fallback mode get exactly enough to stay functional — and the filtering policy resumes as soon as AdGuard comes back and clients cycle back to it.
Why DHCP Lives on the Router
AdGuard has a built-in DHCP server. So does almost every DNS server worth running. The integration between DHCP and DNS that comes with co-locating them — automatic hostname registration for dynamic leases, a single management interface for both — is genuinely useful for some setups.
For this one, DHCP lives on OPNsense because the router is always on first. When a host boots and needs an IP address before anything else is up, the DHCP server needs to be available. If DHCP is running on the Docker host alongside AdGuard, a host restart — planned or otherwise — takes both down simultaneously. Clients can't get new leases. Services that depend on DHCP renewals may stall. The network's ability to hand out addresses becomes contingent on the availability of a single compute host.
Moving DHCP to the router decouples it from compute availability entirely. The router handles network fundamentals — routing, firewalling, DHCP, Unbound — and the Docker host handles services. When the Docker host restarts, the network keeps functioning normally. Clients get leases, they get the right DNS servers, and they have a working fallback while AdGuard comes back up. That separation is worth more than the convenience of co-located DHCP and DNS.
Configuration behaviour described here reflects OPNsense as of early 2026. DHCP service implementation details — particularly around ISC DHCPv4 vs KEA — have been evolving across recent OPNsense releases. Verify the available service options against current documentation for your version.