nixos/services/adguard.nix

80 lines
3.2 KiB
Nix
Raw Normal View History

# services/adguard.nix — AdGuard Home network-wide DNS ad blocker
{ config, lib, pkgs, ... }:
2026-09-15 13:50:03 +01:00
let
# AdGuard Home uses Type=simple, so systemd considers it started before its
# DNS listeners are necessarily accepting queries. Network-dependent units
# ordered after adguardhome.service need a stronger readiness boundary.
waitForDns = pkgs.writeShellScript "wait-for-adguard-dns" ''
attempt=0
while [ "$attempt" -lt 30 ]; do
# dnsmasq may answer on loopback while AdGuard is still starting, so
# probe AdGuard's exclusive LAN listener instead.
if answer="$(${pkgs.dnsutils}/bin/dig +short +time=1 +tries=1 @10.0.0.1 example.com A 2>/dev/null)"; then
if [ -n "$answer" ]; then
exit 0
fi
fi
attempt=$((attempt + 1))
${pkgs.coreutils}/bin/sleep 1
done
echo "AdGuard Home did not provide working upstream DNS within 30 seconds" >&2
exit 1
'';
in
{
config = lib.mkIf (config.networking.hostName == "FredOS-Mediaserver") {
services.adguardhome = {
enable = true;
# Web UI bound to localhost; nginx reverse-proxies at adguard.nordhammer.it
host = "127.0.0.1";
port = 3000;
# Nix is authoritative: settings below overwrite UI-made changes on rebuild
mutableSettings = false;
settings = {
dns = {
bind_hosts = [ "10.0.0.1" "127.0.0.1" ];
port = 53;
# Query all upstreams in parallel; take the fastest response
upstream_mode = "parallel";
# Mix of DoH (encrypted) and plain UDP (low-latency) upstreams
upstream_dns = [
"https://dns.cloudflare.com/dns-query"
"https://dns.quad9.net/dns-query"
"1.1.1.1"
"9.9.9.9"
];
bootstrap_dns = [ "1.1.1.1" "9.9.9.9" ];
cache_size = 4194304;
cache_ttl_min = 60;
};
filters = [
{ enabled = true; id = 1; name = "AdGuard DNS filter";
url = "https://adguardteam.github.io/AdGuardSDNSFilter/Filters/filter.txt"; }
{ enabled = true; id = 2; name = "AdAway Default Blocklist";
url = "https://adaway.org/hosts.txt"; }
{ enabled = true; id = 3; name = "OISD Big";
url = "https://big.oisd.nl/"; }
];
2026-09-15 15:04:48 +01:00
# Resolve hosted service subdomains directly to the router. Keep the
# bare nordhammer.it name public: Valheim/Steam identifies the server
# by that public endpoint, and router.nix reflects only the Pelican
# game-port range back into the LAN. Rewriting the bare name here made
# gameplay work but left the in-game browser showing a red status icon.
# `enabled` was added in AdGuard's recent schema and defaults to false.
filtering.rewrites = [
{ domain = "*.nordhammer.it"; answer = "10.0.0.1"; enabled = true; }
];
};
};
2026-09-15 13:50:03 +01:00
# Delay completion of adguardhome.service startup until DNS is genuinely
# usable, rather than merely until the AdGuard process has been spawned.
systemd.services.adguardhome.serviceConfig.ExecStartPost = [ waitForDns ];
# LAN clients reach :53 via the nftables "LAN trusted" rule in router.nix;
# WAN:53 is dropped there.
};
}