- services/pihole.nix: official pihole/pihole:2026.07.2 via podman, host net,
caps NET_ADMIN/NET_RAW/SYS_NICE/CHOWN; FTLCONF_* env config (upstream unbound,
DHCP 50-200, static lease jupiter, .sol domain, local records)
- unbound: resolveLocalQueries=false (was hijacking resolv.conf to :53 -> boot
DNS deadlock; the real root cause of the earlier failures too)
- password via sops FTLCONF env file; /var/lib/pihole created via tmpfiles
- VM-verified: mercury.sol/jupiter.sol/external all resolve, 0 restarts
mercury is the DHCP server (no lease of its own) so its name wasn't resolvable.
Add explicit dns.hosts A records. VM-verified: both resolve, external unaffected.
- per-host darman_password (distinct hash) in secrets/{jupiter,vps,mercury}.yaml
-> hashedPasswordFile; different console password per host (ssh still key-only)
- mercury: dedicated age key (on boot partition post-flash), sops-nix wired
- AdGuard: module has no secret hook + writable config -> mutableSettings=true,
admin password set via web setup on first boot (never in repo/store)
- services/{samba,avahi,audiobookshelf,containers,caddy,tailscale}.nix
- common.nix grows firewall base + timezone; hosts import what they need
- jupiter/vm/vps import service modules; drop the jupiter/services.nix monolith
- each module opens its own firewall ports; caddy/tailscale shared by hosts
- verified: jupiter/vps/vbox eval + jupiter builds, config equivalent