7.9 KiB
7.9 KiB
AdGuard migration to Pikachu: design tree
Research facts
- The pinned Nixpkgs revision provides
adguardhomeversion0.107.79. - NixOS provides the
services.adguardhomemodule. - The module runs AdGuard Home as a hardened dynamic systemd user.
- It stores state in
/var/lib/AdGuardHome. - It grants
CAP_NET_BIND_SERVICEfor DNS port 53. - It grants
CAP_NET_RAWwhen AdGuard Home DHCP is enabled. - The module supports an arbitrary YAML configuration through
settings. - The module supports fully declarative operation with
mutableSettings = false. - In fully declarative operation, the module replaces
/var/lib/AdGuardHome/AdGuardHome.yamlon each service start. - Fully declarative operation requires
dns.bootstrap_dnsas a list. - Declarative settings pass an AdGuard configuration check during the build.
mutableSettings = truemerges declared settings into UI changes at service start.mutableSettings = falsereplaces the state configuration on every service start.openFirewallopens only the web interface port.- The migration must explicitly open DNS ports 53/TCP and 53/UDP when clients need them.
- Pikachu has address
10.23.10.102on its untagged network. - Pikachu carries VLAN 20 and creates bridge
br-vlan20. - The guest framework runs each guest in its own systemd-nspawn container.
- Each guest attaches to a host VLAN bridge and receives an address through DHCP.
- Pikachu currently configures only VLAN 20 for guests.
- The repository has no AdGuard configuration, Proxmox inventory, or DHCP-provider configuration.
- The current DHCP provider remains unestablished.
- The current Proxmox AdGuard container uses MAC
bc:24:11:91:60:bf. - The current Proxmox AdGuard container uses address
10.23.20.33on VLAN 20. - This environment has no Proxmox SSH target or local Proxmox control utility.
- The current AdGuard configuration listens on all guest addresses at DNS port 53.
- The current AdGuard configuration has no allowed-client or disallowed-client restrictions.
- The current AdGuard configuration uses Cloudflare, Google, and Quad9 encrypted upstreams in parallel.
- The current AdGuard configuration disables DNSSEC.
- The current AdGuard configuration defines three local rewrites.
- The repository configures no host backup system or monitoring system.
- Hosts update through explicit
nixos-rebuild switch --flakecommands. - The working tree has unrelated operator changes.
Service tradeoffs
| Service | NixOS support | Domain filtering | Administration UI | DHCP | Encrypted DNS | Main tradeoff |
|---|---|---|---|---|---|---|
| AdGuard Home | services.adguardhome; checked YAML and mutable or immutable state |
Native block lists, rules, and per-client policy | Native | Native | Upstream and client-facing encrypted DNS | Direct migration with the closest state and feature match. UI state conflicts with fully declarative operation unless configuration is immutable. |
| Blocky | services.blocky; checked declarative YAML |
Native lists, allow lists, rewrites, and per-client groups | No UI; REST API and metrics only | No | Encrypted upstreams and client-facing DoH, DoT, and DoQ | Strong Git-managed configuration and low operational surface. It lacks an interactive administration interface and DHCP. |
| Pi-hole | services.pihole-ftl plus services.pihole-web; declarative TOML, lists, and dashboard |
Native gravity lists, allow lists, regex rules, and groups | Native | Native | Use a companion for encrypted upstream DNS | Familiar filtering product with a dashboard. The migration changes product data and uses more coupled services. |
| Technitium DNS Server | services.technitium-dns-server; service and firewall options only |
Native block lists and DNS applications | Native | Native | Upstream and client-facing encrypted DNS | Broadest DNS feature set, including authoritative DNS. NixOS does not expose its runtime configuration declaratively. |
| Unbound | services.unbound; structured server and free-form settings |
Local zones or response-policy zones require custom policy management | No | No | DNS-over-TLS support | Mature validating recursive resolver. Filtering and user operations require separate design. |
| dnscrypt-proxy | services.dnscrypt-proxy; declarative TOML |
Local block and allow rules, without a list-management UI | No | No | Encrypted upstream DNS, including DNSCrypt and DoH | Strong upstream privacy and resolver selection. It is not a full network filtering appliance. |
| Knot Resolver | services.kresd; structured listener settings and extra Lua |
Custom policy modules | No | No | Client-facing DoH and TLS listeners | Flexible high-performance recursive resolver. Filtering requires resolver expertise and custom policy. |
| SmartDNS | services.smartdns; free-form settings |
Domain and address rules | No NixOS-integrated UI | No | Encrypted upstream and client-facing DNS | Optimizes upstream selection and latency. It offers less complete filtering management than dedicated blockers. |
Native means that the product provides the feature without a companion service.
Decision tree
- D1 — DNS service product [settled]
- Retain AdGuard Home on Pikachu.
- Constraint: Preserve AdGuard Home as the DNS service product.
- D2A — AdGuard Home role [settled]
- Provides DNS filtering and resolution only.
- Constraint: The existing DHCP provider continues to assign addresses and DHCP options.
- D3A — Execution placement [settled]
- Runs in a dedicated guest on Pikachu's existing VLAN 20.
- Constraint: Isolate AdGuard Home from the Pikachu host.
- D4A — Guest network identity [settled]
- Reuses MAC
bc:24:11:91:60:bfand address10.23.20.33on VLAN 20. - Constraint: Stop the Proxmox container before the guest starts.
- Reuses MAC
- D5A — Network exposure [settled]
- Listens on all guest addresses at port 53.
- Accepts requests from every reachable internal device.
- D6A — Resolver policy [settled]
- Preserves the existing upstream resolvers and parallel resolver mode.
- Preserves disabled DNSSEC and the three local rewrites.
- D7A — Configuration authority [settled]
- Uses fully declarative Nix configuration.
- Constraint: Set
services.adguardhome.mutableSettings = false. - Constraint: Declare
dns.bootstrap_dnsas a list. - Constraint: Web UI changes do not persist.
- Constraint: Match existing service behavior except for the administrator password.
- D8A — Migration data [settled]
- Migrate functional DNS configuration only.
- Constraint: Do not migrate query history or statistics.
- D9A — Operations [settled]
- Declares a newly generated bcrypt verifier in Nix.
- Constraint: Keep the plaintext password outside the repository and Nix store.
- Constraint: The verifier is readable from the Nix store.
- D10A — Cutover and rollback [settled]
- Uses a planned atomic cutover with rollback.
- Stop the Proxmox container before starting the guest.
- Validate the guest before restoring the Proxmox container during rollback.
- D11A — Runtime-state backup [settled]
- Do not back up rebuildable AdGuard Home runtime state.
- D12A — Monitoring [settled]
- Do not add DNS availability monitoring.
- D13A — Upgrade ownership [settled]
- The normal flake update and explicit NixOS rebuild workflow owns upgrades.
- Replace AdGuard Home. [not selected]
- D2B — Replacement product [not applicable]
- Choose Blocky, Pi-hole, Technitium, or a composed resolver.
- D2B — Replacement product [not applicable]
- Retain AdGuard Home on Pikachu.
Frontier
None.
Sources
- Pinned Nixpkgs module:
nixos/modules/services/networking/adguardhome.nix. - Pinned Nixpkgs modules:
blocky.nix,pihole-ftl.nix,pihole-web.nix,technitium-dns-server.nix,unbound.nix,dnscrypt-proxy.nix,knot-resolver.nix, andsmartdns.nix. - AdGuard Home README, release
v0.107.79. - Technitium DNS Server README, current upstream.