Summary
Add an optional keepalived + Virtual IP (VIP) layer so LAN DNS fails over
seamlessly between the primary AdGuard (linux-server/adguard) and the secondary
AdGuard on the Pi (linux-pi/adguard).
This is a potential follow-up, not urgent. The current setup already survives a
full main-server outage — the Pi resolver is self-sufficient (public DoH upstreams,
host-networked :53, filtering active, decoupled from Tailscale/the server). The
only rough edge is client steering: the router hands out DNS as
[<server-ip> primary, <pi-ip> secondary], and secondary-DNS failover is not
deterministic — some clients keep hitting the dead primary until a timeout before
falling back. Verdict today: works-but-degraded.
Proposal
Introduce a floating VIP (a spare LAN address outside the DHCP pool, e.g.
<vip>) managed by keepalived/VRRP across both resolver hosts:
- Primary host = MASTER (higher priority), normally holds the VIP.
- Pi = BACKUP; claims the VIP within ~1–3s if the master's VRRP heartbeats stop.
- A
vrrp_script health check probes AdGuard on :53 so the VIP also moves when
AdGuard itself dies while the host stays up (not just on a full crash).
- Router DHCP then hands out only the VIP as DNS — no primary/secondary racing,
so failover is invisible to clients.
Keeps the same AdGuard software on both ends, so filtering + split-horizon behavior
is preserved regardless of which node holds the VIP. LAN-only; tailnet HTTPS admin
access via the sidecars is unaffected.
Suggested shape (mirror existing per-service layout)
- New
linux-server/keepalived/ and a Pi counterpart under linux-pi/, each with a
tracked keepalived.conf template + .env.example (VIP, interface, router id,
auth pass, priority) and a :53 health-check script; real values in gitignored
.env, placeholders committed.
- Document the router change (hand out the VIP as the sole DNS) in the UPS/DNS
runbooks and docs/.
Acceptance criteria
Notes / caveats
- Requires both nodes on the same L2 subnet (they are) and VRRP allowed on the LAN
(multicast 224.0.0.18, IP proto 112 — fine on typical home switches).
- Overkill for most home LANs; the degraded secondary-DNS path usually self-recovers
within seconds. This buys zero-hiccup failover, nothing more.
- Alternative considered: make the Pi the sole DHCP DNS (moves the SPOF to the Pi) —
rejected in favor of an active/backup VIP.
Context: verified DNS-resilience discussion during the PR #61 live-verification work.
Summary
Add an optional keepalived + Virtual IP (VIP) layer so LAN DNS fails over
seamlessly between the primary AdGuard (
linux-server/adguard) and the secondaryAdGuard on the Pi (
linux-pi/adguard).This is a potential follow-up, not urgent. The current setup already survives a
full main-server outage — the Pi resolver is self-sufficient (public DoH upstreams,
host-networked
:53, filtering active, decoupled from Tailscale/the server). Theonly rough edge is client steering: the router hands out DNS as
[<server-ip> primary, <pi-ip> secondary], and secondary-DNS failover is notdeterministic — some clients keep hitting the dead primary until a timeout before
falling back. Verdict today: works-but-degraded.
Proposal
Introduce a floating VIP (a spare LAN address outside the DHCP pool, e.g.
<vip>) managed by keepalived/VRRP across both resolver hosts:vrrp_scripthealth check probes AdGuard on:53so the VIP also moves whenAdGuard itself dies while the host stays up (not just on a full crash).
so failover is invisible to clients.
Keeps the same AdGuard software on both ends, so filtering + split-horizon behavior
is preserved regardless of which node holds the VIP. LAN-only; tailnet HTTPS admin
access via the sidecars is unaffected.
Suggested shape (mirror existing per-service layout)
linux-server/keepalived/and a Pi counterpart underlinux-pi/, each with atracked
keepalived.conftemplate +.env.example(VIP, interface, router id,auth pass, priority) and a
:53health-check script; real values in gitignored.env, placeholders committed.runbooks and
docs/.Acceptance criteria
Pi within a few seconds; DNS keeps resolving + filtering via the VIP throughout.
virtual_router_id, distinct priorities, shared auth).names in any tracked file.
Notes / caveats
(multicast
224.0.0.18, IP proto 112 — fine on typical home switches).within seconds. This buys zero-hiccup failover, nothing more.
rejected in favor of an active/backup VIP.
Context: verified DNS-resilience discussion during the PR #61 live-verification work.