Files
dev/docs/00 INBOX/ai/adguard-pikachu-migration-design-tree.md

7.9 KiB

AdGuard migration to Pikachu: design tree

Research facts

  • The pinned Nixpkgs revision provides adguardhome version 0.107.79.
  • NixOS provides the services.adguardhome module.
  • The module runs AdGuard Home as a hardened dynamic systemd user.
  • It stores state in /var/lib/AdGuardHome.
  • It grants CAP_NET_BIND_SERVICE for DNS port 53.
  • It grants CAP_NET_RAW when 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.yaml on each service start.
  • Fully declarative operation requires dns.bootstrap_dns as a list.
  • Declarative settings pass an AdGuard configuration check during the build.
  • mutableSettings = true merges declared settings into UI changes at service start.
  • mutableSettings = false replaces the state configuration on every service start.
  • openFirewall opens 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.102 on 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.33 on 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 --flake commands.
  • 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:bf and address 10.23.20.33 on VLAN 20.
        • Constraint: Stop the Proxmox container before the guest starts.
      • 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_dns as 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.

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, and smartdns.nix.
  • AdGuard Home README, release v0.107.79.
  • Technitium DNS Server README, current upstream.