From 85b1c3ecbff223a8634b3c785e6e23208c236dbc Mon Sep 17 00:00:00 2001 From: rope Date: Tue, 15 Sep 2026 13:50:03 +0100 Subject: [PATCH] Order network jobs after DNS readiness --- services/adguard.nix | 26 ++++++++++++++++++++++++++ services/cloudflare-ddns.nix | 7 +++++++ services/crowdsec.nix | 12 ++++++++++++ 3 files changed, 45 insertions(+) diff --git a/services/adguard.nix b/services/adguard.nix index 57c75e7..06140be 100644 --- a/services/adguard.nix +++ b/services/adguard.nix @@ -1,5 +1,27 @@ # services/adguard.nix — AdGuard Home network-wide DNS ad blocker { config, lib, pkgs, ... }: +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") { @@ -45,6 +67,10 @@ }; }; + # 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. }; diff --git a/services/cloudflare-ddns.nix b/services/cloudflare-ddns.nix index fd9416a..ed91f4b 100644 --- a/services/cloudflare-ddns.nix +++ b/services/cloudflare-ddns.nix @@ -7,5 +7,12 @@ apiTokenFile = "/var/secrets/cloudflare-token"; domains = [ "nordhammer.it" ]; }; + + # network-online.target stays active while AdGuard is restarted during + # deployment. Wait for AdGuard's DNS-readiness check as well. + systemd.services.cloudflare-dyndns = { + after = [ "network-online.target" "adguardhome.service" ]; + wants = [ "network-online.target" "adguardhome.service" ]; + }; }; } diff --git a/services/crowdsec.nix b/services/crowdsec.nix index e66ba48..e6ec713 100644 --- a/services/crowdsec.nix +++ b/services/crowdsec.nix @@ -142,5 +142,17 @@ in enable = true; registerBouncer.enable = true; }; + + # CrowdSec setup and hub refresh both contact the upstream hub. The + # generic online target does not become inactive when local DNS restarts, + # so explicitly order these jobs after AdGuard's DNS-readiness check. + systemd.services.crowdsec-setup = { + after = [ "adguardhome.service" ]; + wants = [ "adguardhome.service" ]; + }; + systemd.services.crowdsec-update-hub = { + after = [ "adguardhome.service" ]; + wants = [ "adguardhome.service" ]; + }; }; }