{ config, pkgs, lib, ... }: with lib; let acmeChallengeZonefile = domain: let reverseDomain = concatStringsSep "." (reverseList (["_acme-challenge"] ++ splitString "." domain)); in pkgs.writeText "${reverseDomain}.zone" '' $ORIGIN _acme-challenge.${domain}. $TTL 3600 @ IN SOA ns.yggdrasil.li. root.yggdrasil.li. 2022022103 10800 3600 604800 30 IN NS ns.yggdrasil.li. ''; in { config = { fileSystems."/var/lib/knot" = { device = "surtr/safe/var-lib-knot"; fsType = "zfs"; }; systemd.services.knot.unitConfig.RequiresMountsFor = [ "/var/lib/knot" ]; services.knot = { enable = true; keyFiles = [ config.sops.secrets."rheperire.org_acme_key.yaml".path config.sops.secrets."webdav.141.li_acme_key.yaml".path config.sops.secrets."knot_local_key.yaml".path ]; extraConfig = '' server: listen: 127.0.0.1@53 listen: ::1@53 listen: 202.61.241.61@53 listen: 2a03:4000:52:ada::@53 remote: - id: inwx_notify address: 185.181.104.96@53 - id: recursive address: ::1@5353 - id: local address: ::1@53 key: local_key acl: - id: inwx_acl address: 185.181.104.96 action: transfer - id: rheperire.org_acme_acl key: rheperire.org_acme_key action: update - id: webdav.141.li_acme_acl key: webdav.141.li_acme_key action: update - id: local_acl key: local_key action: update update-type: DS mod-rrl: - id: default rate-limit: 200 slip: 2 mod-cookies: - id: default secret-lifetime: 4h badcookie-slip: 1 submission: - id: validating-resolver parent: recursive check-interval: 5m policy: - id: rsa2048 algorithm: rsasha256 ksk-size: 4096 zsk-size: 2048 zsk-lifetime: 30d ksk-submission: validating-resolver - id: ed25519 algorithm: ed25519 nsec3: on nsec3-iterations: 0 ksk-lifetime: 360d signing-threads: 2 ksk-submission: validating-resolver - id: ed25519_local-push algorithm: ed25519 nsec3: on nsec3-iterations: 0 ksk-lifetime: 360d signing-threads: 2 ksk-submission: validating-resolver cds-cdnskey-publish: double-ds propagation-delay: 0 ds-push: [local] template: - id: default global-module: [mod-cookies/default, mod-rrl/default] - id: inwx_zone storage: /var/lib/knot zonefile-sync: -1 zonefile-load: difference-no-serial serial-policy: dateserial journal-content: all semantic-checks: on dnssec-signing: on dnssec-policy: ed25519 notify: [inwx_notify] acl: [inwx_acl] - id: acme_zone storage: /var/lib/knot zonefile-sync: -1 zonefile-load: difference-no-serial serial-policy: dateserial journal-content: all semantic-checks: on dnssec-signing: on dnssec-policy: ed25519_local-push zone: - domain: yggdrasil.li template: inwx_zone file: ${./zones/li.yggdrasil.soa} - domain: nights.email template: inwx_zone file: ${./zones/email.nights.soa} - domain: 141.li template: inwx_zone acl: [local_acl, inwx_acl] file: ${./zones/li.141.soa} - domain: _acme-challenge.webdav.141.li template: acme_zone acl: [webdav.141.li_acme_acl] file: ${acmeChallengeZonefile "webdav.141.li"} - domain: kleen.li template: inwx_zone file: ${./zones/li.kleen.soa} - domain: xmpp.li template: inwx_zone file: ${./zones/li.xmpp.soa} - domain: dirty-haskell.org template: inwx_zone file: ${./zones/org.dirty-haskell.soa} - domain: praseodym.org template: inwx_zone file: ${./zones/org.praseodym.soa} - domain: rheperire.org template: inwx_zone acl: [local_acl, inwx_acl] file: ${./zones/org.rheperire.soa} - domain: _acme-challenge.rheperire.org template: acme_zone acl: [rheperire.org_acme_acl] file: ${acmeChallengeZonefile "rheperire.org"} ''; }; sops.secrets = { "rheperire.org_acme_key.yaml" = { format = "binary"; owner = "knot"; sopsFile = ./keys/rheperire.org_acme.yaml; }; "webdav.141.li_acme_key.yaml" = { format = "binary"; owner = "knot"; sopsFile = ./keys/webdav.141.li_acme.yaml; }; "knot_local_key.yaml" = { format = "binary"; owner = "knot"; sopsFile = ./keys/local_key.yaml; }; }; fileSystems."/var/lib/unbound" = { device = "surtr/local/var-lib-unbound"; fsType = "zfs"; }; systemd.services.unbound.unitConfig.RequiresMountsFor = [ "/var/lib/unbound" ]; services.unbound = { enable = true; resolveLocalQueries = false; stateDir = "/var/lib/unbound"; localControlSocketPath = "/run/unbound/unbound.ctl"; settings = { server = { interface = ["127.0.0.1@5353" "::1@5353"]; access-control = ["127.0.0.0/8 allow" "::1/128 allow"]; root-hints = "${pkgs.dns-root-data}/root.hints"; num-threads = 12; so-reuseport = true; msg-cache-slabs = 16; rrset-cache-slabs = 16; infra-cache-slabs = 16; key-cache-slabs = 16; rrset-cache-size = "100m"; msg-cache-size = "50m"; outgoing-range = 8192; num-queries-per-thread = 4096; so-rcvbuf = "4m"; so-sndbuf = "4m"; # serve-expired = true; # serve-expired-ttl = 86400; # serve-expired-reply-ttl = 0; prefetch = true; prefetch-key = true; minimal-responses = false; extended-statistics = true; rrset-roundrobin = true; use-caps-for-id = true; }; }; }; }; }