aboutsummaryrefslogtreecommitdiff
path: root/modules/adguard.nix
diff options
context:
space:
mode:
authorKaran Jayachandra <mail@karanjayachandra.com>2026-07-18 23:04:53 +0200
committerKaran Jayachandra <mail@karanjayachandra.com>2026-07-18 23:04:53 +0200
commit9ceddb33272e5fca6382c1b4dec2074bd1167738 (patch)
treecac68c1bdc90c9ab618e4fdb4c8eb65d27d9a647 /modules/adguard.nix
parent718a79f8de2a55f2ab83cac7e8595cd3916ed486 (diff)
Simplify config and add AdGuard DoH/DoT support
- Replace the hand-rolled Podman OCI container for Actual Budget with the native services.actual module (available in the pinned nixpkgs release); the container never actually had a backend enabled, so it likely never ran. - Collapse cgit's Caddy routing to a single reverse proxy - the smart-HTTP git backend was already served on the same nginx vhost/port as cgit itself, so the separate /git/* -> 8085 route was dead and pointed at a port nothing listened on. - Drop the unused kvm-intel kernel module from the guest hardware profile, and rename disko's misleadingly-named ESP partition (it's ext4, not a real EFI System Partition). - Point common.nix's disabled autoUpgrade flake URL at this repo's own cgit hosting instead of a generic GitHub placeholder. - Add AdGuard Home DNS-over-TLS (853) and DNS-over-HTTPS (8443) support, backed by an independent ACME certificate (modules/acme.nix) issued via a webroot Caddy serves on port 80. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Diffstat (limited to 'modules/adguard.nix')
-rw-r--r--modules/adguard.nix36
1 files changed, 33 insertions, 3 deletions
diff --git a/modules/adguard.nix b/modules/adguard.nix
index 85c5f5c..e66d072 100644
--- a/modules/adguard.nix
+++ b/modules/adguard.nix
@@ -2,8 +2,20 @@
# AdGuard Home - DNS resolver + optional network-wide ad blocker.
#
-# DNS listens on port 53 (udp/tcp) directly on the public IP.
-# The web UI listens on 127.0.0.1:3000 and is fronted by Caddy.
+# Plain DNS listens on port 53 (udp/tcp) directly on the public IP.
+# DNS-over-TLS (853/tcp) and DNS-over-HTTPS (8443/tcp, path /dns-query) are
+# also served directly by AdGuard itself, terminating TLS with their own
+# independent Let's Encrypt cert (modules/acme.nix) - NOT via Caddy, since
+# Caddy already owns port 443 for its own reverse-proxied vhosts and
+# AdGuard's HTTPS/DoH listener needs its own port.
+#
+# AdGuard's HTTPS/DoH listener binds to the same host as the plain `http`
+# listener below (confirmed in AdGuardHome's source: both come from
+# HTTPConfig.Address) - that's why `http.address` binds 0.0.0.0 rather than
+# 127.0.0.1 even though the plain-HTTP web UI is still meant to be reached
+# only via Caddy's reverse proxy: port 3000 itself is never opened in the
+# firewall (modules/common.nix), so it's still unreachable directly.
+# DNS-over-TLS reuses `dns.bind_hosts` below, so it needs no such change.
#
# Admin password is seeded from a sops secret containing a bcrypt hash.
# To generate the hash on your local machine:
@@ -16,7 +28,19 @@
settings = {
http = {
- address = "127.0.0.1:3000";
+ address = "0.0.0.0:3000";
+ };
+
+ tls = {
+ enabled = true;
+ server_name = "dns.karanj.com";
+ port_https = 8443;
+ port_dns_over_tls = 853;
+ # DNS-over-QUIC and DNSCrypt were not requested - keep them off.
+ port_dns_over_quic = 0;
+ port_dnscrypt = 0;
+ certificate_path = "/var/lib/acme/dns.karanj.com/fullchain.pem";
+ private_key_path = "/var/lib/acme/dns.karanj.com/key.pem";
};
dns = {
@@ -25,6 +49,7 @@
# Clients configure this server's public IPv4 address (not
# dns.karanj.com - that hostname only resolves to the HTTPS web UI
# via Caddy) as their plain DNS resolver, e.g. <server-ipv4>:53.
+ # For encrypted DNS, see the client setup notes in README.md.
# Upstream DNS resolvers (privacy-respecting)
upstream_dns = [
"https://dns.quad9.net/dns-query"
@@ -96,6 +121,11 @@
# `sed -i`: sed -i creates a temp file and chowns/renames it in place, and
# this unit's hardened SystemCallFilter (~@privileged) blocks the chown
# syscall, killing sed with SIGSYS ("Bad system call").
+ # Don't attempt the first start until the ACME cert referenced by
+ # tls.certificate_path/private_key_path above actually exists.
+ systemd.services.adguardhome.after = [ "acme-dns.karanj.com.service" ];
+ systemd.services.adguardhome.wants = [ "acme-dns.karanj.com.service" ];
+
systemd.services.adguardhome.serviceConfig = {
DynamicUser = lib.mkForce false;
User = "adguardhome";