infra/ansible/roles/resolvers/templates/nixos-unbound.nix.j2
2026-06-21 13:39:36 -05:00

114 lines
2.9 KiB
Django/Jinja

# 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 ];
}