{ config, lib, ... }: let # Function to generate CoreDNS config for a single vhost generateCoreDNSConfigForVhost = domain: conf: let # Retrieve architect's IP on each interface interfaceConfigs = builtins.map (iface: let architectIP = config.architect.networks.${iface}.devices.architect.address; interfaceNet = config.architect.networks.${iface}.net; in '' ${domain} { view ${iface} { expr incidr(client_ip(), '${interfaceNet}') } template IN A ${domain} { answer "${domain}. 60 IN A ${architectIP}" } template IN HTTPS ${domain} { answer "${domain}. 60 IN HTTPS 1 . ipv4hint=\"${architectIP}\"" } cache log } '' ) conf.dnsInterfaces; in lib.concatStringsSep "\n" interfaceConfigs; in { services = { coredns = { enable = true; config = '' ${lib.concatStringsSep "\n" (lib.mapAttrsToList generateCoreDNSConfigForVhost config.architect.vhost)} . { cache forward . 127.0.0.1:${toString config.services.adguardhome.settings.dns.port} } ''; }; adguardhome = { enable = true; settings = { port = 5354; dns = { port = 5300; }; upstream_dns = [ "tls://architect.d65174.dns.nextdns.io" "https://dns.nextdns.io/d65174/architect" ]; }; }; dnscrypt-proxy2 = { enable = true; settings = { listen_addresses = [ "127.0.0.1:5354" ]; ipv4_servers = true; ipv6_servers = false; block_ipv6 = true; dnscrypt_servers = true; doh_servers = true; require_nolog = true; require_nofilter = true; timeout = 350; lb_strategy = "p4"; lb_estimator = true; ignore_system_dns = true; fallback_resolvers = [ "1.1.1.1:53" "9.9.9.9:53" ]; cache_min_ttl = 60; cache_max_ttl = 360; }; }; }; }