docs: onboard AdGuard Home to Ansible; retire check-mx2; migrate plan to Linear
- Add dns.windy.lan to Ansible inventory (adguardhome group/profile) with a read-only healthcheck template, systemd timer, and on-demand report parity with the other active hosts; verified green on the host. - Add synapse.chans.xyz to the AGENTS.md active-host quick map. - Remove plans/; migrate decisions/verification to a Linear vps project doc and file the remaining gaps as W1N-46..49 with blocking edges. - Retire scripts/check-mx2.sh; point mailcow health/update runbooks and the mx2 host file at the Ansible health report. - Trim us2 stub software to verified running services; note dormant dirs. - Normalize repo docs to English; drop the non-existent CONTEXT.md/ADR claim and remove docs/agents/domain.md.
This commit is contained in:
@@ -0,0 +1,164 @@
|
||||
# AdGuard Home official configuration review basis (2026-08)
|
||||
|
||||
This page is the **official source basis and recommendation baseline** used
|
||||
during the on-site review of AdGuard Home (AGH) on `192.168.66.36`. It does not
|
||||
claim to have read that host's configuration and contains no credentials.
|
||||
On-site conclusions must be based on the live `AdGuardHome.yaml`, OpenWrt
|
||||
`dnsmasq`/DHCP, firewall, routing, and actual client leases.
|
||||
|
||||
Official sources (AdGuard only):
|
||||
|
||||
- [Configuration](https://adguard-dns.io/kb/adguard-home/configuration/)
|
||||
- [Setting up AdGuard Home securely](https://adguard-dns.io/kb/adguard-home/running-securely/)
|
||||
- [Getting started](https://adguard-dns.io/kb/adguard-home/getting-started/)
|
||||
- [DHCP](https://adguard-dns.io/kb/adguard-home/dhcp/)
|
||||
- [DNS encryption](https://adguard-dns.io/kb/adguard-home/encryption/)
|
||||
|
||||
## Recommended role split (for the existing OpenWrt gateway)
|
||||
|
||||
Preferred: keep **OpenWrt/dnsmasq as the single DHCP and local-domain
|
||||
authority, with AGH as the LAN DNS filter/forwarder**: DHCP option 6 hands
|
||||
clients `.36`; AGH sets the router's local DNS (usually the gateway LAN IP) as
|
||||
`local_ptr_upstreams` and, where needed, uses domain-specific upstreams to route
|
||||
the LAN search domain / local names back to dnsmasq. Clients are filtered while
|
||||
still keeping DHCP lease names, static hosts, local reverse resolution, and
|
||||
gateway-internal service discovery.
|
||||
|
||||
Rationale: AGH supports dnsmasq-style domain-specific upstreams for internal
|
||||
private name servers; private PTR should be configured in **Private reverse DNS
|
||||
servers** / `local_ptr_upstreams` rather than regular upstreams; when not
|
||||
explicitly configured, it falls back to the OS default resolver, which shifts as
|
||||
host networking changes. [Official config: domain-specific upstreams](https://adguard-dns.io/kb/adguard-home/configuration/#configuring-upstreams);
|
||||
[private rDNS](https://adguard-dns.io/kb/adguard-home/configuration/#private-addresses).
|
||||
|
||||
Do not have OpenWrt dnsmasq and AGH both listen on `:53` at the same LAN IP;
|
||||
port conflicts, or pointing dnsmasq's upstream at AGH while AGH points back at
|
||||
dnsmasq, cause failures/forwarding loops. When AGH runs on a separate `.36`
|
||||
host, the simplest topology is clients → AGH `.36:53` → public/encrypted
|
||||
upstreams, forwarding only local resolution (PTR, LAN domain) → gateway dnsmasq.
|
||||
This is an operational inference based on the official capabilities above and
|
||||
must be validated against the live `ss -lntup`, dnsmasq config, and query path.
|
||||
|
||||
AGH also has built-in DHCP, but it should only be enabled after **disabling the
|
||||
existing gateway DHCP, explicitly migrating leases/reservations and verifying
|
||||
options 3/6**. The official docs describe it as an alternative when the router
|
||||
cannot hand out custom DNS, not as a dual-DHCP setup; the DHCP docs also state
|
||||
leases/static leases are managed by AGH. [Getting started: router DHCP/DNS
|
||||
handout and alternative DHCP](https://adguard-dns.io/kb/adguard-home/getting-started/#router);
|
||||
[DHCP configuration](https://adguard-dns.io/kb/adguard-home/dhcp/).
|
||||
|
||||
## Exposure and access control
|
||||
|
||||
1. `dns.bind_hosts` should bind only loopback and the actual LAN address (here
|
||||
prefer `.36`'s LAN address); do not use `0.0.0.0`/public interfaces for a
|
||||
home recursive resolver. The official docs note full-interface binding
|
||||
exposes DDoS risk; a small isolated network should pick local service
|
||||
interfaces and may add loopback alongside. [Secure deployment: server
|
||||
addresses](https://adguard-dns.io/kb/adguard-home/running-securely/#choosing-server-addresses);
|
||||
[`bind_hosts` definition](https://adguard-dns.io/kb/adguard-home/configuration/#dns).
|
||||
2. In the firewall, allow only managed LAN/VLAN → `.36` TCP/UDP 53; bind the web
|
||||
admin UI to the management network/loopback and avoid WAN forwarding. At the
|
||||
app layer, further restrict with `allowed_clients` to the local subnets; when
|
||||
non-empty, only the CIDR/IP/ClientIDs in it are accepted, and it overrides
|
||||
the effect of `disallowed_clients`. [Official access
|
||||
control](https://adguard-dns.io/kb/adguard-home/configuration/#dns).
|
||||
3. Keep `refuse_any: true` and a non-zero `ratelimit` (default 20 qps), unless
|
||||
on-site evidence shows the service can never be reached from the internet and
|
||||
LAN high-concurrency needs are data-backed; the official docs list both as
|
||||
protection against reflection/DDoS. [Configuration
|
||||
notes](https://adguard-dns.io/kb/adguard-home/configuration/#dns).
|
||||
4. The web UI must have a user with login-failure lockout enabled;
|
||||
`users: []` disables authentication, and `auth_attempts` or `block_auth_min`
|
||||
of 0 disables the corresponding lockout logic. [Web/auth
|
||||
parameters](https://adguard-dns.io/kb/adguard-home/configuration/#users).
|
||||
|
||||
## Upstreams, encryption, and DNSSEC
|
||||
|
||||
- Use two trusted, differently-networked DoH/DoT/DoQ upstreams for normal public
|
||||
resolution; AGH supports these protocols and DNS Stamps. If an upstream
|
||||
URL/hostname needs resolving, `bootstrap_dns` is its initial resolver; do not
|
||||
point bootstrap at a name that requires AGH itself to resolve, and use
|
||||
directly reachable, stable IPs. A `fallback_dns` can be set separately; it is
|
||||
used only when primary upstreams do not respond. [Upstream protocols and
|
||||
bootstrap/fallback](https://adguard-dns.io/kb/adguard-home/configuration/#dns).
|
||||
- If local IPv6's actual egress path is unstable, do not enable
|
||||
`bootstrap_prefer_ipv6`; the official docs note it makes DoH/DoQ/DoT bootstrap
|
||||
prefer IPv6. Decide on-site based on each upstream's IPv4/IPv6 reachability,
|
||||
latency, and failure rate. [Same reference](https://adguard-dns.io/kb/adguard-home/configuration/#dns).
|
||||
- Consider enabling `enable_dnssec`, choosing recursive upstreams that actually
|
||||
handle DNSSEC; but understand precisely: officially AGH sets the DO flag on
|
||||
requests to upstreams; it does not perform recursive validation itself. On
|
||||
site, query a known-bad-signature domain and observe AD/failure responses to
|
||||
confirm upstream validation behavior. [DNSSEC parameter
|
||||
definition](https://adguard-dns.io/kb/adguard-home/configuration/#dns).
|
||||
- Prefer `upstream_mode: load_balance` unless measurement shows `parallel` first
|
||||
answer latency is clearly worth the privacy/traffic cost of querying all
|
||||
upstreams. The former picks by failure rate and average latency weighting; the
|
||||
latter queries all upstreams concurrently; this is an operational judgment
|
||||
based on documented behavior. [Upstream
|
||||
modes](https://adguard-dns.io/kb/adguard-home/configuration/#dns).
|
||||
|
||||
## Cache, ECS, and privacy
|
||||
|
||||
- Keep DNS cache enabled; use `cache_ttl_min`/`cache_ttl_max` overrides
|
||||
cautiously to avoid stale or unnecessarily short TTLs. `cache_optimistic`
|
||||
answers with a 10-second TTL after expiry and attempts refresh — good for
|
||||
low-latency scenarios that tolerate briefly stale results, not to be enabled
|
||||
blindly on internal domains sensitive to immediate changes. [Cache
|
||||
parameters](https://adguard-dns.io/kb/adguard-home/configuration/#dns).
|
||||
- ECS is off by default: when enabled, AGH adds EDNS Client Subnet to upstream
|
||||
requests; if CDN geo-scheduling is truly needed, use `use_custom: true` with a
|
||||
coarse, non-real-client-subnet `custom_ip`, then compare hit rate vs. privacy
|
||||
impact. [ECS parameters](https://adguard-dns.io/kb/adguard-home/configuration/#dns).
|
||||
- Review log retention and who can read it. If device identity is not needed,
|
||||
consider `anonymize_client_ip: true`; this anonymizes client addresses in logs
|
||||
and stats. [Anonymization
|
||||
parameter](https://adguard-dns.io/kb/adguard-home/configuration/#dns).
|
||||
|
||||
## Proxy / OpenClash coexistence
|
||||
|
||||
If OpenClash/transparent proxy redirects DNS, validate hop by hop to ensure:
|
||||
client DNS requests reach AGH uniquely; AGH's outbound traffic to public
|
||||
encrypted upstreams is not hijacked back to AGH; and the router's local dnsmasq
|
||||
PTR/local-domain requests return to dnsmasq. Create explicit proxy/hijack
|
||||
exceptions for `.36` and its upstreams, or explicitly design the proxy to take
|
||||
over AGH's outbound resolution; do not rely on "it seems to resolve" to conclude
|
||||
there is no loop.
|
||||
|
||||
This is not an AGH-official OpenClash instruction (the official docs do not
|
||||
maintain that integration), but an on-site verification requirement derived from
|
||||
AGH's independent listening, upstream forwarding, and local-PTR-split
|
||||
capabilities. The officially supported mechanisms are referenced at
|
||||
[`bind_hosts`/upstreams/PTR](https://adguard-dns.io/kb/adguard-home/configuration/#dns).
|
||||
|
||||
If serving DoH via a reverse proxy, `trusted_proxies` must list only the actual
|
||||
proxy IP/CIDR; AGH will only trust `X-Real-IP`, `X-Forwarded-For`, etc. from
|
||||
those sources. Do not write the whole LAN/WAN for convenience;
|
||||
`http.doh.insecure_enabled` should only be enabled when a reverse proxy really
|
||||
terminates TLS in front. [Proxy and
|
||||
DoH](https://adguard-dns.io/kb/adguard-home/configuration/#dns); [encrypted DNS
|
||||
docs](https://adguard-dns.io/kb/adguard-home/encryption/). For a pure-LAN
|
||||
plaintext-53 service, publishing DoH/DoT/DoQ outward is usually unnecessary.
|
||||
|
||||
## On-site review checklist (read-only)
|
||||
|
||||
1. Record the version, service method, and the full effective configuration
|
||||
(secrets redacted); run the AGH config check. Officially provided via
|
||||
`--check-config`. [Command-line
|
||||
arguments](https://adguard-dns.io/kb/adguard-home/configuration/#command-line-arguments).
|
||||
2. On `.36`, the gateway, and a wired/wireless client, record `ss` listeners,
|
||||
DHCP option 6, default route, `/etc/config/dhcp`, and OpenClash
|
||||
DNS/firewall-redirect rules.
|
||||
3. From a client test: public A/AAAA, ad-rule hits, DHCP hostnames, forward LAN
|
||||
domain, private PTR, DNSSEC bad-signature domain, and the expected failure
|
||||
mode when AGH stops. Then check whether client IPs in AGH query logs are
|
||||
still genuinely identifiable.
|
||||
4. From the AGH host, test each upstream and bootstrap over the actual protocol
|
||||
for IPv4 and IPv6 reachability; compare with transparent proxy on/off to rule
|
||||
out loops and leaks.
|
||||
5. Verify the web UI/DNS ports have no WAN exposure; confirm allowed clients and
|
||||
firewall match actual LAN/VLAN, guest network, and VPN subnets.
|
||||
|
||||
Before changing anything, export the current configuration and DHCP/firewall
|
||||
state; adjust one layer at a time (DHCP handout, AGH listening, upstreams, or
|
||||
DNS hijack) and keep a known-good management and DNS fallback path.
|
||||
@@ -0,0 +1,47 @@
|
||||
# Issue tracker: Linear
|
||||
|
||||
Issues and PRDs for this repo are tracked in Linear, driven entirely through the
|
||||
Linear MCP configured in the current runtime. VPS operation records use the
|
||||
Linear **`vps`** project (team `W1ndy`).
|
||||
|
||||
## Conventions
|
||||
|
||||
- **Create**: `linear_save_issue` (requires `title` + `team`); description as
|
||||
real-newline Markdown.
|
||||
- **Read**: `linear_get_issue <identifier>` (e.g. LIN-123), optionally with
|
||||
`includeRelations`.
|
||||
- **List**: `linear_list_issues`, filtered by `query` / `state` / `assignee` /
|
||||
`team` / `project`.
|
||||
- **Comment**: `linear_save_comment` (pass `issueId` + `body`).
|
||||
- **Labels**: `linear_save_issue` `labels` field (replaces the whole label set).
|
||||
- **Status**: `linear_save_issue` `state` field (type / name / ID).
|
||||
|
||||
Resolve team, project, and cycle names through the Linear MCP rather than
|
||||
hard-coding them.
|
||||
|
||||
## Cross-issue constraint baseline
|
||||
|
||||
The `plans/` directory is retired (removed 2026-08-06). Plans and baselines now
|
||||
live in the vps project document "VPS 运维重构:已确认决策与验收标准". Open work
|
||||
items are tracked as individual issues with dependencies expressed via
|
||||
`blockedBy` / `blocks`. Read that document before adding new tasks.
|
||||
|
||||
## When a skill says "publish to the issue tracker"
|
||||
|
||||
Create a Linear issue with `linear_save_issue` (`project: vps`).
|
||||
|
||||
## When a skill says "fetch the relevant ticket"
|
||||
|
||||
Use `linear_get_issue <identifier>`.
|
||||
|
||||
## Wayfinding operations
|
||||
|
||||
- **Map**: one issue as the map; child tickets link via `parentId`.
|
||||
- **Child ticket**: `linear_save_issue` with `parentId` set to the map; labels
|
||||
`wayfinder:<type>` (research / prototype / grilling / task).
|
||||
- **Blocking**: `linear_save_issue` `blockedBy` / `blocks` (append-only).
|
||||
- **Frontier query**: list the map's open children, excluding those blocked or
|
||||
already assigned; take the first in map order.
|
||||
- **Claim**: `linear_save_issue` `assignee: me`.
|
||||
- **Resolve**: `linear_save_comment` the answer → update `state` → append a
|
||||
pointer under the map's decisions-so-far.
|
||||
@@ -0,0 +1,15 @@
|
||||
# Triage Labels
|
||||
|
||||
The skills speak in terms of five canonical triage roles. This file maps those roles to the actual label strings used in this repo's issue tracker.
|
||||
|
||||
| Label in mattpocock/skills | Label in our tracker | Meaning |
|
||||
| -------------------------- | -------------------- | ---------------------------------------- |
|
||||
| `needs-triage` | `needs-triage` | Maintainer needs to evaluate this issue |
|
||||
| `needs-info` | `needs-info` | Waiting on reporter for more information |
|
||||
| `ready-for-agent` | `ready-for-agent` | Fully specified, ready for an AFK agent |
|
||||
| `ready-for-human` | `ready-for-human` | Requires human implementation |
|
||||
| `wontfix` | `wontfix` | Will not be actioned |
|
||||
|
||||
When a skill mentions a role (e.g. "apply the AFK-ready triage label"), use the corresponding label string from this table.
|
||||
|
||||
Edit the right-hand column to match whatever vocabulary you actually use.
|
||||
Reference in New Issue
Block a user