# DNS Migration: IONOS → BunnyDNS Safe, zero-downtime migration of `api-index.org` from IONOS to BunnyDNS, enabling apex CNAME support for the Bunny.net CDN. **Risk profile:** Low if the checklist is followed in order. The domain stays fully operational at every step. IONOS remains the authoritative fallback until you explicitly confirm the migration is complete. --- ## Overview ``` Phase 0 — Audit Inventory every record in IONOS. Nothing changes. Phase 1 — Reduce TTL Lower TTL to 300 s. Wait for old TTL to drain. Phase 2 — Mirror Replicate all records into BunnyDNS. Verify. Phase 3 — Nameservers Change NS at IONOS registrar → Bunny.net servers. Phase 4 — CDN switch Replace A record with CNAME to Bunny.net CDN edge. Phase 5 — Cleanup Confirm everything. IONOS zone stays intact as archive. ``` **Total calendar time:** 2–3 days minimum (TTL drain + propagation windows). You can compress to ~24 h if IONOS allows TTL = 60 s and you monitor closely. --- ## Phase 0 — Audit Existing Records **Do this before touching anything.** Log in to IONOS → Domains & SSL → `api-index.org` → DNS. Export or manually list every record. With no email on the domain the expected records are minimal: | Type | Name | Value | Notes | |------|------|-------|-------| | A | `@` | VPS IP or IONOS parking IP | Migrate this | | A / CNAME | `www` | same IP or alias | Migrate this | | CNAME | `_domainconnect` | IONOS internal | **Do NOT migrate — IONOS-specific** | No MX, SPF, DKIM, or DMARC records exist (no email = no mail records). This makes the migration low-risk: there is nothing here that can cause an hours-long silent failure. The worst case is the website is briefly unreachable, which resolves as soon as you revert the nameservers. **Identify the current TTL** for each record. IONOS default is often 3600 s (1 h). That is the minimum wait time after reducing TTL before the change is globally drained. --- ## Phase 1 — Reduce TTL Change every record's TTL in IONOS to **300 seconds** (5 minutes). IONOS UI path: DNS record → Edit → TTL field. If IONOS does not allow TTL below 3600 on your plan, use 3600 — it just means a longer wait in Phase 3. **After saving the reduced TTLs, wait for the old TTL to fully drain.** If the old TTL was 3600 s (1 h), wait at least 1 hour before proceeding. This ensures no resolver is caching the old TTL value. Verify the reduced TTL is live from an external resolver: ```bash # Should show TTL=300 (or close to it) in the answer section dig api-index.org A +noall +answer dig api-index.org MX +noall +answer ``` Do not proceed to Phase 2 until the TTL shown in `dig` output matches your reduced value. --- ## Phase 2 — Mirror Records into BunnyDNS ### 2a. Create the BunnyDNS zone 1. Log in to Bunny.net → DNS → Add Zone 2. Enter `api-index.org` and confirm 3. Bunny.net assigns two nameservers (e.g. `kiki.bunny.net`, `coco.bunny.net`) — note these for Phase 3 ### 2b. Add every record from Phase 0 Replicate the full record list into BunnyDNS exactly — same name, same value, same type. Use TTL = 300 for all records during migration. **Do not add:** - `_domainconnect` — IONOS-internal, not needed - IONOS parking/redirect entries — not needed **Do add:** - A record `@` → VPS IP - A record (or CNAME) `www` → VPS IP (or `api-index.org`) For the apex A record (`@`), add it pointing to the **Hetzner VPS IP** for now. You will convert it to the CDN CNAME in Phase 4 — not before. ### 2c. Verify the BunnyDNS zone before touching IONOS Use `dig` with BunnyDNS as the explicit resolver to query the zone before nameserver delegation. Replace `kiki.bunny.net` with your assigned nameserver: ```bash # A record — should return VPS IP dig @kiki.bunny.net api-index.org A +short # www dig @kiki.bunny.net www.api-index.org A +short ``` Compare every answer against your Phase 0 audit. **Do not proceed to Phase 3 until all records match.** --- ## Phase 3 — Switch Nameservers at IONOS This is the single step that transfers authority. Once saved, resolvers will gradually start querying BunnyDNS instead of IONOS. IONOS DNS zone remains intact — you are only changing where resolvers are pointed, not deleting anything. ### 3a. Change nameservers in IONOS IONOS UI path: Domains & SSL → `api-index.org` → Nameservers → Use custom nameservers Enter the two nameservers from BunnyDNS (e.g.): ``` kiki.bunny.net coco.bunny.net ``` Save. IONOS will show a warning that custom nameservers override IONOS DNS — confirm. ### 3b. Wait for propagation Propagation is complete when global resolvers return the BunnyDNS IP for your domain. This typically takes 15–60 minutes with TTL=300. It can take up to 48 hours in rare cases (resolvers ignoring low TTLs). Monitor: ```bash # Repeat every few minutes — watch for the IONOS nameservers to disappear dig api-index.org NS +short # Check from multiple global vantage points # https://dnschecker.org/#A/api-index.org — paste in browser, check all green ``` **During propagation:** Some resolvers still use IONOS, some use BunnyDNS. Both zones have identical records pointing to the VPS IP — so the site stays up regardless of which nameserver a resolver hits. ### 3c. Verify after propagation ```bash # NS records should now show Bunny.net nameservers from all resolvers dig api-index.org NS +short # A record resolves to VPS IP dig api-index.org A +short # End-to-end HTTPS curl -sv https://api-index.org/ 2>&1 | grep -E "HTTP|certificate" ``` Do not proceed to Phase 4 until all checks pass. --- ## Phase 4 — Switch Apex Record to CDN CNAME Only do this after Phase 3 is fully confirmed. ### 4a. Run the Bunny.net CDN setup script If not already done, provision the pull zone: ```bash BUNNYNET_API_KEY=your-key \ ORIGIN_URL=https:// \ CUSTOM_HOSTNAME=api-index.org \ SYSLOG_HOST= \ INSTALL_CRON=true \ ./scripts/setup-bunnynet.sh ``` Note the CDN hostname printed at the end (e.g. `apix-registry.b-cdn.net`). ### 4b. Replace the apex A record with a CNAME in BunnyDNS In BunnyDNS → `api-index.org` zone: 1. Delete the `@` A record pointing to the VPS IP 2. Add a `CNAME` record: `@` → `apix-registry.b-cdn.net` (your CDN hostname) BunnyDNS supports CNAME at the apex via automatic flattening — this is why you migrated here. ### 4c. Verify CDN is serving the domain ```bash # A record now resolves to Bunny.net edge IP (not VPS IP) dig api-index.org A +short # HTTPS still works curl -sv https://api-index.org/ 2>&1 | grep HTTP # Second request should be a CDN cache HIT curl -sI "https://api-index.org/services?capability=nlp" | grep -i cache ``` --- ## Phase 5 — Cleanup and Archive **Do not delete the IONOS DNS zone.** Leave it intact as a ready-to-activate fallback for at least 30 days. If something goes wrong after Phase 3, you can revert by changing the nameservers back to IONOS in the registrar — the zone still has all the correct records. After 30 days of stable operation: - IONOS zone can be deleted or left (it costs nothing to keep) - Document the Bunny.net nameservers in `.env` or `docs/` for future reference --- ## Rollback Procedure At any phase before Phase 3 is complete: nothing has changed — no rollback needed. After Phase 3 (nameserver switch): ``` IONOS → Domains → api-index.org → Nameservers → Use IONOS nameservers ``` Propagation back takes 5–60 minutes with TTL=300. The IONOS zone was never modified — it still has all records. After Phase 4 (CNAME switch): 1. In BunnyDNS: delete the CNAME `@`, re-add the A record `@` → VPS IP 2. The CDN is bypassed; traffic flows directly to VPS again --- ## Checklist Summary ``` Phase 0 [ ] Audit and export all records from IONOS (expected: A @ , A/CNAME www, _domainconnect) [ ] Identify current TTL values [ ] Confirm no MX records present (no email on domain) Phase 1 [ ] Reduce all TTLs to 300 s in IONOS [ ] Wait for old TTL to drain (at minimum the old TTL duration) [ ] dig confirms TTL ~300 in answers Phase 2 [ ] BunnyDNS zone created for api-index.org [ ] A record @ and www replicated into BunnyDNS (no MX/TXT to worry about) [ ] Verified via: dig @ api-index.org A and dig @ www.api-index.org A Phase 3 [ ] Nameservers changed at IONOS registrar to BunnyDNS [ ] Propagation monitored until global NS shows Bunny.net [ ] HTTPS end-to-end test passes Phase 4 [ ] CDN pull zone provisioned (setup-bunnynet.sh) [ ] Apex A record replaced with CNAME in BunnyDNS [ ] CDN cache HIT confirmed on second request Phase 5 [ ] IONOS zone archived (do not delete for 30 days) [ ] Bunny.net nameservers documented ```