DNS Phase 4 COMPLETE: single zone — managed zone removed

After upgrading the Mac client 0.68.3 -> 0.71.3 (matching mgmt) and clearing
its NetBird resolver cache (netbird service restart), the managed-zone
deletion works: with 0 managed-zone records, the Mac resolves all
hubris.network names by forwarding to Technitium (192.168.8.2). iPhone
confirmed on cellular (no LAN path -> proves mesh-forward).

The first deletion "failure" was a misdiagnosis: the old 0.68.3 resolver
cache held stale answers and wouldn't clear on down/up (needs daemon
restart); the Mac's dual LAN+mesh paths muddied it. A direct
dig @100.122.255.254 of an unsynced name had shown forwarding working.

Done:
- Deleted all 23 NetBird managed-zone A-records.
- Removed the */10 dns-sync cron. Kept /opt/dns-sync/sync.py + token +
  pre-deletion backup as an emergency-restore tool only.

End state: Technitium is the single DNS source. Mesh peers forward to it
(Core route -> 192.168.8.0/24); LAN/household query it directly. No replica,
no sync. Requires mesh clients on 0.71.x+.

Docs: dns.md + 107-dns.md updated to single-source; subdomain recipe no
longer references the sync.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-21 15:49:36 +02:00
parent 0ff592d237
commit f5e23bea0a
2 changed files with 23 additions and 8 deletions

View File

@@ -24,14 +24,14 @@ Authoritative split-horizon DNS for `hubris.network` on the LAN/mesh, plus recur
- API: `http://192.168.8.2:5380/api/...` (token via `/api/user/login`). Zone was built via the API.
## Who points here
- **NetBird mesh peers:** resolve `hubris.network` via the **NetBird managed DNS zone** (kept in sync from this Technitium — see dns-sync below). This is **load-bearing**, not redundant: a Phase 4 test (2026-06-21) that deleted the managed zone broke resolution for mesh peers. The `home-lab-dns` nameserver group (`→ 192.168.8.2`, applied to all peers) shows `Available` but does **not** actually serve queries on the current client (Mac 0.68.3) — forwarding to the routed-LAN IP silently returns nothing. The 2026-06-21 route fix (added `Core``192.168.8.0/24`) restored service *connectivity* for roaming peers but did not change DNS-forwarding behavior.
- **NetBird mesh peers:** resolve `hubris.network` by **forwarding to Technitium** via the `home-lab-dns` nameserver group (`→ 192.168.8.2`, domain `hubris.network`, applied to all peers). The **NetBird managed DNS zone was removed 2026-06-21 (Phase 4)** — Technitium is now the single DNS source for the mesh too. This works because: (a) roaming peers (`Core`) have the `192.168.8.0/24` route to reach `192.168.8.2` (added 2026-06-21), and (b) clients run NetBird **0.71.x** — on the old 0.68.3 client, forwarding reported `Available` but didn't serve queries, and the resolver cache (`100.122.255.254`) wouldn't clear on `down/up`; a `netbird service restart` (or app toggle) clears it. See [dns.md changelog 2026-06-21](../infrastructure/dns.md).
- **Homelab DHCP clients:** Technitium's own DHCP scope hands out `192.168.8.2` as the DNS server for `192.168.8.x` leases (see DHCP section below).
- **Plain LAN clients (`192.168.178.x`):** Fritz!Box DHCP still hands out Fritz!Box itself (`192.168.178.1`) as DNS, **but** the Fritz!Box now *forwards* upstream to Technitium — DNSv4 server set to `192.168.8.2` (Internet → Filter → DNS Server, 2026-06-17). So household clients get split-horizon `*.hubris.network` answers via Fritz!Box→Technitium, with **no NetBird dependency**. (This is the change that decoupled the on-prem tier from the mesh — see [dns.md](../infrastructure/dns.md) 2026-06-17.)
## dns-sync (Technitium = authoring source)
`/opt/dns-sync/sync.py` (cron `*/10`, logs `/var/log/dns-sync.log`) reconciles this zone's named A-records → the NetBird managed DNS zone via the NetBird API (`/api/dns/zones/{id}/records`). Token at `/opt/dns-sync/netbird-token` (mode 600; source of truth in sops `secrets/netbird-pat.yaml`). **Edit DNS only here**; the sync propagates to the mesh. It deletes NetBird records absent from Technitium. Tracked: [scripts/dns-sync.py](../scripts/dns-sync.py).
## dns-sync (RETIRED 2026-06-21 — Phase 4 complete)
**The managed-zone sync is no longer scheduled.** `/opt/dns-sync/sync.py` reconciled this zone's named A-records → the NetBird managed DNS zone; the `*/10` cron (`/etc/cron.d/dns-sync`) was **removed 2026-06-21** when the managed zone was retired. Technitium is now the **single** DNS source — mesh peers forward to it (see "Who points here" above), LAN/household clients query it directly.
> **Why this exists — RETAINED (Phase 4 reverted 2026-06-21).** The managed zone is the mechanism that actually answers `hubris.network` for mesh peers. We tried to retire it (forward to Technitium instead) on the theory that a missing route was the only blocker — adding `Core` to the `192.168.8.0/24` distribution did fix roaming-peer *service connectivity*. But deleting the managed zone then broke DNS resolution for mesh peers: forwarding to `192.168.8.2` reports `Available` yet does not serve queries on the current client (Mac 0.68.3). So the original "NetBird won't forward to Technitium for mesh peers" finding stands. The managed zone + this sync are **kept**. To remove them, forwarding must first be made to actually work — candidates: upgrade clients to 0.71.x, or point the nameserver group at a **mesh-native** DNS IP (join CT 107 to the mesh) rather than the routed-LAN `192.168.8.2`. See [dns.md changelog 2026-06-21](../infrastructure/dns.md).
The script + token + a pre-deletion record backup remain at `/opt/dns-sync/` **as an emergency-restore tool only**: running `python3 /opt/dns-sync/sync.py` once re-creates the managed zone from Technitium (used during the Phase 4 rollback). Do not re-add the cron unless reverting Phase 4. Tracked: [scripts/dns-sync.py](../scripts/dns-sync.py).
## DHCP

View File

@@ -7,7 +7,7 @@ There is **no wildcard on the LAN side**. Every subdomain needs an explicit entr
## Components
- **Authoritative public DNS:** IONOS. `*.hubris.network → 82.165.190.79` (was `74.118.126.4` until 2026-04-22).
- **LAN authoritative for `hubris.network` records:** [Technitium DNS](https://technitium.com) on [dns (107)](../containers/107-dns.md) at `192.168.8.2:53`. Syncs A records to the NetBird managed DNS zone via cron (see [dns-sync.py](../scripts/dns-sync.py)). Formerly dnsmasq on [authentik (124)](../containers/124-authentik.md) (decommissioned 2026-06-04).
- **LAN authoritative for `hubris.network` records:** [Technitium DNS](https://technitium.com) on [dns (107)](../containers/107-dns.md) at `192.168.8.2:53` — the **single DNS source** for LAN, household, and mesh. (Through 2026-06-21 it also synced A-records into a NetBird managed zone; that replica was retired in Phase 4, see changelog.) Formerly dnsmasq on [authentik (124)](../containers/124-authentik.md) (decommissioned 2026-06-04).
- **PVE host** (`192.168.8.77`): resolver is the local Netbird daemon at `100.122.38.109:53`, which forwards to the LAN/upstream and learns hubris.network answers via that path. `netbird status` says "Nameservers: 0/0 Available" — confirming netbird does NOT manage a hubris.network zone; it just caches whatever the system resolver returns.
- **All LXCs** now point at Technitium (`192.168.8.2`) directly (since 2026-06-21 — see changelog). The earlier mix of router DNS (`192.168.8.1`) / Tailscale MagicDNS (`100.100.100.100`) — which returned the public IONOS A record and forced `/etc/hosts` overrides — has been removed.
@@ -50,11 +50,11 @@ Creating a new Caddyfile site block is necessary but **not sufficient**. Without
## Recipe — adding a new subdomain
1. Edit `/etc/caddy/Caddyfile` on [caddy (121)](../containers/121-caddy.md), commit + push to `dtoro/caddy-conf`. Webhook reloads caddy. See [auto-deploy](auto-deploy.md).
2. Add the A record in the [Technitium UI](http://192.168.8.2) at `dns (107)` — the NetBird managed DNS zone sync picks it up within ~10 minutes via cron. Or add directly to the NetBird managed zone via API if you need it faster.
2. Add the A record in the [Technitium UI](http://192.168.8.2) at `dns (107)`. That's it — Technitium is the single DNS source; mesh peers forward to it live and LAN/household query it directly. (No managed-zone sync to wait for — retired 2026-06-21, Phase 4.)
3. Verify: `dig @192.168.8.2 +short <new>.hubris.network``192.168.8.175`.
4. On macOS clients, flush: `sudo dscacheutil -flushcache && sudo killall -HUP mDNSResponder`.
4. On macOS clients, flush: `sudo dscacheutil -flushcache && sudo killall -HUP mDNSResponder`. On a NetBird peer that caches a stale answer, `netbird service restart` clears its resolver cache.
> The Technitium config on LXC 107 is the single source of truth. Never hand-edit the NetBird managed zone directly — the [`scripts/dns-sync.py`](../scripts/dns-sync.py) cron on 107 reconciles them and reaps stale records. See [dns.md changelog 2026-06-03](#2026-06-03--single-authoring-source-technitium--netbird-managed-zone-sync).
> Technitium on LXC 107 is the single source of truth. (Through 2026-06-21 a `dns-sync.py` cron mirrored it into a NetBird managed zone; that replica + cron were removed in Phase 4 once mesh peers were forwarding directly — see [changelog](#2026-06-21--dns-single-source-phase-4-complete--managed-zone-removed-technitium-is-the-single-source).)
## Public path — what does and doesn't follow the LAN map
@@ -76,6 +76,21 @@ Either:
## Changelog
### 2026-06-21 — DNS single-source, Phase 4: COMPLETE — managed zone removed, Technitium is the single source
After upgrading the Mac client `0.68.3 → 0.71.3` (matching mgmt) and clearing its NetBird resolver cache (`netbird service restart`), the managed-zone deletion was retried and **works**: with 0 managed-zone records, the Mac resolves `git`/`cloud`/`nfs-export`/`auth`.hubris.network entirely by forwarding to Technitium (`192.168.8.2`). The iPhone confirmed the same on **cellular** (no LAN/Fritz path — proof it's the mesh-forward path).
So the first deletion attempt (the REVERTED entry below) was a **misdiagnosis**: forwarding wasn't broken — the old 0.68.3 client's resolver cache (`100.122.255.254`) held stale/empty answers and wouldn't clear on `down/up` (only a full daemon restart clears it), and the Mac's dual LAN+mesh resolver paths muddied the test. A direct query (`dig @100.122.255.254 <unsynced-name>`) had in fact shown forwarding working all along.
**Done:**
- Deleted all 23 NetBird managed-zone A-records via API.
- Removed the `*/10` sync cron (`/etc/cron.d/dns-sync`). Kept `/opt/dns-sync/sync.py` + token + a pre-deletion backup as an emergency-restore tool only (run it once to rebuild the managed zone if ever reverting).
**End state — one zone:** Technitium (`192.168.8.2`) is the single authoring + serving source. Mesh peers forward to it (route via `Core``192.168.8.0/24`); LAN/household query it directly (Fritz!Box DNSv4 → Technitium). No managed-zone replica, no sync.
**Prereqs for it to keep working:** mesh clients on NetBird **0.71.x+**, and roaming peers in the `Core` group (route) — both satisfied. Other peers (laptops, proxmox-server) pick up forwarding as their resolver caches expire, or after a `netbird service restart`.
**Optional, not done:** flip the Technitium wildcard `*.hubris.network` from `→ 82.165.190.79` (VPS, mirrors public) to `→ 192.168.8.175` (Caddy) so new Caddy services need zero DNS entries. Deferred — decide separately.
### 2026-06-21 — DNS single-source, Phase 4: ATTEMPTED + REVERTED — managed zone is load-bearing
Tried to collapse to a single zone by deleting the NetBird managed-zone replica (and pausing `dns-sync`). Result: **mesh-peer DNS broke.** With the managed zone gone, the Mac (NetBird 0.68.3) failed to resolve `git`/`cloud`/`nfs-export`.hubris.network via the NetBird resolver (`100.122.255.254`) — the `home-lab-dns` nameserver group (`→ 192.168.8.2`) reports `Available` but does **not** actually serve forwarded queries. Restored the managed zone via `dns-sync.py` (23 records) and re-enabled the cron; resolution recovered immediately.