Keep sanitized Compose sources in-repo with a confirmation-gated Ansible playbook, add repo-wide validation, tighten runbook ownership/STOP/review metadata, and archive stale research docs. Co-authored-by: Cursor <cursoragent@cursor.com>
36 KiB
Home-LAN DNS alternatives for the windy LAN (research, 2026-08)
Status: research only. No configuration was changed. This page evaluates
resolvers/splitters that are genuinely better than — or meaningfully different
from — the current "AdGuard Home (AGH) + mosdns" setup on
dns.windy.lan (.36), for a GFW-constrained
China home LAN. Claims are cited to primary sources (official repos, official
docs, upstream READMEs); anything not verified is flagged as such.
2026-08-12: facts in this page's scope recap were refreshed by W1N-56 live verification — mosdns on
.1is not idle, it is clash'snameserver/default-nameserver(DIRECT-rule real-IP resolution); the canonical decision record islan-dns-architecture.md(final verdict aligned, Phase 0 kill-test evidence incl. a measured upstream-blackhole degradation gap).
Scope recap (from lan-overview.md, verified 2026-08-06):
- Clients get DNS via EdgeRouter DHCP option 6 → AGH
192.168.66.36:53. - AGH upstreams:
dns.alidns.com+doh.pubDoH (load-balanced), fallbackhttps://adg.chans.xyz/dns-query. DNSSEC disabled (known-bad-signature check failed on the selected path). Rewrites:hass.local/hass.windy.lan. gfwOpenWrt (.1) runs OpenClash fake-ip + TPROXY; dnsmasq → clash DNS127.0.0.1#7874.mosdnson127.0.0.1:6052is clash'snameserver/default-nameserver(DIRECT-rule real-IP resolution: domestic → AGH.36:53, foreign →223.5.5.5/119.29.29.29); it is not in the LAN client query path.- No local authoritative PTR source yet; private reverse DNS is a known gap.
1. TL;DR / recommendation
The current stack is already 80% of the answer. AGH is a strong LAN DNS
front-end (filtering, rewrites, per-client upstreams, query log, web UI) and its
upstream layer — per-domain upstreams plus a per-domain list loaded from a
file (upstream_dns_file) — is exactly the mechanism the official docs
recommend for accelerating China CDN domains while keeping everything else on a
trusted path. AGH configuration: upstreams.
The genuinely worthwhile changes, in order of value:
- Add geo-split inside AGH via
upstream_dns_filefed by a convertedaccelerated-domains.china.conf(felixonmars/dnsmasq-china-list): domestic CDN domains →dns.alidns.com/doh.pub; everything else → the trusted foreign path (currentlyadg.chans.xyz). This is a documented AGH use case, requires no new daemon, and removes the need for mosdns. This is the top recommendation. - Re-enable real DNSSEC by putting validation behind AGH: AGH's
enable_dnsseconly sets the DO bit — it does not validate (AGH config: DNSSEC). The two realistic ways are (a) point the foreign/trusted default upstream at a validating resolver (unbound, blocky) and re-test a known-bad-signature domain; or (b) insert a validating resolver (blocky is the lightest) between AGH and the upstreams. - mosdns on
.1is resolved, not idle — it is clash'snameserver/default-nameserver(DIRECT-rule real-IP resolution, verified 2026-08-12), so "delete it" is off the table; its role is documented inlan-dns-architecture.md§1. If a future change moves this role to an AGH-side companion, keep in mind mosdns's cache strips EDNS0 and it performs no DNSSEC validation (mosdns v5 executable plugins).
Top-3 alternatives worth pursuing (see §3 for detail):
| Rank | Option | Why |
|---|---|---|
| 1 | AGH with China-list geo-split (upstream_dns_file) |
Documented AGH pattern; single box; no new service; keeps filtering/rewrites/UI. |
| 2 | Blocky as validating backend behind AGH | The only "new software" option that adds real in-process DNSSEC validation + conditional per-domain upstreams + ECS in one static binary (blocky README, config). |
| 3 | Unbound as validating recursive resolver (replaces forwarders for the foreign path, or whole path) | True validation, full recursion (fail-open by nature), private local-zones; heavier ops than AGH's file-driven split. |
Explicitly not recommended as replacements here: smartdns and chinadns-ng (both excellent splitters, but neither validates DNSSEC and both lack AGH's filtering/UI/query-log layer, so they add a daemon without closing the DNSSEC gap); mihomo/sing-box DNS as the primary path (couples DNS to the proxy and is fail-closed; keep for proxy-side concerns only); knot-resolver/dnsdist (overkill for a single-operator home LAN).
2. Requirement matrix
Legend: ● native/built-in · ◐ possible with config/lists · ○ absent/ not applicable. "Geo-split" = route domestic vs foreign names to different upstreams. "Anti-pollution" = a mechanism to avoid/adjudicate poisoned answers (IP-verdict or trusted-upstream routing). "DNSSEC" = performs validation in-process (not just forwards DO).
| Candidate | Geo-split | Anti-pollution | DNSSEC (validate) | Cache | Private names / rewrites | Ops simplicity | License |
|---|---|---|---|---|---|---|---|
| AGH (current) | ◐ per-domain upstreams + list file | ◐ via trusted foreign upstream | ○ (DO bit only) | ● | ● rewrites, per-client, private-PTR | ● Docker + UI | GPL-3.0 |
| mosdns v5 | ● domain/ip list matchers | ◐ forward foreign→trusted | ○ | ● (strips EDNS0) | ● hosts/redirect/reverse_lookup | ◐ single binary, YAML, no UI | GPL-3.0 |
| smartdns | ● nameserver groups + domain lists | ● bogus-nxdomain / blacklist-ip / trusted groups | ○ (no option in config ref) | ● serve-expired | ● address / local-domain / lease file | ◐ single binary, optional WebUI plugin | GPL-3.0 |
| chinadns-ng | ● chnlist/gfwlist + tag:none IP-test | ● IP verdict via chnroute ipset/nftset | ○ | ● cache/stale/verdict | ◐ hosts / dns-rr-ip | ◐ single static binary, config file | AGPL-3.0 |
| dnsmasq-china-list | ◐ (data only) | ◐ (via host resolver) | ◐ via host | ◐ via host | ◐ via host | ◐ feed lists | WTFPL |
| unbound | ◐ forward-zones / RPZ / views | ◐ forward-zones + bogus-nxdomain | ● | ● serve-expired | ● local-zone / local-data | ◐ config daemon, no UI | BSD-style (NLnet) |
| blocky | ◐ conditional per-domain + client groups | ◐ blocking lists + conditional routing | ● | ● prefetch | ● customDNS / rewrite / hosts | ◐ single binary, YAML, REST (no full web UI) | Apache-2.0 |
| Technitium | ◐ conditional-forwarder zones / apps | ◐ blocked lists + forwarding | ● | ● persistent | ● zones, stub, split-horizon | ● .NET + web console | GPL-3.0 |
| sing-box | ● DNS rules (geoip/geosite) | ● rule-based servers + (proxy) sniffing | ○ | ● LRU + optimistic | ● hosts / local server | ◐ single binary, JSON | GPLv3-family (metadata "other") |
| mihomo | ● nameserver-policy + fallback-filter | ● geoip verdict + geosite | ○ | ● (cache-algorithm) | ● hosts; fake-ip-filter for .lan |
◐ single binary, YAML | not cleanly verifiable (repo obfuscated) |
| knot-resolver | ◐ policy modules | ◐ policy + RPZ | ● | ● persistent | ◐ hints / local data | ◐ systemd, Lua config | open source (CZ-NIC) |
| dnsdist | ◐ Lua rules (custom) | ◐ custom policies | ○ (balancer, not validator) | ○ (no cache of its own) | ○ | ○ power tool | GPL (PowerDNS) |
Notes:
- "Geo-split" for AGH/blocky/unbound/Technitium is real but requires feeding a China domain list; chinadns-ng/mihomo additionally offer the IP-verdict path for domains not in any list (query both, adopt CN result only if the answer IP is mainland).
- mosdns v5's
cacheplugin ignores request EDNS0 and strips response EDNS0 (cache plugin) — relevant because AGH in front of it relies on the DO bit for DNSSEC-capable upstreams. - License for mihomo/sing-box/knot-resolver marked conservative: GitHub metadata is "other"/custom or deliberately obfuscated; see §3 caveats.
3. Per-candidate evaluation
3.1 AdGuard Home — advanced upstream routing / built-ins
What it is: Go DNS proxy + adblock + DHCP, LAN DNS front-end (official).
Capabilities relevant here (all from the official configuration page):
- Per-domain upstreams dnsmasq-style:
[/domain/]upstream, wildcards,#= "default upstreams", empty//= unqualified names (upstreams for domains). - List from file
upstream_dns_file— the docs explicitly call out China CDN acceleration via dnsmasq lists, with theserver=/0-100.com/114.114.114.114→[/0-100.com/]114.114.114.114conversion (loading upstreams from file). - Upstream modes:
load_balance,parallel,fastest_addr; plusfallback_dnsused only when primary upstreams fail (config file: dns). - Per-client upstreams (
clients.persistent[].upstreams), rewrites (filtering.rewrites, incl. wildcard),local_ptr_upstreamsfor private PTR, ECS (edns_client_subnetwithuse_customcoarse prefix), optimistic cache (same page). - DNSSEC is DO-bit only:
enable_dnssec"defines whether the proxy should set the DO flag in the upstream requests" — validation must happen upstream (same page). - DoH/DoT/DoQ/DoH3 serving,
bind_hosts/ACL guidance (running securely).
Verdict: Already installed and capable of the geo-split itself. The current setup under-uses it: only a load-balanced CN pair + fallback, no per-domain routing and no validating upstream. This is the cheapest "better" state — see §5.
3.2 mosdns v5 — installed, active as clash nameserver (gateway-side)
What it is: "一个 DNS 转发器" (a DNS forwarder) — plugin-based, sequence-driven (README, GPL-3.0, ~3.7k★).
What it does (verified from the v5 wiki and source tree):
- Servers:
udp_server,tcp_server(TLS→DoT),quic_server,http_server(DoH); upstreams inforwardsupportudp,tcp,tls,https,quic, HTTP/3, concurrent racing (concurrent: npicks the fastest) and socks5 (server plugins, executable plugins). - Geo-split: v5 data providers are
domain_set/ip_set(text list files) plusqname/resp_ipmatchers — verified from the current source tree (plugin/data_provider) — and anipset/nftsetexec plugin to push answer IPs to kernel sets. The old v4-stylegeosite/geoip.datplugins are not present in the v5 tree; the v5 wiki's own matcher page currently states there are no matcher plugins to document (matcher page). Plan on chnlist/gfwlist-style text lists, notgeosite.dat. - Cache: yes, incl. optional lazy cache and disk dump; request EDNS0 is ignored and response EDNS0 stripped by the cache plugin (cache).
- Private names:
hosts(domain-rules style, not OS /etc/hosts syntax),redirect,arbitrary(zone records),reverse_lookup(PTR/HTTP lookup). - Ops: single binary + YAML;
mosdns service installships a systemd/launchd helper (v5 overview); Docker image exists. No web UI of its own.
Verdict: capable splitter/forwarder, but adds no DNSSEC and no filtering layer, and its cache interferes with EDNS0/DO handling. As a back-end splitter behind AGH it is a legitimate choice only if DNSSEC stays off. Given AGH can do the same per-domain split natively (3.1), mosdns's marginal value here is concurrent upstream racing and ipset/nftset integration — neither is needed at this LAN's scale. Either wire it up properly or remove it.
3.3 smartdns
What it is: local DNS server that queries multiple upstreams, speed-tests the answer IPs and returns the fastest; DoH/DoT/DoQ/DoH3; GPL-3.0, ~11.2k★ (README).
Capabilities (from the official config reference and FAQ):
- Multi upstream + "returns the fastest IP", unlike dnsmasq all-servers (README).
- Domain groups:
server ... -group <name>+nameserver /domain/grouprouting, per-bindport flags (-group,-no-speed-check…), client rules/MAC/IP (config options). - Anti-pollution tooling:
bogus-nxdomain(return NXDOMAIN for poisoned IPs),blacklist-ip,whitelist-ip,ignore-ip,ipset/nftsetexport (same page). - ECS: global
edns-client-subnetand per-server-subnet(same page). - Cache:
cache-size,serve-expired(RFC-like stale),prefetch-domain, persistent cache file (same page). - Private names:
address,cname,local-domain,dnsmasq-lease-file(same page). - DNSSEC: no validation option appears anywhere in the official config reference or FAQ — its pollution model is blacklist/whitelist + trusted groups + speed selection, not DNSSEC (config options, FAQ). Flagged: verify on the version you deploy before relying on it.
Verdict: the classic China-home "best-IP" resolver; good splitter, no DNSSEC, speed-test model optimizes for latency rather than anti-pollution correctness. Not better than AGH+China-list for this LAN; at most a back-end splitter behind AGH, with the same DNSSEC caveat as mosdns.
3.4 chinadns-ng / chinadns2 / dnsmasq-china-list
chinadns-ng (the requested "china-dns-ng"; actual repo zfl9/chinadns-ng,
AGPL-3.0, Zig, ~1.4k★) is the maintained rewrite of shadowsocks/ChinaDNS:
- Two upstream groups (china / trust) +
chnlist.txt/gfwlist.txtdomain lists; domains are taggedchn/gfw/none(README). tag:nonenames are queried on both upstreams and the china answer is adopted only if its A/AAAA is a mainland IP (tested against achnrouteipset/nftset loaded into the kernel); verdict caching avoids re-testing and leaks (README: 原理/verdict-cache).- Cache with stale + pre-refresh + optional persistence; DoT upstream
(wolfssl build);
hosts+dns-rr-iplocal records;nftsetadd for chn/gfw IPs; no DoH by design and no DNSSEC — the author's stated philosophy is "one job, done well" (README). - Resource footprint is tiny: ~140 KB baseline, ~2.4 MB with 73k+ chnlist + 5.7k gfwlist entries (README).
chinadns2 (zfl9/chinadns2) is the older C predecessor; effectively
superseded by chinadns-ng for new deployments (README not directly fetched —
treat as legacy line).
dnsmasq-china-list (felixonmars, ~6.1k★) is data, not a daemon:
accelerated-domains.china.conf, bogus-nxdomain.china.conf,
apple.china.conf, google.china.conf, with generators for dnsmasq,
unbound, bind, dnscrypt-proxy
(README, WTFPL per repo).
Verdict: chinadns-ng is the strongest pure splitter for GFW networks (IP
verdict beats pure list-based routing for unknown domains), but it cannot
validate DNSSEC and brings no filtering UI. As AGH's backend it duplicates what
AGH's per-domain upstreams already do; its IP-test mode requires shipping
chnroute ipset/nftset into the host. dnsmasq-china-list is best used as the
data feed for the AGH upstream_dns_file recommendation in §5.
3.5 unbound
What it is: validating, recursive, caching resolver from NLnet Labs (docs).
- Real DNSSEC validation by default (trust anchor, chain of trust); the official home-network guide turns it on explicitly (home resolver guide).
- Full recursion → does not hard-depend on any upstream or proxy; serve-expired (RFC 8767), aggressive NSEC, DoH/DoT/DoQ serving and TLS upstreams, forward-zone/stub-zone/authority-zone, RPZ filtering, views, ECS module (docs index).
- Private names:
local-zone/local-datafor*.windy.lan-style names (unbound.conf(5)). - No built-in China split: you assemble it with forward-zones fed by
dnsmasq-china-list (
make unboundgenerator) +bogus-nxdomain; no UI, no per-client grouping comparable to AGH.
Verdict: the gold standard for the validation half. Best used as (a) the validating upstream behind AGH for the foreign/trusted path, or (b) a full recursive resolver replacing the forwarders if you accept losing AGH-style filtering/UI on top — keep AGH in front for that. System-package based, heavier to operate than blocky but battle-tested.
3.6 blocky
What it is: Go DNS proxy + ad-blocker, "fast and lightweight", single static binary, stateless, Apache-2.0, ~6.9k★ (README).
- In-process DNSSEC validation:
dnssec.validatewith DO bit, RRSIG verification, chain-of-trust, NSEC/NSEC3, custom trust anchors, SERVFAIL on bogus (DNSSEC validation docs). - Upstreams:
parallel_best(2 random resolvers, fastest answer),strict,random; per-client/per-subnet upstream groups; UDP/TCP/DoT/DoH/DoQ/DoH3; DNS stamps; bootstrap DNS (upstreams). - Conditional forwarding +
customDNSmapping/rewrite (the AGH-rewrite equivalent), hosts files, per-domain upstream routing (custom DNS / conditional). - ECS:
ecs.useAsClient/ecs.forward(ECS). - Cache with min/max TTL + prefetching; optional Redis cache/state sync between instances; query log to SQLite/Postgres/CSV; Prometheus metrics; REST API (README, config).
- No full web admin UI (metrics/REST/logs only) — an ops trade-off vs AGH's UI.
Verdict: the most attractive new software option for this LAN as a backend
behind AGH: it adds real DNSSEC validation + conditional upstream routing +
ECS with a single binary and YAML. It has no China-IP-verdict split built in —
feed it the China domain list via conditional.mapping/upstream groups, which
is fine at this scale. One caveat: no GUI means AGH stays the human-facing
front, so AGH→blocky is strictly additive.
3.7 Technitium DNS Server
What it is: self-hosted authoritative and recursive DNS server, .NET, web console, GPL-3.0, ~9.5k★ (README).
- DNSSEC validation for recursive resolution, forwarders, and conditional forwarders (RSA/ECDSA/EdDSA, NSEC/NSEC3); can also serve signed zones (README).
- Conditional forwarder zones + bulk conditional forwarding app; blocked-domain lists with regex support and per-client variants; split-horizon/geolocation via DNS Apps; ECS; QNAME minimization (README).
- Serving side: DoH/DoT/DoQ/DoH3 server, built-in DHCP, persistent cache, caching with serve-stale/prefetch, clustering, HTTP/SOCKS5 proxy for DNS (e.g. over Tor) (README).
- Heavier footprint (needs .NET; Docker image available) and a full web console with many features this LAN won't use.
Verdict: capable and genuinely feature-rich (a real AGH alternative in the "everything in one box" sense — filtering, private zones, validation, DHCP), but it's more moving parts than this LAN needs, and its geo-split still requires manual conditional-forwarder lists. Not chosen over the lighter AGH+backend approach.
3.8 sing-box / mihomo built-in DNS as the split resolver (fake-ip)
The "third option": let the proxy engine's DNS own resolution, AGH on top.
sing-box DNS object: multiple server types (local, udp, tcp, tls, https,
http3, quic, fakeip, hosts, dhcp, mdns…), rule-based server selection by
geoip/geosite, LRU cache + optimistic serving, per-query timeout, client_subnet
(ECS), reverse_mapping
(sing-box DNS docs).
mihomo (Clash.Meta lineage; docs at
wiki.metacubex.one):
nameserver-policy (geosite/rule-set/domain keys) routes specific domains to
specific resolvers; fallback + fallback-filter (geoip=CN, geosite=gfw,
ipcidr, domain) adjudicate pollution — a CN resolver's answer is adopted only if
the IP is mainland, otherwise the overseas fallback's answer is used;
fake-ip/redir-host enhanced mode, fake-ip-filter with e.g. '*.lan' to
keep local names on real-IP; per-DNS-server ECS; cache-algorithm
(mihomo DNS config).
Assessment for THIS LAN:
- The pollution adjudication is strong (geoip-verdict fallback, geosite lists), and mihomo already runs on the gateway — so "clash DNS as splitter" is tempting.
- But the DNS service is coupled to the proxy: foreign resolution rides the
proxy path, so when OpenClash/subscription is down, fake-ip mapping and
foreign lookups break (partial fail-open only if
direct-nameserver/fallback are carefully set). The LAN requirement says must not hard-depend on the proxy (fail-open). - fake-ip adds an indirection layer for anything in front of it (AGH on top resolves client IPs against fake-ip ranges; leaks/loops need careful rules).
- Neither engine validates DNSSEC (no RRSIG verification).
- sing-box repo license shows "other" in GitHub metadata (not cleanly
verifiable); mihomo's repo currently carries deliberately obfuscated content
("Void Terminal" parody) — treat
wiki.metacubex.oneas the authoritative docs and expect the GitHub surface to change.
Verdict: keep clash/mihomo DNS exactly where it is (proxy-side, TPROXY/fake-ip), do not make it the LAN resolver of record. If you ever want its IP-verdict quality outside the proxy, chinadns-ng gives the same idea with zero proxy dependency.
3.9 knot-resolver / dnsdist — power-resolver options
knot-resolver (CZ-NIC): minimal caching validating resolver, modular/Lua, full DNSSEC validation, forwarding over TLS, query policies, RPZ, views/ACLs, DNS64, persistent cache, serve-stale, even XDP fast-path (docs). As powerful as unbound but with more configuration surface (Lua); overkill for a one-operator home LAN, though it would do the validating-resolver role well.
dnsdist (PowerDNS): "highly DNS-, DoS- and abuse-aware loadbalancer" — routes traffic to backend servers, Lua/YAML config, runtime console, metrics (overview). It is a balancer, not a validator/cache — it fronts other resolvers. Overkill; only relevant if you wanted a multi-backend DNS LB, which this LAN does not.
3.10 Emerging / also-considered options
- AdGuard Home + dnsmasq-china-list — covered in §3.1/§5; this is the "emerging best practice" for China CDN splits on AGH and is officially documented.
- pi-hole — adblock/dashboard equivalent of AGH but no per-domain upstream routing worth choosing it over AGH here (not deeply verified for this write-up; AGH already satisfies the role).
- dnscrypt-proxy — encrypted forwarder with stamp support; a transport option, not a splitter/validator (not deeply verified for this write-up).
- coredns — plugin-based; geo-split is DIY via plugins; no DNSSEC validation by default (not deeply verified for this write-up).
3.11 Other popular options (survey supplement, 2026-08-12)
Follow-up survey of additional popular solutions not covered above, evaluated
against this LAN's constraints (fail-open, keep DNS on .36, DNSSEC goal).
None of these change the §4/§5 recommendation.
Encrypted-forwarder micro-tools (AGH downstream options, not replacements):
- dnscrypt-proxy — the classic OpenWrt encrypted forwarder with China-list support and DNS-stamp routing. No in-process DNSSEC validation and no filtering UI; overlaps with AGH's own DoH upstream layer, so its marginal value here is low.
- dnsproxy (AdGuardTeam) — lightweight DoH/DoT/DoQ forwarder/server. Functionally a subset of AGH's upstream layer; only useful if forwarding logic is deliberately split out of AGH.
- Stubby — dnsmasq→stubby→DoT (privacy-community pattern). Pure forwarding, no split/filter/validation; adopting it alone would be a downgrade from AGH.
Managed / cloud DNS (zero-ops, not self-hosted):
- NextDNS / ControlD / AdGuard DNS / Cloudflare — hosted filtering, logs,
per-device policies. This LAN already self-hosts AGH + a private
adg.chans.xyzfallback, so a cloud service would be a downgrade in control (data leaves the LAN). Only realistic use: add one as an extra foreign-path upstream inside AGH'supstream_dns_file.
Heavier all-in-one resolvers:
- PowerDNS Recursor — real DNSSEC validation + Lua policy, authoritative and recursive in one. Capable but overlaps unbound; over-provisioned here.
- BIND9 — classic authoritative/recursive; can validate DNSSEC and, more interestingly, serve as a local authoritative zone that would close the private-PTR gap. As a LAN resolver it lacks AGH's filtering/UI and is heavier to operate; a small dnsmasq authoritative zone is a lighter way to achieve the PTR goal (still deferred until a local authoritative source exists).
- hickory-dns / trust-dns (Rust) — emerging recursive resolver, DNSSEC friendly, smaller ecosystem/ops track record than unbound/blocky; not yet worth switching for this LAN.
Popular stack patterns (structure, not new software):
- Pi-hole + unbound — the most common global self-hosted combo (filtering front-end + validating backend). AGH already occupies the Pi-hole role here (and does more), so the equivalent is AGH + unbound/ blocky — exactly the report's recommendation #2.
- dnsmasq + china-list + smartdns (classic OpenWrt trio) — routes the
China list on the gateway itself. Equivalent to co-locating DNS with the
proxy host (
.1), which violates the fail-open requirement; not recommended for this LAN.
Verdict: the survey adds no better candidate. dnsproxy/dnscrypt-proxy duplicate AGH's upstream layer, cloud DNS is a control downgrade, and the only genuinely new capability (a local authoritative source for PTR) is better served by a small dnsmasq authoritative zone than by replacing the resolver.
4. Architecture recommendation for this LAN
4.1 Preferred architecture (change is config-only)
clients (DHCP option 6 = .36)
│ UDP/TCP :53
▼
AGH .36 (filtering, rewrites, query log, per-client upstreams)
│ upstream_dns_file:
│ [/cn-domain-list/] dns.alidns.com doh.pub ← CN CDN domains (China list)
│ default: https://adg.chans.xyz/dns-query … ← trusted/foreign path
└→ validating resolver (unbound OR blocky) for the foreign path (optional phase 2)
- Front = AGH stays the single LAN DNS box (filtering/rewrites/UI/query log are its strong suit and are already operating).
- Split = AGH per-domain upstreams fed by a converted dnsmasq-china-list; no new daemon. This is the documented AGH pattern (upstreams from file).
- Validation = add a validating resolver behind AGH for the trusted path
(blocky simplest; unbound most battle-tested) and re-run the known-bad-signature
check that failed before; then flip
enable_dnssec.
4.2 Why not the alternatives as front-ends
- smartdns / chinadns-ng as the LAN resolver: they are pure splitters — no adblock layer, no query log/UI, no DNSSEC. Replacing AGH with either is a capability downgrade; behind AGH they duplicate AGH's built-in split while adding a daemon and losing validation. Only chinadns-ng's IP-verdict mode is genuinely beyond AGH, and it needs kernel ipset/nftset plumbing.
- mosdns as the AGH backend: viable splitter, but no validation and its cache strips EDNS0/DO (cache plugin), which fights the DNSSEC goal. It is already idle on the box — configure it deliberately or remove it.
- mihomo/sing-box DNS as the resolver of record: fail-closed + proxy-coupled
- no validation. Keep as proxy-side concern (§3.8).
- knot-resolver / dnsdist / Technitium: capable but over-provisioned; Technitium is the only one that would replace AGH wholesale, and there's no benefit worth the migration here.
4.3 Deployment location
- Keep DNS on
dns.windy.lan(.36). It is already the DHCP-advertised resolver; it is a separate VM from the proxy host; DNS therefore stays independent of OpenClash state (fail-open), which is an explicit requirement. - Do not move it to
gfw(.1): the gateway is where OpenClash injects TPROXY/fake-ip/DNS-hijack rules; co-locating LAN DNS there couples DNS to the proxy and its restart/update lifecycle. - A standalone resolver VM adds nothing: both current VMs already sit on the same PVE hypervisor (lan-overview.md §Positioning facts), so a hypervisor outage takes out either placement equally; a second physical host for HA is out of scope for a home LAN.
- If you ever run a validating resolver + AGH on
.36, verify outbound from.36to the foreign upstreams is not re-hijacked by OpenClash (loop check already mandated in the AGH review).
4.4 Fail-open, DNSSEC, private names — by candidate
| Concern | How the recommended stack behaves |
|---|---|
| Fail-open when proxy/subscription down | AGH forwards directly to DoH upstreams; .36's outbound is not forced through the proxy in normal ops (no TUN policy routing on .36 — dns host facts). With unbound/blocky behind, foreign resolution recurses/validates directly, independent of OpenClash. Avoid mihomo-DNS-as-resolver, which is proxy-coupled. |
| DNSSEC validation | Only unbound, blocky, knot-resolver, Technitium validate in-process. AGH sets DO only; mosdns/smartdns/chinadns-ng/mihomo/sing-box do not. Plan: validate behind AGH, or accept "validating public upstream" (confirm with dig +dnssec/known-bad test). |
| Private names / rewrites | AGH rewrites (already in use for hass.windy.lan) + local_ptr_upstreams once a local PTR source exists. blocky: customDNS mapping/rewrite + hosts. unbound: local-zone. All adequate. |
| Query log / visibility | AGH is the best at this of everything evaluated (14-day anonymized log already configured). |
5. What would make the current AGH + mosdns setup genuinely better
Concrete, in increasing effort:
- Implement the China-list geo-split in AGH itself
(
upstream_dns_file+ convertedaccelerated-domains.china.conf, default upstreams = trusted foreign path,fallback_dnskept). Official AGH docs describe exactly this pattern (loading upstreams from file); list source: dnsmasq-china-list. Wire a refresh path (cron/ansible) so the list stays current. Re-test CDN resolution and the DNSSEC known-bad domain after. - Put a validating resolver on the trusted path (unbound or blocky), re-run
the known-bad-signature check, then enable AGH DNSSEC. Without this, AGH's
enable_dnssecis only a DO-flag — the exact reason it is currently off (AGH DNSSEC semantics, host facts). - Either fully configure mosdns (systemd service, sequence, lists) or remove
it. Leaving an idle
127.0.0.1:6052listener documented as "not the active path" is drift. If kept, plan around no-EDNS0 cache + no validation; if removed, drop the listener and its config to reduce surface. - Close the private-PTR gap: once a local authoritative source exists (e.g.
dnsmasq on
gw, or a tiny authoritative zone), point AGHlocal_ptr_upstreamsat it as the AGH review recommends (AGH review); don't set it before that source exists (dns host facts). - Optional: ECS for CDN geo-accuracy — AGH
edns_client_subnet.use_customwith a coarse fixed prefix (or blockyecs.forward) if measurements show a benefit; note many CN resolvers ignore ECS (AGH ECS).
If the DNS engineering budget is one afternoon, do #1 + #3. If the goal is "real DNSSEC or nothing", do #1 + #2 + #3. Replacing the stack is only justified if you want to abandon AGH's UI/filtering entirely — nothing evaluated here beats it on that axis for this LAN.
Caveats / not verified
- Live behavior not tested: all capability claims are from primary docs
reviewed 2026-08-12; DNSSEC behavior of
dns.alidns.com/doh.pub/theadg.chans.xyzpath and mosdns's actual version on.36need on-boxdig +dnssecverification (per adguard-home-health). - smartdns DNSSEC: the official config reference lists no DNSSEC option; if a newer version added one, it is not reflected here (config options).
- mosdns geosite/geoip: v5 source tree (fetched 2026-08-12) contains only
domain_set/ip_setdata providers; if ageosite.datplugin exists in a release branch, it is not inmain(plugin/data_provider). - mihomo: the GitHub repo currently shows deliberately obfuscated metadata (see §3.8); capabilities cited from wiki.metacubex.one. sing-box/knot-resolver/dnsdist license identifiers via GitHub metadata are "other"/custom — treat the specific SPDX ids with caution.
- chinadns2 README was not retrieved (404 on the raw URL); treated as the legacy predecessor of chinadns-ng and not evaluated in depth.
- Obsidian/personal notes were not consulted; this is upstream-docs-only.
Related docs
- lan-overview.md — full topology (verified 2026-08-06)
- hosts/dns.windy.lan.md — AGH host facts
- hosts/gfw.windy.lan.md — OpenClash facts
- adguard-home-official-review-2026-08.md — prior AGH config review
- runbooks/adguard-home-health.md