DNS for Homelab

DNS is the homelab piece that quietly determines what every other service looks like. Get it right and your services have memorable names that work the same from any device on the network. Get it wrong and you're typing IP addresses, fighting NAT hairpins, and dealing with mismatched internal-vs-external resolution. The setup is straightforward if you pick a clear scheme up front and apply it consistently.

What you want from homelab DNS

  • Internal hostnames for your services (plex.lab.example.com, jellyfin.lab.example.com).
  • Same hostname resolves correctly whether the client is on the LAN or outside it.
  • Ad and tracker blocking applied to every device on the network.
  • Predictable resolution that doesn't depend on which device's stub resolver decided what.

The pick-a-domain decision

Several conventions for internal hostnames:

ConventionExampleNotes
Subdomain of owned domainplex.lab.example.comBest — works for valid TLS certs, no conflicts
RFC 8375 home.arpaplex.home.arpaIETF-reserved; can't get public TLS for it
Made-up .lan or .homeplex.lanWorks locally but invalid for TLS; collisions possible if .lan ever becomes a real TLD
.localplex.localAVOID — reserved for mDNS; causes conflicts

The recommendation: own a real domain (cheap), and use a subdomain like lab.example.com or home.example.com for internal services. You can get valid TLS certificates via DNS-01 challenges without exposing anything internally.

The DNS server choice

  • Pi-hole — DNS forwarder with web UI, blocklists, and easy custom record management. Most popular homelab choice.
  • AdGuard Home — alternative to Pi-hole; similar features, different UI, DoH/DoT support built in.
  • Unbound — recursive resolver; doesn't forward to a public upstream. Often paired with Pi-hole as the upstream.
  • BIND9 — full DNS server. Heavy for a homelab but maximally capable.
  • dnsmasq — lightweight DNS+DHCP. Often used by routers (OpenWrt) directly.

Split-horizon: the key pattern

Without split-horizon, services accessed by hostname from inside the LAN go through NAT hairpin — your router has to route packets out and back in, which some routers handle poorly. Split-horizon avoids this:

  • External public DNSplex.example.com A record points at your public IP (where your reverse proxy lives, port-forwarded from the router).
  • Internal homelab DNSplex.example.com A record points at the reverse proxy's internal IP (e.g., 10.0.0.50).

Inside the LAN, devices query the homelab DNS first and get the internal IP. Outside the LAN, devices query public DNS and get the public IP. Same hostname; correct routing both ways; no hairpin.

Pi-hole local records

In Pi-hole, the "Local DNS Records" section lets you add hostname-to-IP mappings:

plex.lab.example.com    →  10.0.0.50
jellyfin.lab.example.com → 10.0.0.50
home.lab.example.com    →  10.0.0.50
*.lab.example.com       →  10.0.0.50  (wildcard via dnsmasq.d conf)

For a single reverse proxy serving everything, point a wildcard at the proxy's IP. The proxy handles per-hostname routing.

Configuring clients to use your DNS

The pattern: your router's DHCP server hands out your Pi-hole as the DNS server. All clients get it automatically.

  • In the router's DHCP settings, set DNS server 1 to Pi-hole's IP.
  • Remove or deprioritize secondary DNS servers (8.8.8.8, 1.1.1.1) so clients don't fail over and bypass Pi-hole.
  • For devices that hardcode DNS (smart TVs, some IoT), block external DNS at the firewall so they're forced to use your DNS.

The Pi-hole + Unbound pattern

Many advanced homelabs combine Pi-hole (filtering + local records) with Unbound (recursive resolver) running on the same machine:

  1. Client queries Pi-hole.
  2. Pi-hole checks its blocklist; blocks tracker/ad domains.
  3. Pi-hole checks local records; returns internal IPs for homelab services.
  4. For everything else, Pi-hole forwards to localhost:5335 (Unbound on a non-standard port).
  5. Unbound queries the root, then the TLD, then the authoritative servers directly.

Benefits: no public resolver sees the queries (other than the authoritative servers themselves), and you control the entire stack.

DNSSEC validation

Unbound validates DNSSEC by default. Pi-hole can be configured to validate (or to forward to a DNSSEC-validating upstream like Cloudflare 1.1.1.1). DNSSEC validation rejects forged DNS responses; for paranoia about cache poisoning it's worth enabling.

DoH / DoT for upstream

For privacy from the ISP, encrypt the DNS path between your homelab and the upstream resolver:

  • Pi-hole + cloudflared — cloudflared runs as a DoH client that Pi-hole forwards to.
  • AdGuard Home — DoH/DoT support built into the upstream configuration.
  • Unbound forward-zone DoT — Unbound can use DoT to talk to upstream resolvers.

The ISP sees that your homelab made an encrypted connection to a known resolver, but not which domains you queried.

Conditional forwarding for VLANs

When you have multiple VLANs with multiple subnets, Pi-hole's "Conditional Forwarding" tells it where to look up reverse DNS for each subnet. Lets the dashboard show device hostnames per client IP instead of just IP addresses.

For more complex setups (multiple DHCP servers, multiple internal zones), you may need a full DNS server like BIND with views, or chain multiple DNS resolvers.

Common mistakes

  • Using .local for non-mDNS DNS. Conflicts with mDNS resolution on macOS and some Linux distros. Use a different suffix.
  • Forgetting to set the internal A record. External resolution works; internal fails because Pi-hole doesn't know about the service.
  • Hairpin NAT relied upon. Works on some routers, fails on others. Just use split-horizon.
  • Pi-hole is the only DNS and goes down. Everything stops resolving. Run a secondary (a small Pi-hole VM on a different host).
  • Browser DoH bypasses Pi-hole. Modern browsers use their own DoH. Set the browser's DoH to point at Pi-hole, or disable browser DoH at the policy level.

Frequently Asked Questions

Why run my own DNS for homelab?

Three reasons. First, internal-only hostnames — your home services can have nice names that resolve only inside the LAN. Second, split-horizon — public hostnames can resolve to internal IPs when queried from inside, avoiding NAT hairpinning. Third, ad and tracker blocking — DNS-level filtering applies to every device on the network.

What is split-horizon DNS?

A configuration where the same hostname resolves to different IPs depending on where the query comes from. Inside the LAN, plex.example.com resolves to the internal IP of your Plex server. From the internet, the same name resolves to your public IP (which forwards to the same Plex via your reverse proxy). Lets you use one hostname everywhere without NAT hairpin complications.

What is Pi-hole?

A DNS server designed for home networks that blocks ad and tracker domains by returning NXDOMAIN (or a sinkhole IP). It forwards non-blocked queries to an upstream resolver. Beyond ad blocking, Pi-hole serves as a place to publish local hostname-to-IP mappings — making it the typical homelab DNS choice for both filtering and internal name resolution.

What is the difference between Pi-hole and Unbound?

Pi-hole is a DNS forwarder with built-in filtering — it forwards queries to an upstream resolver after applying its blocklist. Unbound is a recursive resolver — it queries authoritative DNS servers directly without an upstream. They're complementary: Pi-hole for filtering and local zones; Unbound as Pi-hole's upstream so queries don't go through any public resolver.

Why use an internal domain like .lan or .local?

To distinguish internal-only services from public ones. Common conventions: a private subdomain of a domain you own (lab.example.com), the made-up .lan suffix (plex.lan), or a reserved test domain (.home.arpa). Avoid .local — it's reserved for mDNS and using it for normal DNS creates subtle conflicts.

Related Guides

More From This Section