Sanitized mirror from private repository - 2026-04-05 08:31:50 UTC
This commit is contained in:
150
docs/guides/dns-audit.md
Normal file
150
docs/guides/dns-audit.md
Normal file
@@ -0,0 +1,150 @@
|
||||
# DNS Audit Script
|
||||
|
||||
**Script**: `.gitea/scripts/dns-audit.py`
|
||||
**Workflow**: `.gitea/workflows/dns-audit.yml` (runs daily at 08:00 UTC, or manually)
|
||||
|
||||
Audits DNS consistency across three systems that must stay in sync:
|
||||
1. **DDNS updater containers** (`favonia/cloudflare-ddns`) — the source of truth for which domains exist and their proxy setting
|
||||
2. **NPM proxy hosts** — every DDNS domain should have a corresponding NPM rule
|
||||
3. **Cloudflare DNS records** — proxy settings in CF must match the DDNS config
|
||||
|
||||
---
|
||||
|
||||
## What It Checks
|
||||
|
||||
| Step | What | Pass condition |
|
||||
|------|------|----------------|
|
||||
| 1 | Parse DDNS compose files | Finds all managed domains + proxy flags |
|
||||
| 2 | Query NPM API | Fetches all proxy host domains |
|
||||
| 3 | DNS resolution | Proxied domains resolve to CF IPs; unproxied to direct IPs |
|
||||
| 4 | NPM ↔ DDNS cross-reference | Every DDNS domain has an NPM rule and vice versa |
|
||||
| 5 | Cloudflare audit | CF proxy settings match DDNS config; flags unrecognised records |
|
||||
| 6 | ntfy alert | Sends notification if any check fails (only when `NTFY_URL` is set) |
|
||||
|
||||
---
|
||||
|
||||
## Running Manually
|
||||
|
||||
### From the Gitea UI
|
||||
|
||||
Actions → **DNS Audit & NPM Cross-Reference** → **Run workflow**
|
||||
|
||||
### Locally (dry run — no changes made)
|
||||
|
||||
Run from the repo root:
|
||||
|
||||
```bash
|
||||
cd /home/homelab/organized/repos/homelab
|
||||
|
||||
CF_TOKEN=<token> \
|
||||
NPM_EMAIL=<email> \
|
||||
NPM_PASSWORD="REDACTED_PASSWORD" \
|
||||
python3 .gitea/scripts/dns-audit.py
|
||||
```
|
||||
|
||||
CF_TOKEN is the `CLOUDFLARE_API_TOKEN` value from any of the DDNS compose files.
|
||||
NPM credentials are stored as Gitea secrets — check the Gitea Secrets UI to retrieve them.
|
||||
|
||||
### Without NPM credentials
|
||||
|
||||
The script degrades gracefully — steps 1, 3, and 5 still run fully:
|
||||
|
||||
```bash
|
||||
CF_TOKEN=<token> python3 .gitea/scripts/dns-audit.py
|
||||
```
|
||||
|
||||
This still checks all DNS resolutions and audits all Cloudflare records.
|
||||
The NPM cross-reference (step 4) is skipped and the "DDNS-only" summary count
|
||||
will be inflated (it treats all DDNS domains as unmatched) — ignore it.
|
||||
|
||||
### With auto-fix enabled
|
||||
|
||||
To automatically patch Cloudflare proxy mismatches (sets `proxied` to match DDNS):
|
||||
|
||||
```bash
|
||||
CF_TOKEN=<token> CF_SYNC=true python3 .gitea/scripts/dns-audit.py
|
||||
```
|
||||
|
||||
**This makes live changes to Cloudflare DNS.** Only use it when the DDNS config
|
||||
is correct and Cloudflare has drifted out of sync.
|
||||
|
||||
---
|
||||
|
||||
## Environment Variables
|
||||
|
||||
| Variable | Required | Description |
|
||||
|----------|----------|-------------|
|
||||
| `CF_TOKEN` | Yes | Cloudflare API token (same one used by DDNS containers) |
|
||||
| `NPM_EMAIL` | No | NPM admin email — enables step 4 cross-reference |
|
||||
| `NPM_PASSWORD` | No | NPM admin password |
|
||||
| `CF_SYNC` | No | Set to `true` to auto-patch CF proxy mismatches |
|
||||
| `NTFY_URL` | No | ntfy endpoint for failure alerts |
|
||||
|
||||
---
|
||||
|
||||
## DDNS Files Scanned
|
||||
|
||||
The script reads these compose files to build its domain list:
|
||||
|
||||
| File | Host | Services |
|
||||
|------|------|----------|
|
||||
| `hosts/synology/atlantis/dynamicdnsupdater.yaml` | Atlantis | vish.gg proxied, thevish.io proxied + unproxied |
|
||||
| `hosts/physical/concord-nuc/dyndns_updater.yaml` | concord-nuc | api.vish.gg unproxied |
|
||||
| `hosts/physical/guava/portainer_yaml/dynamic_dns.yaml` | Guava | crista.love |
|
||||
| `hosts/vms/seattle/ddns-updater.yaml` | Seattle | st.vish.gg, stoatchat subdomains |
|
||||
|
||||
---
|
||||
|
||||
## Output Guide
|
||||
|
||||
```
|
||||
OK domain.vish.gg [CF] -> 104.21.x.x # Proxied domain resolving to Cloudflare ✓
|
||||
OK api.vish.gg [direct] -> YOUR_WAN_IP # Unproxied resolving to direct IP ✓
|
||||
WARN domain: expected CF IP, got 1.2.3.4 # Proxied in DDNS but resolving directly ✗
|
||||
ERR domain: NXDOMAIN # Record missing entirely ✗
|
||||
MISMATCH domain: CF=true DDNS=false # Proxy flag out of sync — fix with CF_SYNC=true
|
||||
INFO *.vish.gg [unmanaged-ok] [direct] # Known manually-managed record, ignored
|
||||
NEW? sub.vish.gg [proxied] ip=1.2.3.4 # In CF but not in any DDNS config — investigate
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Known Exceptions
|
||||
|
||||
### Domains in DDNS with no NPM rule (`DDNS_ONLY_EXCEPTIONS`)
|
||||
|
||||
These are legitimately in DDNS but don't need an NPM proxy entry:
|
||||
|
||||
- `mx.vish.gg` — mail server
|
||||
- `turn.thevish.io` — TURN/STUN server
|
||||
- `www.vish.gg`, `vish.gg`, `www.thevish.io`, `crista.love` — root/www records
|
||||
|
||||
### Cloudflare records not tracked by DDNS (`CF_UNMANAGED_OK`)
|
||||
|
||||
These are in Cloudflare but intentionally absent from DDNS configs:
|
||||
|
||||
- `*.vish.gg`, `*.crista.love`, `*.vps.thevish.io` — wildcard catch-alls
|
||||
|
||||
To add a new exception, edit the `DDNS_ONLY_EXCEPTIONS` or `CF_UNMANAGED_OK` sets at the top of `.gitea/scripts/dns-audit.py`.
|
||||
|
||||
---
|
||||
|
||||
## Last Run (2026-03-07)
|
||||
|
||||
```
|
||||
57 domains across 4 DDNS files
|
||||
32 NPM proxy hosts, 32 unique domains
|
||||
57/57 DNS checks: all OK
|
||||
✓ All NPM domains covered by DDNS
|
||||
✓ All DDNS domains have an NPM proxy rule
|
||||
Cloudflare: 60 A records audited, 0 proxy mismatches
|
||||
✅ All 57 DDNS domains OK, CF and DDNS are in sync
|
||||
```
|
||||
|
||||
### Notes from this session
|
||||
|
||||
- `mx.vish.gg` was moved from proxied → unproxied DDNS service (CF proxy breaks
|
||||
Matrix federation on port 8448). The CF record was patched with `CF_SYNC=true`.
|
||||
- CF cross-reference confirmed working end-to-end in CI (run 441, 2026-02-28):
|
||||
NPM credentials (`NPM_EMAIL` / `NPM_PASSWORD`) are stored as Gitea Actions secrets
|
||||
and are already injected into the `dns-audit.yml` workflow — no further setup needed.
|
||||
Reference in New Issue
Block a user