apix-demo, apix-portal/src, apix-spider/src, apix-registry/src, apix-common/src were never staged. Without them the CI build has no source to compile and the Docker images cannot be produced. Also adds docs/ (infrastructure notes) missed in prior commits. Co-Authored-By: Mira <noreply@anthropic.com>
8.6 KiB
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:
# 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
- Log in to Bunny.net → DNS → Add Zone
- Enter
api-index.organd confirm - 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 (orapi-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:
# 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:
# 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
# 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:
BUNNYNET_API_KEY=your-key \
ORIGIN_URL=https://<vps-ip> \
CUSTOM_HOSTNAME=api-index.org \
SYSLOG_HOST=<vps-ip> \
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:
- Delete the
@A record pointing to the VPS IP - Add a
CNAMErecord:@→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
# 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
.envordocs/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):
- In BunnyDNS: delete the CNAME
@, re-add the A record@→ VPS IP - 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 @<bunny-ns> api-index.org A and dig @<bunny-ns> 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