Split-horizon DNS
The lab uses split-horizon DNS so that internal services
(*.lab.jackhall.dev) resolve to LAN addresses (192.168.1.x) on
configured devices, while still being able to issue a real Let’s Encrypt
wildcard certificate via DNS-01 against Google Cloud DNS.
This page covers the architecture, then walks through pointing a device at
AdGuard Home (192.168.1.200) as its DNS server.
For the underlying decision rationale, see ADR-0003: Public domain + DNS-01 + split-horizon.
Architecture
Section titled “Architecture”Two zones, two responsibilities.
Public side — Google Cloud DNS
Section titled “Public side — Google Cloud DNS”- The apex zone
jackhall.devis untouched at the registrar. - The
labsubzone is NS-delegated from the registrar to a Cloud DNS zone in therockingham-homelabGCP project. The full layout of that project — both zones, the SAs cert-manager and ESO impersonate, the CAA record, the state bucket — is documented in Cloud / rockingham-homelab GCP project. - Cloud DNS holds only records needed for:
- ACME DNS-01 challenge records (
_acme-challenge.lab.jackhall.dev), written by cert-manager via a GCP service account. - Any genuinely public records (none today).
- ACME DNS-01 challenge records (
- Cloud DNS does not serve
dashboard.lab.jackhall.dev,argocd.lab.jackhall.dev, or any other internal hostname. No192.168.1.xaddresses live in the public zone.
Internal side — AdGuard Home in-cluster
Section titled “Internal side — AdGuard Home in-cluster”- AdGuard Home runs as a Kubernetes Deployment in the cluster, fronted by a
Cilium
LoadBalancerService pinned to192.168.1.200(the first address in the192.168.1.200–192.168.1.230LB pool). - AdGuard Home holds the rewrite rules for
*.lab.jackhall.dev → 192.168.1.x(the LB IPs of the relevant Services) and acts as the recursive resolver and ad-blocker for any device pointed at it. - Devices that aren’t pointed at AdGuard Home (guests, IoT) bypass it
entirely and use Optimum’s default resolver. They will fail to resolve
*.lab.jackhall.dev, which is the accepted tradeoff.
Why split-horizon
Section titled “Why split-horizon”The goal is a real, browser-trusted wildcard certificate for
*.lab.jackhall.dev without either:
- Distributing a private CA to every device on the LAN, or
- Exposing internal services on the public internet just so Let’s Encrypt can validate them with HTTP-01.
The split:
- DNS-01 against Cloud DNS lets cert-manager prove ownership of the
lab.jackhall.devzone by writing aTXTrecord. No inbound traffic required, and no public A/AAAA records required. - Internal A records served by AdGuard Home mean the actual hostnames
(
dashboard.lab.jackhall.dev,argocd.lab.jackhall.dev, etc.) only resolve from inside the LAN, on devices configured to use it.
The issued wildcard cert is valid against any *.lab.jackhall.dev name
regardless of which side answered the DNS query, so browsers see a green
padlock for internal-only services.
Reaching AdGuard Home
Section titled “Reaching AdGuard Home”Three theoretical ways to point devices at AdGuard Home; only one is in use.
- Path A — DHCP-pushed DNS. The router advertises
192.168.1.200as the DNS server in DHCP leases. Not available: the Optimum Gateway 6E exposes no custom-DNS-via-DHCP setting and no DHCP-disable. - Path B — Bridge mode + downstream router. Put the Optimum gateway in bridge mode, run a real router behind it, then use Path A from there. Recorded as the future escape hatch; not pursued today.
- Path C — Per-device manual config. Set
192.168.1.200as the DNS server on each device by hand. This is the steady state.
Path C means non-configured devices bypass AdGuard. That’s accepted: the
operator’s own devices are the ones that need *.lab.jackhall.dev
resolution and ad-blocking; everything else can use Optimum’s resolver.
Per-OS manual DNS recipes
Section titled “Per-OS manual DNS recipes”Each recipe sets 192.168.1.200 as the only DNS server for the active
Wi-Fi or Ethernet connection. DNS settings are stored per network profile,
not globally — repeat per network (home Wi-Fi, wired, etc.) as needed.
To verify after changing, run from a terminal on the device:
dig +short dashboard.lab.jackhall.devIt should return a 192.168.1.2xx address. If it returns NXDOMAIN or
nothing, the device is still using its old DNS server.
- Open System Settings → Network.
- Click the active connection (Wi-Fi or the Ethernet entry), then Details….
- Select DNS in the sidebar.
- Under DNS Servers, click + and enter
192.168.1.200. - Select any greyed-out DHCP-supplied entries and click − to remove them. Greyed entries are inherited from DHCP; removing them makes the manual list authoritative.
- Click OK, then Apply.
iOS / iPadOS
Section titled “iOS / iPadOS”- Open Settings → Wi-Fi.
- Tap the ⓘ next to the active network.
- Scroll to DNS and tap Configure DNS.
- Switch from Automatic to Manual.
- Under DNS Servers, tap Add Server and enter
192.168.1.200. - Tap the red − next to any auto-populated servers and tap Delete.
- Tap Save (top right).
Windows 11
Section titled “Windows 11”- Open Settings → Network & internet, then click Wi-Fi (or Ethernet).
- Click the active network’s name to open its properties.
- Find DNS server assignment and click Edit.
- Change the dropdown from Automatic (DHCP) to Manual.
- Toggle IPv4 on.
- Set Preferred DNS to
192.168.1.200. Leave Alternate DNS blank, and leave DNS over HTTPS at its default. - Click Save.
Android
Section titled “Android”Steps vary slightly by skin (Pixel/stock vs. Samsung One UI). The Pixel flow:
- Open Settings → Network & internet → Internet.
- Tap the gear ⚙ next to the active Wi-Fi network.
- Tap the pencil ✏ (top right), then expand Advanced options.
- Change IP settings from DHCP to Static.
- Fill in the fields, copying the values your router currently gave you
for IP/gateway/prefix:
- IP address: the address this device already has (check it before switching to Static).
- Gateway:
192.168.1.1. - Network prefix length:
24. - DNS 1:
192.168.1.200. - DNS 2: leave blank, or repeat
192.168.1.200.
- Tap Save.
Android’s Private DNS setting (Settings → Network & internet → Private DNS) is not the right knob here — it requires DNS-over-TLS, which the in-cluster AdGuard Home isn’t fronting today.
Linux (NetworkManager)
Section titled “Linux (NetworkManager)”Most desktop distros (Ubuntu, Fedora, Arch with GNOME/KDE) use NetworkManager. From a terminal:
-
List active connections to find the right name:
Terminal window nmcli connection show --active -
Override DNS for that connection (replace
<name>with the value from step 1):Terminal window nmcli connection modify "<name>" \ipv4.dns "192.168.1.200" \ipv4.ignore-auto-dns yes -
Bounce the connection so the change takes effect:
Terminal window nmcli connection down "<name>" && nmcli connection up "<name>"
For headless boxes that use systemd-resolved directly (no NetworkManager),
edit /etc/systemd/resolved.conf, set the following under [Resolve]:
DNS=192.168.1.200Domains=~lab.jackhall.devthen run sudo systemctl restart systemd-resolved. The ~lab.jackhall.dev
routing domain ensures queries for that suffix are sent to AdGuard Home
even if other resolvers are configured for general traffic.