Files
apix-mvp/docs/dns-migration-ionos-to-bunnynet.md
Carsten Rehfeld 46f32c2df2
Deploy to Production / deploy (push) Failing after 7s
chore: add missing source modules to version control
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>
2026-05-14 15:49:03 +02:00

279 lines
8.6 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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:** 23 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 1560 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://<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:
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 560 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 @<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
```