46f32c2df2
Deploy to Production / deploy (push) Failing after 7s
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>
279 lines
8.6 KiB
Markdown
279 lines
8.6 KiB
Markdown
# 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://<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 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 @<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
|
||
```
|