1 { config, lib, pkgs, ... }:
6 cfg = config.services.pdns-recursor;
8 oneOrMore = type: with types; either type (listOf type);
9 valueType = with types; oneOf [ int str bool path ];
10 configType = with types; attrsOf (nullOr (oneOrMore valueType));
12 toBool = val: if val then "yes" else "no";
13 serialize = val: with types;
14 if str.check val then val
15 else if int.check val then toString val
16 else if path.check val then toString val
17 else if bool.check val then toBool val
18 else if builtins.isList val then (concatMapStringsSep "," serialize val)
21 configDir = pkgs.writeTextDir "recursor.conf"
22 (concatStringsSep "\n"
23 (flip mapAttrsToList cfg.settings
24 (name: val: "${name}=${serialize val}")));
26 mkDefaultAttrs = mapAttrs (n: v: mkDefault v);
29 options.services.pdns-recursor = {
30 enable = mkEnableOption (lib.mdDoc "PowerDNS Recursor, a recursive DNS server");
32 dns.address = mkOption {
33 type = oneOrMore types.str;
34 default = [ "::" "0.0.0.0" ];
35 description = lib.mdDoc ''
36 IP addresses Recursor DNS server will bind to.
43 description = lib.mdDoc ''
44 Port number Recursor DNS server will bind to.
48 dns.allowFrom = mkOption {
49 type = types.listOf types.str;
51 "127.0.0.0/8" "10.0.0.0/8" "100.64.0.0/10"
52 "169.254.0.0/16" "192.168.0.0/16" "172.16.0.0/12"
53 "::1/128" "fc00::/7" "fe80::/10"
55 example = [ "0.0.0.0/0" "::/0" ];
56 description = lib.mdDoc ''
57 IP address ranges of clients allowed to make DNS queries.
61 api.address = mkOption {
64 description = lib.mdDoc ''
65 IP address Recursor REST API server will bind to.
72 description = lib.mdDoc ''
73 Port number Recursor REST API server will bind to.
77 api.allowFrom = mkOption {
78 type = types.listOf types.str;
79 default = [ "127.0.0.1" "::1" ];
80 example = [ "0.0.0.0/0" "::/0" ];
81 description = lib.mdDoc ''
82 IP address ranges of clients allowed to make API requests.
86 exportHosts = mkOption {
89 description = lib.mdDoc ''
90 Whether to export names and IP addresses defined in /etc/hosts.
94 forwardZones = mkOption {
97 description = lib.mdDoc ''
98 DNS zones to be forwarded to other authoritative servers.
102 forwardZonesRecurse = mkOption {
104 example = { eth = "[::1]:5353"; };
106 description = lib.mdDoc ''
107 DNS zones to be forwarded to other recursive servers.
111 dnssecValidation = mkOption {
112 type = types.enum ["off" "process-no-validate" "process" "log-fail" "validate"];
113 default = "validate";
114 description = lib.mdDoc ''
115 Controls the level of DNSSEC processing done by the PowerDNS Recursor.
116 See https://doc.powerdns.com/md/recursor/dnssec/ for a detailed explanation.
120 serveRFC1918 = mkOption {
123 description = lib.mdDoc ''
124 Whether to directly resolve the RFC1918 reverse-mapping domains:
126 `168.192.in-addr.arpa`,
127 `16-31.172.in-addr.arpa`
128 This saves load on the AS112 servers.
132 settings = mkOption {
135 example = literalExpression ''
138 log-common-errors = true;
141 description = lib.mdDoc ''
142 PowerDNS Recursor settings. Use this option to configure Recursor
143 settings not exposed in a NixOS option or to bypass one.
144 See the full documentation at
145 <https://doc.powerdns.com/recursor/settings.html>
146 for the available options.
150 luaConfig = mkOption {
153 description = lib.mdDoc ''
154 The content Lua configuration file for PowerDNS Recursor. See
155 <https://doc.powerdns.com/recursor/lua-config/index.html>.
160 config = mkIf cfg.enable {
162 services.pdns-recursor.settings = mkDefaultAttrs {
163 local-address = cfg.dns.address;
164 local-port = cfg.dns.port;
165 allow-from = cfg.dns.allowFrom;
167 webserver-address = cfg.api.address;
168 webserver-port = cfg.api.port;
169 webserver-allow-from = cfg.api.allowFrom;
171 forward-zones = mapAttrsToList (zone: uri: "${zone}.=${uri}") cfg.forwardZones;
172 forward-zones-recurse = mapAttrsToList (zone: uri: "${zone}.=${uri}") cfg.forwardZonesRecurse;
173 export-etc-hosts = cfg.exportHosts;
174 dnssec = cfg.dnssecValidation;
175 serve-rfc1918 = cfg.serveRFC1918;
176 lua-config-file = pkgs.writeText "recursor.lua" cfg.luaConfig;
180 log-timestamp = false;
181 disable-syslog = true;
184 systemd.packages = [ pkgs.pdns-recursor ];
186 systemd.services.pdns-recursor = {
187 wantedBy = [ "multi-user.target" ];
190 ExecStart = [ "" "${pkgs.pdns-recursor}/bin/pdns_recursor --config-dir=${configDir}" ];
194 users.users.pdns-recursor = {
196 group = "pdns-recursor";
197 description = "PowerDNS Recursor daemon user";
200 users.groups.pdns-recursor = {};
205 (mkRemovedOptionModule [ "services" "pdns-recursor" "extraConfig" ]
206 "To change extra Recursor settings use services.pdns-recursor.settings instead.")
209 meta.maintainers = with lib.maintainers; [ rnhmjoj ];