# Managed by Ansible (roles/resolvers/templates/nixos-unbound.nix.j2) # Settings derived from unbound.conf.j2 — same configuration as resolver1. { config, pkgs, lib, ... }: let accessControl = [ "0.0.0.0/0 refuse" "::0/0 refuse" {%- for netblock in resolver_allowed_netblocks %} "{{ netblock }} allow" {%- endfor %} ]; blocklistZone = pkgs.writeText "blocklist.rpz" '' $TTL 3600 $ORIGIN blocklist.rpz. @ IN SOA localhost. root.localhost. 1 3600 600 86400 3600 @ IN NS localhost. {%- for domain in resolver_blocked_domains | default([]) %} {{ domain }} CNAME . *.{{ domain }} CNAME . {%- endfor %} ''; in { services.unbound = { enable = true; settings = { server = { interface = [ "0.0.0.0" "::0" ]; port = 53; # DoH endpoint via loopback (Caddy terminates TLS upstream) interface-auto = false; https-port = 8080; http-endpoint = "/dns-query"; http-notls-downstream = true; access-control = accessControl; # Performance tuning num-threads = 4; msg-cache-size = "512m"; rrset-cache-size = "512m"; key-cache-size = "512m"; msg-cache-slabs = 8; rrset-cache-slabs = 8; infra-cache-slabs = 8; key-cache-slabs = 8; num-queries-per-thread = 1024; outgoing-port-permit = "32768-60999"; outgoing-num-tcp = 100; incoming-num-tcp = 600; # Prefetch and serve-expired prefetch = true; prefetch-key = true; serve-expired = true; serve-expired-ttl = 86400; serve-expired-client-timeout = 1800; # Socket tuning so-reuseport = true; so-rcvbuf = "4m"; ip-transparent = true; edns-buffer-size = 1232; edns-tcp-keepalive = true; # Hardening harden-short-bufsize = true; harden-large-queries = true; harden-glue = true; harden-dnssec-stripped = true; harden-below-nxdomain = true; aggressive-nsec = true; qname-minimisation = true; # Logging log-time-ascii = true; # Statistics extended-statistics = true; shm-enable = false; }; remote-control = { control-enable = true; control-interface = "127.0.0.1"; control-port = 8953; control-use-cert = false; }; rpz = { name = "blocklist.rpz"; zonefile = "${blocklistZone}"; rpz-action-override = "nxdomain"; rpz-log = true; rpz-log-name = "blocklist"; }; }; # DNSSEC root trust anchor enableRootTrustAnchor = true; }; # Python for Ansible management (appended, doesn't clobber other packages) environment.systemPackages = lib.mkAfter [ pkgs.python3 ]; # Open DNS ports networking.firewall.allowedTCPPorts = [ 53 ]; networking.firewall.allowedUDPPorts = [ 53 ]; }