DNS moved to Cloudflare (executed) — the Dynadot saga ends
Why: This morning's literal-A-on-Dynadot fix still didn't hold — Dynadot's ns1 served the dead old IP for 3+ hours after the IP change and could not be forced to reload by any API call. The only durable fix was to stop trusting Dynadot's nameservers, so we executed the long-planned Cloudflare migration.
All three domains' nameservers were switched from Dynadot to Cloudflare. This makes the June-2 Cloudflare runbook DONE and supersedes this morning's Dynadot-A self-heal entry. Damien's accelerating IP-change cadence (2yr → 1yr → 6mo → 3mo → 1mo → ~2wk — an ISP nudging hobbyists off residential hosting) made "recover in minutes, hands-off" a hard requirement, not a nicety.
1. The cutover
- Nameservers flipped via the Dynadot API (
command=set_ns) forskyhouse.dev,botaa.org,room101.com→luciane.ns.cloudflare.com+remy.ns.cloudflare.com. DNSSEC was OFF (no DS records) so the flip was clean and reversible. - Pre-flight check that paid off: querying the assigned Cloudflare NS directly (
dig @luciane.ns.cloudflare.com) before flipping caught that botaa.org's zone had imported empty — we added its records first instead of black-holing it. - Propagation took ~94 min.
.org/.comhit the registry fast;.devlagged badly and only moved after re-submitting theset_ns— Dynadot dragging its feet one final time. Verified end-to-end: all threedns:OK http:200from outside.
2. Grey-cloud (DNS-only), not proxied
Cloudflare imported every A/CNAME as Proxied (orange cloud) by default, which returned Cloudflare anycast IPs and routed traffic through the CDN. For this media-heavy box that's wrong: the free tier caps proxied uploads at 100 MB (breaks Immich/Pairdrop large files) and forbids proxied video streaming (ToS). We set every record to DNS only (grey cloud) so it behaves exactly like the old direct setup — real origin IP, no limits, no SSL-mode surprises. Plex is unaffected regardless (it uses plex.tv + the :32400 forward, never these domains).
3. room101 email on Cloudflare Email Routing
room101's value is its email, not its content. Moving its NS off Dynadot killed Dynadot's parkmail forwarding, so we rebuilt it on Cloudflare Email Routing (free): MX → route1/2/3.mx.cloudflare.net + Cloudflare SPF + DKIM (cf2024-1._domainkey), destination verified, rules set. Confirmed forwarding works. One cosmetic leftover: the imported _dmarc TXT still sends aggregate reports to parkmail-dmarc@dynadot.com (policy p=none, harmless) — edit or delete whenever.
4. Automation: one notifier, token-free
Self-healing is now Cloudflare's job, not a script's. The intended end state is each apex = a flattened CNAME → cw526dc.glddns.com (grey): the GL.iNet router updates that DDNS name ~30s after an IP change and Cloudflare's anycast follows — no scripts, no API token, no split-brain. (As of this entry the apexes are still the imported static A records; flipping them to the flattened CNAME is the one remaining manual step to make IP changes fully self-heal.)
- New:
/home/plex/bin/dns-monitor.sh(cron*/5) — notify-only, no DNS writes, no token. Telegrams 🌐 on a public-IP change, ✅ once all three domains resolve to the new IP from outside, ⚠️ if not within 15 min. This is the "tell me it changed, then tell me it's resynced" experience. - Retired (Dynadot-era, now obsolete):
ip-watch.sh,dns-watchdog.sh,ip-recovery-verify.sh,dns-push.sh,dynadot-update.py. Left on disk + cron removed; they are now only a rollback aid.lib-pubip.shis reused by the monitor.
5. Rollback
Fully reversible: at Dynadot, set each domain's nameservers back to ns1.dyna-ns.net + ns2.dyna-ns.net (set_ns or the web UI). The Dynadot-hosted zones still exist, and the retired scripts can re-assert literal A records there. Keep that escape hatch until Cloudflare is proven for a week.
Net effect: DNS now lives on Cloudflare's anycast nameservers — no more per-nameserver split-brain, no Dynadot in the resolution path, and an IP change becomes a notification rather than an outage. The accelerating IP churn is now background noise.
← Back to Admin Hub