{ config, lib, ... }: with lib; let inherit (config.networking) domain; cfg = config.local.ns.server; acmeChallengeDomain = "acme-challenge.${domain}"; in { options. local. ns. server = { enable = mkEnableOption "nsd authoritative server"; tsigName = mkOption { type = types.str; default = "NOKEY"; }; acme = { apiListen.v6 = mkOption { type = types.str; }; dnsListen.v6 = mkOption { type = types.str; }; }; }; config = mkIf cfg.enable { assertions = [ { assertion = cfg.tsigName == "NOKEY" || config.services.nsd.keys ? "${cfg.tsigName}"; message = "TSIG key '${cfg.tsigName}' not defined"; } ]; networking.firewall = let inherit (config.services.nsd) port; in { allowedTCPPorts = [ port ]; allowedUDPPorts = [ port ]; }; services = { acme-dns = { enable = true; settings = { api = { ip = "[${cfg.acme.apiListen.v6}]"; port = 80; }; general = { domain = acmeChallengeDomain; nsname = acmeChallengeDomain; nsadmin = "hostmaster.${domain}"; listen = "[${cfg.acme.dnsListen.v6}]:53"; records = [ "${acmeChallengeDomain}. NS ${acmeChallengeDomain}." "${acmeChallengeDomain}. AAAA ${cfg.acme.dnsListen.v6}" ]; }; }; }; nsd = { enable = true; ipFreebind = true; bind8Stats = true; statistics = 3600; tcpCount = 128; tcpTimeout = 30; tcpQueryCount = 128; zones = mapAttrs' (name: zone: nameValuePair "${name}." zone.nsdConfig) config.local.ns.zones; }; }; }; }