at 23.11-pre 5.4 kB view raw
1{ config, lib, pkgs, ... }: 2 3with lib; 4 5let 6 cfg = config.services.adguardhome; 7 8 args = concatStringsSep " " ([ 9 "--no-check-update" 10 "--pidfile /run/AdGuardHome/AdGuardHome.pid" 11 "--work-dir /var/lib/AdGuardHome/" 12 "--config /var/lib/AdGuardHome/AdGuardHome.yaml" 13 ] ++ cfg.extraArgs); 14 15 configFile = pkgs.writeTextFile { 16 name = "AdGuardHome.yaml"; 17 text = builtins.toJSON cfg.settings; 18 checkPhase = "${pkgs.adguardhome}/bin/adguardhome -c $out --check-config"; 19 }; 20 21in 22{ 23 24 imports = 25 let cfgPath = [ "services" "adguardhome" ]; 26 in 27 [ 28 (mkRenamedOptionModuleWith { sinceRelease = 2211; from = cfgPath ++ [ "host" ]; to = cfgPath ++ [ "settings" "bind_host" ]; }) 29 (mkRenamedOptionModuleWith { sinceRelease = 2211; from = cfgPath ++ [ "port" ]; to = cfgPath ++ [ "settings" "bind_port" ]; }) 30 ]; 31 32 options.services.adguardhome = with types; { 33 enable = mkEnableOption (lib.mdDoc "AdGuard Home network-wide ad blocker"); 34 35 openFirewall = mkOption { 36 default = false; 37 type = bool; 38 description = lib.mdDoc '' 39 Open ports in the firewall for the AdGuard Home web interface. Does not 40 open the port needed to access the DNS resolver. 41 ''; 42 }; 43 44 mutableSettings = mkOption { 45 default = true; 46 type = bool; 47 description = lib.mdDoc '' 48 Allow changes made on the AdGuard Home web interface to persist between 49 service restarts. 50 ''; 51 }; 52 53 settings = mkOption { 54 default = null; 55 type = nullOr (submodule { 56 freeformType = (pkgs.formats.yaml { }).type; 57 options = { 58 schema_version = mkOption { 59 default = pkgs.adguardhome.schema_version; 60 defaultText = literalExpression "pkgs.adguardhome.schema_version"; 61 type = int; 62 description = lib.mdDoc '' 63 Schema version for the configuration. 64 Defaults to the `schema_version` supplied by `pkgs.adguardhome`. 65 ''; 66 }; 67 bind_host = mkOption { 68 default = "0.0.0.0"; 69 type = str; 70 description = lib.mdDoc '' 71 Host address to bind HTTP server to. 72 ''; 73 }; 74 bind_port = mkOption { 75 default = 3000; 76 type = port; 77 description = lib.mdDoc '' 78 Port to serve HTTP pages on. 79 ''; 80 }; 81 }; 82 }); 83 description = lib.mdDoc '' 84 AdGuard Home configuration. Refer to 85 <https://github.com/AdguardTeam/AdGuardHome/wiki/Configuration#configuration-file> 86 for details on supported values. 87 88 ::: {.note} 89 On start and if {option}`mutableSettings` is `true`, 90 these options are merged into the configuration file on start, taking 91 precedence over configuration changes made on the web interface. 92 93 Set this to `null` (default) for a non-declarative configuration without any 94 Nix-supplied values. 95 Declarative configurations are supplied with a default `schema_version`, `bind_host`, and `bind_port`. 96 ::: 97 ''; 98 }; 99 100 extraArgs = mkOption { 101 default = [ ]; 102 type = listOf str; 103 description = lib.mdDoc '' 104 Extra command line parameters to be passed to the adguardhome binary. 105 ''; 106 }; 107 }; 108 109 config = mkIf cfg.enable { 110 assertions = [ 111 { 112 assertion = cfg.settings != null -> cfg.mutableSettings 113 || (hasAttrByPath [ "dns" "bind_host" ] cfg.settings) 114 || (hasAttrByPath [ "dns" "bind_hosts" ] cfg.settings); 115 message = 116 "AdGuard setting dns.bind_host or dns.bind_hosts needs to be configured for a minimal working configuration"; 117 } 118 { 119 assertion = cfg.settings != null -> cfg.mutableSettings 120 || hasAttrByPath [ "dns" "bootstrap_dns" ] cfg.settings; 121 message = 122 "AdGuard setting dns.bootstrap_dns needs to be configured for a minimal working configuration"; 123 } 124 ]; 125 126 systemd.services.adguardhome = { 127 description = "AdGuard Home: Network-level blocker"; 128 after = [ "network.target" ]; 129 wantedBy = [ "multi-user.target" ]; 130 unitConfig = { 131 StartLimitIntervalSec = 5; 132 StartLimitBurst = 10; 133 }; 134 135 preStart = optionalString (cfg.settings != null) '' 136 if [ -e "$STATE_DIRECTORY/AdGuardHome.yaml" ] \ 137 && [ "${toString cfg.mutableSettings}" = "1" ]; then 138 # Writing directly to AdGuardHome.yaml results in empty file 139 ${pkgs.yaml-merge}/bin/yaml-merge "$STATE_DIRECTORY/AdGuardHome.yaml" "${configFile}" > "$STATE_DIRECTORY/AdGuardHome.yaml.tmp" 140 mv "$STATE_DIRECTORY/AdGuardHome.yaml.tmp" "$STATE_DIRECTORY/AdGuardHome.yaml" 141 else 142 cp --force "${configFile}" "$STATE_DIRECTORY/AdGuardHome.yaml" 143 chmod 600 "$STATE_DIRECTORY/AdGuardHome.yaml" 144 fi 145 ''; 146 147 serviceConfig = { 148 DynamicUser = true; 149 ExecStart = "${pkgs.adguardhome}/bin/adguardhome ${args}"; 150 AmbientCapabilities = [ "CAP_NET_BIND_SERVICE" ]; 151 Restart = "always"; 152 RestartSec = 10; 153 RuntimeDirectory = "AdGuardHome"; 154 StateDirectory = "AdGuardHome"; 155 }; 156 }; 157 158 networking.firewall.allowedTCPPorts = mkIf cfg.openFirewall [ cfg.settings.bind_port ]; 159 }; 160}