6 Commits

Author SHA1 Message Date
d4a5ce9f82 coredns: script-based NOTIFY to ns1.he.net on every prep
Hurricane Electric requires asymmetric transfer config:
  - AXFR pull from 216.218.133.2 (slave.dns.he.net / ns4.he.net)
  - NOTIFY destination 216.218.130.2 (ns1.he.net)

CoreDNS's transfer plugin uses a single bidirectional `to` list for
both, which is fine in principle but breaks in a confirmed bug: any
`to` with more than one specific IPv4 silently kills server-block
listener startup (no error, zones load, but :53 never binds).
Reproduced on 1.11.3 + 1.12.2 even with a minimal fresh `docker run`.

Workaround:
  - Corefile keeps `transfer { to * }` (open AXFR; firewall does the
    real source-IP filtering on TCP/53)
  - scripts/notify-he.py crafts and sends NOTIFY messages directly to
    216.218.130.2 (only). Pure-stdlib Python — no dependencies.
  - Makefile `prep` target runs notify-he.py after prepare-zones.sh
    so every zone-bump fires NOTIFY automatically.

Verified end-to-end: HE acks NOTIFY (rcode=0) for the 10 zones it
hosts as secondaries; remaining 81 return REFUSED (rcode=5) because
HE doesn't have them configured yet. Note: HE's free slave service
acks NOTIFY but only actually re-pulls AXFR on its hourly poll cycle
(observed behavior — they're poll-based by design). NOTIFY still
useful long-term in case HE changes that behavior; harmless either way.
2026-05-18 16:57:54 -06:00
5afdb05667 zones: replace all A 100.79.95.190 with CNAME rpm-bullet.mer.idahomuellers.net
27 records across 15 zones converted from direct A records pointing at
the Tailscale endpoint (100.79.95.190) to CNAMEs pointing at the
Tailscale-named alias. Now if the underlying Tailscale node's IP
changes, only the rpm-bullet record needs updating instead of
chasing 27 zones.

Affected zones (all *.l labels + a handful of dev / dev.mary names):
  acrazy.org      copper-springs.online   demostar.io      flonhoney.com
  homestar.ink    kg7q.cc                 malloys.us       ourjob.site
  qubeseptic.com  ryanmalloy.com          septic.report    sidejob.pro
  supported.systems  warehack.ing         zmesh.systems

No CNAME collisions: none of the converted names had other records
(MX/TXT/SRV/CAA/AAAA) at the same exact name. _acme-challenge.<sub>.l
records sit at distinct subdomains and continue to resolve independently
(verified: TXT lookups for known _acme-challenge.l.* names still return
the original values).

Also fixed prepare-zones.sh: added `|| true` after the serial-detection
grep so a zero-match (first run of a new day) doesn't trip `set -e`
and abort the whole prep.
2026-05-17 03:29:34 -06:00
87eaa27c4c coredns: auto-bump SOA serial (NN counter) on every make prep
Previously: `SERIAL=$(date +%Y%m%d)01` — same-day re-runs produced the
same serial. HE polled, saw no change, never pulled the update.

Now: scan zones-prepared/ for the highest `YYYYMMDDNN` matching today's
date and increment the NN counter. First run of the day starts at NN=01.
Caps at NN=99 with a clear error message (set SERIAL manually if you
genuinely need >99 changes per day).

`SERIAL=<value> make prep` still overrides the auto-detection, useful
for forcing a specific serial during recovery or for testing.

Verified end-to-end on dell01: prep bumped 2026051601 → 2026051602,
CoreDNS auto-reload picked it up within 30s, all queried zones serve
the new serial. HE will pull on its next refresh poll (SOA refresh
= 3600s, so worst case 1 hour).
2026-05-16 16:25:53 -06:00
1ab88a25f7 coredns: hidden-primary architecture with AXFR for HE secondaries
Goal: serve the public DNS face via Hurricane Electric's free
secondary-DNS service (dns.he.net), with CoreDNS on dell01 acting as
the hidden primary. We edit zones here; HE pulls them via AXFR.

Changes:
- scripts/prepare-zones.sh:
  * SOA mname: ns1.vultr.com -> ns1.he.net (so the apex SOA reflects
    HE as the primary in published RDATA)
  * Strip ns?.vultr.com NS records from each zone and inject the five
    HE nameservers (ns1..ns5.he.net) as the authoritative NS set
- Corefile (shared `common` snippet):
  * Add `transfer { to * }` to authorize AXFR. Tried specific IPs +
    `*` mixed on the same line but CoreDNS silently fails to bind
    server blocks with that syntax; bare `to *` is the only form that
    actually starts the listeners. Trade-off: NOTIFY targeting is lost
    (HE polls per SOA refresh=3600s instead of being pushed). For DNS
    data this is fine since each record is publicly queryable anyway.

Verified AXFR end-to-end: `dig @dell01 -p 5353 acrazy.org AXFR +tcp`
returns 41 records with the new HE NS set and HE-rooted SOA.

Still needed (operator action):
- Firewall NAT for TCP/53 -> 172.16.1.15:5353 (so HE can connect in)
- Add each of the 91 zones at dns.he.net as Secondary DNS pointing
  at 154.27.180.210
- Update each domain's registrar NS records from Vultr -> HE
2026-05-16 15:49:42 -06:00
066ba1892a coredns: DoT (:853) + DoH (:443) listeners with self-signed cert
- New Corefile snippet (common) shared across plain DNS / DoT / DoH so
  zone-loading + forward + cache stay DRY across all three transports
- scripts/generate-certs.sh: openssl-only self-signed RSA cert with SANs
  for localhost / 127.0.0.1 / ::1 / coredns / dns.local. Idempotent —
  skips regeneration if cert is valid >24h ahead; FORCE=1 to rotate.
- Key chmod is 0644 so the CoreDNS container's nonroot user can read it
  via the bind mount. Acceptable for local dev; production should mount
  real certs with proper UID/GID.
- DOT_PORT=8853, DOH_PORT=8443 (avoids Caddy already-on-443 collision)
- Makefile: `make certs`, `make test-tls`
- All three transports verified end-to-end (dig +tls, dig +https,
  curl with raw RFC 8484 wire format)
2026-05-14 01:12:25 -06:00
10867ee319 coredns: docker compose stack with Vultr zone import
- Auto plugin loads zones-prepared/*.zone (regex zone-name extraction)
- scripts/prepare-zones.sh transforms raw Vultr exports:
  * synthesizes SOA (omitted by Vultr; CoreDNS requires it)
  * prepends @ to leading-TAB apex lines to disambiguate owner inheritance
  * dot-terminates NS/MX/CNAME rdata so $ORIGIN doesn't double-suffix
- DNS_PORT defaults to 1053 (5353=avahi, 53=libvirt dnsmasq on this host)
- Forwards non-authoritative queries to 1.1.1.1/1.0.0.1/9.9.9.9
- Makefile targets: prep, up, down, reload, test, logs
- 91 zones loaded
2026-05-12 01:51:09 -06:00