Luigit
repositories / bugabinga.net

bugabinga.net

personal infrastructure for bugabinga!

owned by admin

docs/dns-migration.md

Raw
Rendered preview

DNS and domain migration

Goal

Move authoritative DNS away from Mail-in-a-Box while keeping current mail, calendar, contacts, and public services working.

Use wildcard DNS for relay-hosted services instead of periodically enumerating subdomains through the Mail-in-a-Box API.

Domain registration and authoritative DNS are independent migrations. Complete and verify DNS before transferring the domain registrar.

Current state

  • GoDaddy registers bugabinga.net.
  • Mail-in-a-Box at box.bugabinga.net is authoritative through the in-bailiwick ns1.box.bugabinga.net and ns2.box.bugabinga.net nameservers.
  • Both nameserver glue records resolve to the DigitalOcean VPS.
  • Mail-in-a-Box serves mail, calendars, contacts, and DNS.
  • The apex MX points to box.bugabinga.net.
  • DNSSEC and DANE are active.
  • A klops Quadlet rewrites an explicit list of A and AAAA records every five minutes, although all records receive the relay's stable primary addresses.

Target shape

registrar
    |
    +-- delegates bugabinga.net to external authoritative DNS
                                      |
                                      +-- explicit mail records -> mail server
                                      |
                                      +-- apex and wildcard -> Hetzner relay
                                                                    |
                                                                    +-- klops

The baseline records are:

@       A       <relay-primary-ipv4>
@       AAAA    <relay-primary-ipv6>
*       A       <relay-primary-ipv4>
*       AAAA    <relay-primary-ipv6>

box     A       <current-mail-ipv4>
@       MX 10   box.bugabinga.net.

Preserve all additional Mail-in-a-Box records, including SPF, DKIM, DMARC, MTA-STS, TLSA, SRV, autoconfiguration, verification, and calendar/contact records. Explicit names override the wildcard.

The wildcard remains DNS-only. Caddy and the relay remain default-deny and only serve explicitly configured hosts and ports.

Provider decision

Cloudflare DNS

Choose Cloudflare when preserving DNSSEC and DANE is required.

  • Free authoritative DNS.
  • DNSSEC signing and TLSA support.
  • Zone-scoped API tokens.
  • OpenTofu provider support.
  • Web records may optionally use the Cloudflare proxy.
  • Mail, SSH, Luci SSH, and the wildcard remain DNS-only.

Cloudflare becomes part of the critical DNS trust chain.

Hetzner DNS

Choose Hetzner when one infrastructure provider and the smallest operational surface are more important than DNSSEC.

  • Free authoritative DNS in the existing Hetzner project system.
  • Project-scoped API token and current hcloud OpenTofu resources.
  • Supports the required ordinary DNS record types.
  • Does not currently sign primary zones with DNSSEC.

Choosing Hetzner disables authenticated DANE for inbound mail. MTA-STS, SPF, DKIM, and DMARC remain available. Re-evaluate Hetzner DNSSEC support before execution.

Phase 0: optional interim simplification

Before migrating providers, determine whether Mail-in-a-Box accepts wildcard custom A and AAAA records through its supported UI or API.

If supported:

  1. Add wildcard A and AAAA records pointing to the relay.
  2. Preserve explicit Mail-in-a-Box host records.
  3. Verify unknown names resolve to the relay and mail names still resolve to the DigitalOcean VPS.
  4. Remove the enumerated five-minute DDNS updater.

Do not modify Mail-in-a-Box-generated records or zone files behind its supported interfaces.

Phase 1: inventory and freeze

  1. Export the complete authoritative zone through Mail-in-a-Box. AXFR is currently unavailable, so use its authenticated API, administration interface, backup, or zone files.
  2. Record registrar nameservers, glue, DS records, TTLs, and domain locks.
  3. Record expected answers for apex, mail, service, DKIM, DMARC, MTA-STS, TLSA, SRV, autoconfiguration, and calendar/contact names.
  4. Lower relevant TTLs at least one existing TTL period before cutover.
  5. Keep Mail-in-a-Box authoritative and serving mail throughout this phase.

Phase 2: create the replacement zone

  1. Create bugabinga.net as a primary zone at the selected provider.
  2. Encode static records declaratively in OpenTofu.
  3. Reference the Hetzner primary IPv4 and IPv6 resources directly for the apex and wildcard records.
  4. Enable zone and RRset deletion protection where supported.
  5. Keep the provider API token out of source and state values.
  6. Query every assigned authoritative nameserver directly.
  7. Compare its answers with the recorded current answers.
  8. Confirm mail records still target the current Mail-in-a-Box server.

The replacement zone must be complete before registrar delegation changes.

Phase 3: DNSSEC transition

The current registrar publishes DS records for the Mail-in-a-Box DNS keys. Those DS records must never remain while an unsigned or differently signed zone is authoritative.

  1. Remove the existing DS records at GoDaddy.
  2. Wait at least their full TTL and verify that multiple public resolvers return no DS records.
  3. Change authoritative nameservers only after the parent zone is unsigned.
  4. For Cloudflare, enable DNSSEC after delegation is stable and publish the new Cloudflare DS record through the registrar.
  5. For Hetzner, leave DNSSEC disabled and archive or remove TLSA records whose authenticity depended on DNSSEC.

A stale DS record makes the whole domain bogus to validating resolvers and causes DNS, web, and mail failure.

Phase 4: nameserver cutover

  1. Replace the GoDaddy delegation with all nameservers assigned by the selected provider.
  2. Keep the old and new zones serving identical answers during propagation.
  3. Monitor authoritative answers and DNSSEC validation from independent resolvers for at least 48 hours.
  4. Verify:
    • apex and unknown subdomains resolve to the relay;
    • box and every mail-specific hostname resolve correctly;
    • MX, SPF, DKIM, DMARC, MTA-STS, TLSA when applicable, and SRV answers;
    • inbound and outbound mail;
    • calendar and contact clients;
    • HTTP, HTTPS, Git SSH, Luci SSH, and certificates.
  5. Disable and remove the Mail-in-a-Box DDNS Quadlet after the new delegation is authoritative everywhere.
  6. Retain the old DNS service until the observation period completes.

Rollback is changing delegation back to the still-complete Mail-in-a-Box zone. Coordinate DS records again if Cloudflare DNSSEC has already been enabled.

Phase 5: registrar transfer

Perform this only after the DNS migration is stable.

  1. Create the required contact handle in Hetzner Domain Registration Robot, or prepare Cloudflare Registrar if Cloudflare will also be registrar.
  2. Disable GoDaddy domain and transfer protection.
  3. Obtain the EPP/AuthCode.
  4. Start the .net transfer while preserving the active nameserver delegation.
  5. Confirm transfer requests.
  6. Verify holder data, nameservers, DNSSEC state, expiration, and automatic renewal after completion.
  7. Remove obsolete ns1.box and ns2.box registrar glue only after nothing delegates to them.

Registrar transfer may take up to five working days but must not change active DNS answers.

Later mail migration

Moving Mail-in-a-Box services to Stalwart is a separate project.

It includes SMTP relay exposure, outbound delivery, PTR/rDNS, SPF, DKIM, DMARC, DANE or MTA-STS, data migration, client discovery, calendars, contacts, off-host backup, restore, and rollback.

Do not destroy the DigitalOcean VPS until the Stalwart migration has passed delivery, client, data, and restore acceptance tests.

Later public-site canonicalization

Choose one canonical location for the personal site after the DNS and mail migrations. Remove the redundancy between https://bugabinga.net, https://me.bugabinga.net, and https://site.bugabinga.net/personal/. Preserve old URLs with permanent redirects.

Completion criteria

  • The selected provider is authoritative from independent resolvers.
  • DNSSEC validates with Cloudflare, or is cleanly absent with Hetzner.
  • Wildcard and explicit override behavior is verified.
  • Mail, calendar, contacts, web, Git SSH, and Luci SSH work.
  • The DDNS updater is removed.
  • DNS records are reproducible from committed configuration.
  • Registrar recovery credentials and provider API recovery access exist outside the homelab failure domain.
# DNS and domain migration

## Goal

Move authoritative DNS away from Mail-in-a-Box while keeping current mail,
calendar, contacts, and public services working.

Use wildcard DNS for relay-hosted services instead of periodically enumerating
subdomains through the Mail-in-a-Box API.

Domain registration and authoritative DNS are independent migrations.
Complete and verify DNS before transferring the domain registrar.

## Current state

- GoDaddy registers `bugabinga.net`.
- Mail-in-a-Box at `box.bugabinga.net` is authoritative through the in-bailiwick
  `ns1.box.bugabinga.net` and `ns2.box.bugabinga.net` nameservers.
- Both nameserver glue records resolve to the DigitalOcean VPS.
- Mail-in-a-Box serves mail, calendars, contacts, and DNS.
- The apex MX points to `box.bugabinga.net`.
- DNSSEC and DANE are active.
- A klops Quadlet rewrites an explicit list of A and AAAA records every five
  minutes, although all records receive the relay's stable primary addresses.

## Target shape

```text
registrar
    |
    +-- delegates bugabinga.net to external authoritative DNS
                                      |
                                      +-- explicit mail records -> mail server
                                      |
                                      +-- apex and wildcard -> Hetzner relay
                                                                    |
                                                                    +-- klops
```

The baseline records are:

```dns
@       A       <relay-primary-ipv4>
@       AAAA    <relay-primary-ipv6>
*       A       <relay-primary-ipv4>
*       AAAA    <relay-primary-ipv6>

box     A       <current-mail-ipv4>
@       MX 10   box.bugabinga.net.
```

Preserve all additional Mail-in-a-Box records, including SPF, DKIM, DMARC,
MTA-STS, TLSA, SRV, autoconfiguration, verification, and calendar/contact
records. Explicit names override the wildcard.

The wildcard remains DNS-only. Caddy and the relay remain default-deny and only
serve explicitly configured hosts and ports.

## Provider decision

### Cloudflare DNS

Choose Cloudflare when preserving DNSSEC and DANE is required.

- Free authoritative DNS.
- DNSSEC signing and TLSA support.
- Zone-scoped API tokens.
- OpenTofu provider support.
- Web records may optionally use the Cloudflare proxy.
- Mail, SSH, Luci SSH, and the wildcard remain DNS-only.

Cloudflare becomes part of the critical DNS trust chain.

### Hetzner DNS

Choose Hetzner when one infrastructure provider and the smallest operational
surface are more important than DNSSEC.

- Free authoritative DNS in the existing Hetzner project system.
- Project-scoped API token and current `hcloud` OpenTofu resources.
- Supports the required ordinary DNS record types.
- Does not currently sign primary zones with DNSSEC.

Choosing Hetzner disables authenticated DANE for inbound mail. MTA-STS, SPF,
DKIM, and DMARC remain available. Re-evaluate Hetzner DNSSEC support before
execution.

## Phase 0: optional interim simplification

Before migrating providers, determine whether Mail-in-a-Box accepts wildcard
custom A and AAAA records through its supported UI or API.

If supported:

1. Add wildcard A and AAAA records pointing to the relay.
2. Preserve explicit Mail-in-a-Box host records.
3. Verify unknown names resolve to the relay and mail names still resolve to the
   DigitalOcean VPS.
4. Remove the enumerated five-minute DDNS updater.

Do not modify Mail-in-a-Box-generated records or zone files behind its supported
interfaces.

## Phase 1: inventory and freeze

1. Export the complete authoritative zone through Mail-in-a-Box.
   AXFR is currently unavailable, so use its authenticated API, administration
   interface, backup, or zone files.
2. Record registrar nameservers, glue, DS records, TTLs, and domain locks.
3. Record expected answers for apex, mail, service, DKIM, DMARC, MTA-STS, TLSA,
   SRV, autoconfiguration, and calendar/contact names.
4. Lower relevant TTLs at least one existing TTL period before cutover.
5. Keep Mail-in-a-Box authoritative and serving mail throughout this phase.

## Phase 2: create the replacement zone

1. Create `bugabinga.net` as a primary zone at the selected provider.
2. Encode static records declaratively in OpenTofu.
3. Reference the Hetzner primary IPv4 and IPv6 resources directly for the apex
   and wildcard records.
4. Enable zone and RRset deletion protection where supported.
5. Keep the provider API token out of source and state values.
6. Query every assigned authoritative nameserver directly.
7. Compare its answers with the recorded current answers.
8. Confirm mail records still target the current Mail-in-a-Box server.

The replacement zone must be complete before registrar delegation changes.

## Phase 3: DNSSEC transition

The current registrar publishes DS records for the Mail-in-a-Box DNS keys.
Those DS records must never remain while an unsigned or differently signed zone
is authoritative.

1. Remove the existing DS records at GoDaddy.
2. Wait at least their full TTL and verify that multiple public resolvers return
   no DS records.
3. Change authoritative nameservers only after the parent zone is unsigned.
4. For Cloudflare, enable DNSSEC after delegation is stable and publish the new
   Cloudflare DS record through the registrar.
5. For Hetzner, leave DNSSEC disabled and archive or remove TLSA records whose
   authenticity depended on DNSSEC.

A stale DS record makes the whole domain bogus to validating resolvers and
causes DNS, web, and mail failure.

## Phase 4: nameserver cutover

1. Replace the GoDaddy delegation with all nameservers assigned by the selected
   provider.
2. Keep the old and new zones serving identical answers during propagation.
3. Monitor authoritative answers and DNSSEC validation from independent
   resolvers for at least 48 hours.
4. Verify:
   - apex and unknown subdomains resolve to the relay;
   - `box` and every mail-specific hostname resolve correctly;
   - MX, SPF, DKIM, DMARC, MTA-STS, TLSA when applicable, and SRV answers;
   - inbound and outbound mail;
   - calendar and contact clients;
   - HTTP, HTTPS, Git SSH, Luci SSH, and certificates.
5. Disable and remove the Mail-in-a-Box DDNS Quadlet after the new delegation is
   authoritative everywhere.
6. Retain the old DNS service until the observation period completes.

Rollback is changing delegation back to the still-complete Mail-in-a-Box zone.
Coordinate DS records again if Cloudflare DNSSEC has already been enabled.

## Phase 5: registrar transfer

Perform this only after the DNS migration is stable.

1. Create the required contact handle in Hetzner Domain Registration Robot, or
   prepare Cloudflare Registrar if Cloudflare will also be registrar.
2. Disable GoDaddy domain and transfer protection.
3. Obtain the EPP/AuthCode.
4. Start the `.net` transfer while preserving the active nameserver delegation.
5. Confirm transfer requests.
6. Verify holder data, nameservers, DNSSEC state, expiration, and automatic
   renewal after completion.
7. Remove obsolete `ns1.box` and `ns2.box` registrar glue only after nothing
   delegates to them.

Registrar transfer may take up to five working days but must not change active
DNS answers.

## Later mail migration

Moving Mail-in-a-Box services to Stalwart is a separate project.

It includes SMTP relay exposure, outbound delivery, PTR/rDNS, SPF, DKIM, DMARC,
DANE or MTA-STS, data migration, client discovery, calendars, contacts,
off-host backup, restore, and rollback.

Do not destroy the DigitalOcean VPS until the Stalwart migration has passed
delivery, client, data, and restore acceptance tests.

## Later public-site canonicalization

Choose one canonical location for the personal site after the DNS and mail
migrations. Remove the redundancy between `https://bugabinga.net`,
`https://me.bugabinga.net`, and `https://site.bugabinga.net/personal/`.
Preserve old URLs with permanent redirects.

## Completion criteria

- The selected provider is authoritative from independent resolvers.
- DNSSEC validates with Cloudflare, or is cleanly absent with Hetzner.
- Wildcard and explicit override behavior is verified.
- Mail, calendar, contacts, web, Git SSH, and Luci SSH work.
- The DDNS updater is removed.
- DNS records are reproducible from committed configuration.
- Registrar recovery credentials and provider API recovery access exist outside
  the homelab failure domain.