When SSH to a Pi targets a WireGuard tunnel address, reachability depends on
three things that each fail independently: the unit starting at boot, the NAT
mapping staying open, and the peer hostname still resolving. Rebooting onto a
network with no route to the endpoint previously meant no way back in.
- wg-quick@wg0.service.d/10-boot-resilience.conf: retry a failed boot-time up
forever (Restart=on-failure, RestartSec=15, StartLimitIntervalSec=0) and cap
endpoint resolution (WG_ENDPOINT_RESOLUTION_RETRIES=60, TimeoutStartSec=120)
instead of hanging on the stock infinity.
- wg0-watchdog: POSIX sh healer, oldest symptom first - missing interface or
peer restarts the unit, a missing PersistentKeepalive is set directly, a
stale handshake re-points the peer at a freshly resolved endpoint, and a
very stale one restarts. Restarts are gap-limited so a broken network cannot
make the unit flap, endpoint resolution falls back to the kernel endpoint
and then to a last-known-good cache (tunnel DNS may only be reachable
through the tunnel), and nothing it did not create is ever removed.
Supports --dry-run.
- wg0-watchdog.service/.timer: oneshot on a 60s timer, first check 30s after
boot, Persistent=true to catch up after downtime, TimeoutStartSec=120 and
Nice=10 so a restart cannot wedge the watchdog.
- wg0.conf.template: documents /etc/wireguard/wg0.conf with placeholders only.
Deliberately omits the DNS key so name resolution does not depend on the
tunnel (Debian wg-quick has no `DNS = none`), and sets PersistentKeepalive
25 to hold the NAT mapping for inbound SSH.
- wireguard.md: runbook for the placeholder table, failure modes, deploy, and
verification.
The real wg0.conf and key material never enter the repo.
LLM-Generated: true