DNS Architecture¶
DNS in this estate is split into five deliberately separate planes: an external authoritative service, an internal authoritative + resolver plane, a split-horizon view resolver, a public recursive resolver run as a community service, and a fixed upstream policy. Each plane fails independently of the others.
flowchart TD
subgraph external["External / authoritative"]
bind["BIND 9.20\nnameserver ns — LB .53\npublic 31.3.128.59"]
dnsdist["dnsdist on BPI-R4\nnative IPv6 frontend\nPROXYv2 → BIND"]
hap["haproxy on BPI-R4\npublic v4 TCP :53\nsend-proxy-v2 → BIND"]
end
subgraph internal["Internal"]
tech["Technitium — LB .54\ninternal zones + DHCP"]
unb["unbound split-horizon\nLB 192.168.1.1\ninternal views + recursion"]
end
opennic["OpenNIC tier-2\nrecursive — LB .44"]
nextdns["NextDNS\n(the only recursion upstream)"]
v6c["IPv6 clients"] --> dnsdist --> bind
v4t["IPv4 TCP clients"] --> hap --> bind
v4u["IPv4 UDP clients"] -->|DNAT| bind
lan["LAN clients"] --> unb --> tech
tech -.->|"DoT upstream"| nextdns
unb -.->|"failover only"| nextdns
lan --> tech
world["Public resolver users"] --> opennic
External authoritative — BIND¶
ns.mdapi.ch (BIND 9.20 in the nameserver namespace, LoadBalancer 192.168.1.53,
public 31.3.128.59) is authoritative for the public zones, with DNSSEC and
external secondaries (zone transfers restricted to them). Dynamic updates arrive
TSIG-signed (cert-manager DNS-01, external-dns).
What makes the front end unusual is client-address preservation through the PROXY protocol on both address families:
- IPv6 terminates natively at dnsdist on the router — no NAT64 —
and reaches BIND over IPv4 carrying a PROXYv2 header per UDP datagram. DNS is
the one protocol ecosystem where PROXY-over-UDP exists on both ends (dnsdist
sends it, BIND ≥ 9.20 accepts it on a dedicated
proxy plainlistener). - IPv4 TCP is fronted by haproxy on the router with
send-proxy-v2into the same listener; plain UDP is a straight DNAT.
The result: BIND sees every real client address on every transport, so rate-limiting and ACLs operate per-client rather than per-translator.
Internal — Technitium and split-horizon unbound¶
Technitium (LB .54) is the internal authoritative server and DHCP for the
LAN — internal zones, per-client control, and an API that the automation plane
drives (zone diffing, health probes, query-log shipping run as Windmill probes).
It also serves as unbound's default recursive upstream (DoT), so it resolves
external names on the LAN's behalf as well as the internal zones.
unbound (LB 192.168.1.1 — deliberately the address every DHCP client
already trusts) serves the split-horizon view: internal names resolve to internal
addresses, everything else recurses. Public names of self-hosted services resolve
to their LAN addresses here, so internal traffic never hairpins through the edge.
Non-override queries forward to Technitium first; NextDNS is a failover path only,
used if the Technitium LoadBalancer itself goes unreachable.
OpenNIC tier-2¶
A public recursive resolver (LB .44, IPv6 via the NAT64 prefix) run as an
OpenNIC community tier-2 — one of the estate's public-service contributions,
alongside the NTP pool membership.
Upstream policy¶
Recursion is internal-first: unbound forwards non-override queries to Technitium, which is the actual recursive resolver (DoT upstream). NextDNS sits behind both as the sole external fallback — one place for filtering policy, no fan-out to ad-hoc public resolvers, and no outage cascades from a single upstream being unreachable. This is a standing invariant across the router, unbound, and every appliance.