Dr J’s Binding Protocol — Document 18

DNS Migration & Cutover

Zero-downtime DNS migration from external hosting (Flywheel, GoDaddy, Squarespace, etc.) to prod-hetzner. Pre-deployment preparation, TTL strategy, cutover execution, and post-cutover verification. Every task labeled AI-managed or human-required.

← Back to Build Hub

Table of Contents

  1. The 48-Hour Problem
  2. Migration Architecture
  3. Pre-Deployment Checklist
  4. Cutover Execution
  5. Post-Cutover Verification
  6. AI vs. Human Task Matrix
  7. TTL Strategy — The 5-Minute Cutover
  8. SSL Certificate Timing
  9. Email Continuity
  10. Flywheel Transition Bridge
  11. Rollback Procedure
  12. Golden Rules

1. The 48-Hour Problem

When you change a domain’s DNS records, the old IP address is cached by thousands of DNS resolvers worldwide. Each resolver holds the old record until its TTL (Time To Live) expires. If the TTL was 86400 (24 hours) when you made the change, some visitors will hit the old server for up to 24 hours. If the TTL was 3600 (1 hour), they’ll see mixed content for up to 1 hour.

This means some visitors see the old WordPress site on Flywheel while others see the new site on prod-hetzner. Both sites are live, both are serving pages, and there is no way to force every DNS resolver on the internet to update simultaneously.

The worst-case scenario is a surprise cutover with a high TTL. If you change the A record without lowering the TTL first, you’re committed to 24–48 hours of mixed content. Customers see different versions of the site depending on their ISP, location, and browser cache. Forms submit to the wrong server. Checkout might hit the old Stripe keys. This is a customer experience disaster.
The solution is preparation. Lower the TTL days before the cutover. When the old TTL has expired across all resolvers, the actual A record change propagates in minutes, not hours. The difference between a 48-hour transition and a 5-minute transition is entirely about when you lower the TTL.

2. Migration Architecture

Every migration from external hosting to prod-hetzner follows this pattern. The old host and new host run simultaneously during the transition window.

BEFORE (current state) Visitors → DNS → Flywheel IP → WordPress DURING (TTL propagation window) Some visitors → DNS (cached) → Flywheel IP → WordPress Other visitors → DNS (fresh) → 46.225.85.236 → New site AFTER (propagation complete) All visitors → DNS → 46.225.85.236 → New site on prod-hetzner

What Controls the Transition Speed

FactorYou Control It?Impact
TTL on current A record Yes — lower it days before cutover The single biggest factor. Low TTL = fast propagation
Resolver cache behavior No — each ISP’s resolver follows its own rules Some resolvers honor TTL exactly, others cache longer. 300s TTL means ~5–15 min in practice
Browser DNS cache No — browsers cache DNS 1–3 minutes independently Minor. Hard refresh or incognito clears it
CDN / proxy cache Partial — purge if you use Cloudflare, etc. If the old site used a CDN, its edge nodes cache the old content

3. Pre-Deployment Checklist

Everything in this section happens before the DNS change. The goal is to have the new site fully operational on prod-hetzner, verified, and waiting — so the cutover is just a DNS record change, not a build-and-pray.

Phase 1: Pre-Deployment — 3–7 Days Before Cutover
#TaskOwnerDetails
1 Lower TTL on current DNS Human At the current DNS provider (Flywheel, registrar, or Cloudflare), set the A record TTL to 300 (5 minutes). Do this 3–7 days before cutover so the old high TTL has time to expire everywhere. §7 TTL Strategy
2 Verify domain exists in dpanel Human Log into cp.dominionport.com. Confirm thehighroadmanufacturing.com is listed under the correct account. If not, add it. dpanel auto-creates DNS zone, MX, SPF, DKIM, DMARC records.
3 Deploy site code to prod-hetzner AI Run ship.sh from DevHub. This packages, uploads, deploys via devhub-receive, runs migrations (creates both thr_* and ths_* tables), and runs post-deploy.php (pushes product data, regenerates JS). Doc 10 §4
4 Install nginx vhost AI + Human AI prepares the config (in deploy/nginx-thehighroad.conf with redirects baked in). Human installs it on prod: cp deploy/nginx-thehighroad.conf /etc/nginx/sites-available/, then nginx -t && systemctl reload nginx. Register with Guardian.
5 Configure production .env AI + Human AI provides the template (in .env.production). Human places it at shared/.env with real credentials: DB_HOST, DB_USER, DB_PASS, DB_PREFIX=thr_, SITE_PREFIX=ths_, Stripe keys, MAIL_METHOD=sendmail.
6 Run post-deploy verification AI Run php api/post-deploy.php on prod. Confirms both table tiers exist, pushes product data if needed, regenerates products-data.js. Must report “PASSED.”
7 Test new site via direct IP Human Before DNS changes, verify the new site works on prod-hetzner: curl -H "Host: thehighroadmanufacturing.com" https://46.225.85.236/ -k. Or add 46.225.85.236 thehighroadmanufacturing.com to your local /etc/hosts file to preview in a browser.
8 Prepare Flywheel transition page Human On Flywheel, install a simple redirect or “We’ve moved” page so visitors who still hit the old server during propagation get redirected to the new site. §10 Flywheel Bridge
9 Archive old site Human Export WordPress database + files from Flywheel. Store the backup. This is the rollback safety net. No archive = no cutover.
10 Verify TTL has propagated low Human Check dig thehighroadmanufacturing.com A and confirm the TTL shown is 300 (or close). If the TTL is still high, wait longer before proceeding to cutover. Use dnschecker.org for global verification.
Do not proceed to cutover until every pre-deployment task is complete. The cutover itself is a 2-minute DNS change. All the complexity is in the preparation. If anything fails during pre-deployment, fix it before touching DNS. There is no time pressure during pre-deployment.

4. Cutover Execution

With pre-deployment complete and TTL verified low, the cutover is a single DNS change. This phase takes 2–5 minutes of human work, followed by 5–15 minutes of propagation.

Phase 2: Cutover — The Switch
#TaskOwnerDetails
11 Change DNS A record Human Option A (recommended): At the domain registrar, change nameservers to ns1.host.dominionport.com and ns2.host.dominionport.com. dpanel then controls all DNS (A, MX, SPF, DKIM, DMARC, CAA — all auto-configured).

Option B: Keep external DNS. Update A record to 46.225.85.236. Update www CNAME to thehighroadmanufacturing.com. Manually configure MX, SPF, DKIM records for email.
12 Provision SSL certificate Human Once DNS resolves to prod-hetzner, issue Let’s Encrypt cert via dpanel. Covers thehighroadmanufacturing.com + www + mail. §8 SSL Timing
13 Monitor propagation Human Check dig thehighroadmanufacturing.com A +short — should return 46.225.85.236. Check dnschecker.org for global status. With 300s TTL, expect full propagation within 15 minutes.

5. Post-Cutover Verification

Phase 3: Post-Cutover — First 72 Hours
#TaskOwnerWhenDetails
14 Smoke test suite Human T+5 min Homepage loads, shop shows products, contact form submits, API health check returns 200, SSL padlock shows, no mixed content warnings
15 Verify product data AI T+5 min Hit /api/public-products.php?action=list — should return products. Hit /api/health.php — should return 200 with version. If products missing, run post-deploy.php again.
16 Test WordPress redirects AI T+10 min Verify old WordPress URLs return 301 to new pages: curl -I https://thehighroadmanufacturing.com/products/ should redirect to /shop.html. Test /product/some-old-slug/, /manufacturing/, /wp-admin/.
17 Test email sending Human T+15 min Submit contact form. Verify email arrives. If using dpanel nameservers, MX/SPF/DKIM are automatic. If using external DNS, verify MX records point to mail.thehighroadmanufacturing.com.
18 Submit sitemap to search engines Human T+30 min Google Search Console: submit sitemap.xml. Bing Webmaster Tools: submit sitemap. Optional but speeds up re-indexing.
19 Monitor 404s and error logs AI Day 1–3 Parse /var/log/nginx/thehighroadmanufacturing.com.error.log and access.log for 404 patterns. Add missing redirects to nginx config. Common misses: pagination URLs, attachment pages, random query strings.
20 Decommission Flywheel Human Day 7–30 After 7 days of stable operation with no DNS-related issues, cancel the Flywheel hosting plan. Keep the WordPress backup archive for 90 days minimum.

6. AI vs. Human Task Matrix

This is the definitive reference for what can be delegated to AI (Claude) inside a DevHub container versus what requires a human with browser/SSH access to external services.

What AI Can Manage (Inside DevHub)

TaskHow
Prepare nginx vhost + redirect mapGenerate deploy/nginx-thehighroad.conf with all redirects baked in
Prepare .env.production templateGenerate template with correct variable names, prefixes, comments
Package and deploy site codeRun ship.sh (SSH to prod via devhub-receive)
Run database migrationsIncluded in ship.sh deployment pipeline
Run post-deploy verificationRun php api/post-deploy.php via SSH to prod
Generate products-data.jsPart of post-deploy, or php api/generate-products-js.php
Verify redirects via curlcurl -I commands to test 301s after cutover
Parse error logs for 404sSSH to prod, parse access logs, suggest redirect additions
Generate sitemap.xmlAlready in the codebase, deployed with the site
Prepare Flywheel redirect snippetGenerate the PHP/HTML code for the transition bridge

What Requires a Human

TaskWhy AI Cannot Do This
Log into domain registrarRequires browser + credentials to GoDaddy / Namecheap / etc.
Change DNS records / nameserversRegistrar web UI — no API access from DevHub
Lower TTL on current DNSMust be done at current DNS provider’s control panel
Log into dpanelBrowser access to cp.dominionport.com
Verify domain exists in dpaneldpanel admin UI — no API access from DevHub
Issue SSL certificateTriggered via dpanel after DNS resolves to prod-hetzner
Install nginx config on prodRequires root SSH to prod-hetzner + Guardian registration
Place production .env with real secretsSecrets must never transit through DevHub or be stored in code
Log into FlywheelFlywheel admin panel — browser + credentials
Archive old WordPress siteFlywheel export or manual backup from Flywheel dashboard
Deploy Flywheel redirect/bridge pageFlywheel file manager or SFTP
Submit sitemap to Google Search ConsoleGoogle account + Search Console access
Cancel Flywheel hostingBilling action in Flywheel dashboard
Test email from customer perspectiveRequires sending/receiving real email
Update /etc/hosts for previewLocal machine modification
Rule of thumb: AI handles everything that lives in code, on DevHub, or is accessible via SSH to prod. Humans handle anything that requires a browser login to an external service (registrar, Flywheel, dpanel, Google) or involves real-world secrets and billing.

7. TTL Strategy — The 5-Minute Cutover

This is the most important section of this document. TTL management is the difference between 48 hours of customer confusion and a 5-minute seamless transition.

The Timeline

Day -7: Check Current TTL Human

Run dig thehighroadmanufacturing.com A. Note the TTL value in the answer section. Common defaults: 3600 (1 hour), 14400 (4 hours), 86400 (24 hours).

Day -7 to -3: Lower TTL to 300 Human

At the current DNS provider, change the A record TTL to 300 seconds (5 minutes). Do not change the IP address yet. Keep it pointing to Flywheel. This step only changes how long resolvers cache the record. Wait for the OLD TTL to expire (e.g., if it was 86400, wait 24 hours).

Day -3 to -1: Verify Low TTL Human

Run dig thehighroadmanufacturing.com A again. The TTL in the answer should now show ≤300. Check from multiple locations using dnschecker.org. If any resolver still shows a high TTL, wait longer.

Day -1: Complete All Pre-Deployment AI + Human

All 10 pre-deployment tasks must be complete. New site verified on prod-hetzner. Flywheel bridge page ready. WordPress backup archived. Nothing left to do except flip the switch.

Day 0: Change A Record Human

Change the A record IP from Flywheel to 46.225.85.236. Because TTL is 300s, every resolver worldwide will pick up the new IP within ~5–15 minutes. Issue SSL cert as soon as DNS resolves.

Day 0 + 1 hour: Raise TTL Back Human

Once propagation is confirmed and the site is stable, raise TTL back to 3600 (1 hour) or 86400 (24 hours). Low TTL increases DNS query load and slightly increases latency for first-visit users.

If you already changed the A record without lowering TTL first: The damage is done — you’re waiting for the old TTL to expire. The best mitigation is to set up the Flywheel transition bridge (§10) so visitors who still hit Flywheel get redirected to the new site. Also lower the TTL NOW so any future changes propagate quickly.

8. SSL Certificate Timing

Let’s Encrypt validates domain ownership by hitting http://yourdomain.com/.well-known/acme-challenge/. This means the domain must resolve to prod-hetzner before the cert can be issued. There is a brief window after DNS cutover where the site has no valid SSL cert.

Mitigation Options

OptionHowDowntime
A. Fastest — dpanel auto-cert dpanel monitors new domains and auto-issues certs. Just add the domain and wait for DNS to resolve. 30–120 seconds between DNS propagation and cert issuance
B. Manual — certbot SSH to prod, run certbot certonly --nginx -d thehighroadmanufacturing.com -d www.thehighroadmanufacturing.com immediately after DNS resolves 60–90 seconds
C. Pre-provision — DNS-01 challenge Issue cert BEFORE DNS cutover using DNS TXT record validation instead of HTTP. Requires adding a _acme-challenge TXT record at the current DNS provider Zero — cert exists before cutover
Option C is the gold standard but requires coordination with the current DNS provider. Option A is fine for most migrations — the 30–120 second SSL gap is acceptable because browsers cache certificates from previous sessions and most visitors won’t notice.

9. Email Continuity

If the domain has email (it probably does), DNS migration affects mail delivery. During the propagation window, some mail goes to the old server and some to the new server.

If Using dpanel Nameservers (Option A)

dpanel auto-creates MX records, SPF, DKIM, and DMARC when a domain is added. Email will work as soon as DNS propagates. Helsinki acts as backup MX — any mail that arrives during the transition is queued and delivered when prod is reachable.

If Keeping External DNS (Option B)

You must manually create these DNS records:

# MX records @ MX 10 mail.thehighroadmanufacturing.com. @ MX 20 ns2.host.dominionport.com. # Helsinki backup MX # Mail server A record mail A 46.225.85.236 # SPF @ TXT "v=spf1 mx a ip4:46.225.85.236 ip4:77.42.85.52 ~all" # DKIM (get the key from prod-hetzner) x._domainkey TXT "v=DKIM1; k=rsa; p=..." # DMARC _dmarc TXT "v=DMARC1; p=quarantine; rua=mailto:dmarc@thehighroadmanufacturing.com"

If Old Host (Flywheel) Handled Email

Flywheel is WordPress-only hosting — it does not provide email. Email is likely handled by Google Workspace, Microsoft 365, or another provider. In this case, do not change MX records during migration. Only change the A record. Email continues to work through the existing provider regardless of where the website points.

Verify where email is hosted BEFORE the migration. Run dig thehighroadmanufacturing.com MX +short. If MX points to Google (aspmx.l.google.com) or Microsoft (outlook.com), leave MX alone during the website migration.

10. Flywheel Transition Bridge

During DNS propagation, some visitors will still hit Flywheel. Instead of showing them the old WordPress site (creating confusion), redirect them to the new site. This eliminates the “mixed content” problem even during propagation.

Option A: WordPress Redirect Plugin

Install a simple redirect plugin on the Flywheel WordPress site that sends all traffic to the new domain. Or add this to the WordPress theme’s functions.php:

// Add to functions.php on Flywheel WordPress add_action('template_redirect', function() { $new = 'https://thehighroadmanufacturing.com' . $_SERVER['REQUEST_URI']; wp_redirect($new, 301); exit; });

Option B: .htaccess Redirect

If Flywheel allows .htaccess modifications:

RewriteEngine On RewriteCond %{HTTP_HOST} thehighroadmanufacturing\.com [NC] RewriteRule ^(.*)$ https://thehighroadmanufacturing.com/$1 [R=301,L]
This is the instant fix for mixed content. Even if DNS propagation takes hours, every visitor who hits Flywheel gets immediately redirected to prod-hetzner. The redirect is a 301 (permanent), so browsers and search engines cache it and won’t hit Flywheel again.
Warning: The redirect only works if DNS for the domain still resolves to somewhere. If you point Flywheel’s DNS away before the redirect is active, visitors who cached Flywheel’s IP but can’t reach it will get connection timeouts. Deploy the redirect BEFORE changing DNS.

11. Rollback Procedure

If the new site has critical failures after cutover, revert DNS back to Flywheel. With 300s TTL, this takes effect within 5–15 minutes.

Rollback Steps

  1. Remove the Flywheel redirect — Undo the transition bridge so Flywheel serves WordPress again
  2. Change A record back to Flywheel IP — At the DNS provider, revert the A record
  3. Wait 5–15 minutes — TTL is still low, so propagation is fast
  4. Verifydig thehighroadmanufacturing.com A +short returns Flywheel’s IP

When to Rollback

When NOT to Rollback

12. Golden Rules

Lower TTL days before, not during the cutover. The TTL you see right now is the TTL resolvers cached when they last looked up the record. Lowering it only affects future lookups. If the current TTL is 86400 (24 hours), resolvers that just cached it won’t check again for 24 hours regardless of what you change it to.
The new site must be fully verified before DNS changes. Every page loads, every API responds, product data is populated, email sends. The cutover should be boring — just a DNS record change with nothing left to debug.
Deploy the Flywheel redirect before changing DNS. This eliminates the mixed-content problem during propagation. Visitors who hit Flywheel get 301’d to prod-hetzner. Visitors who hit prod-hetzner directly get the new site. Either way, everyone sees the new site.
SSL has a brief gap — plan for it. Let’s Encrypt needs DNS to resolve to prod-hetzner before it can issue a cert. There will be 30–120 seconds without a valid cert. Use DNS-01 challenge to pre-provision the cert if zero-gap is required.
Verify where email is hosted independently of the website. Changing the A record does not affect MX records. But changing nameservers does. If email is on Google Workspace or Microsoft 365, those MX records must be recreated at the new DNS provider.
Keep the old host active for 7–30 days after cutover. It serves as a safety net. If something goes catastrophically wrong, you can point DNS back and be live again in 5 minutes (because TTL is still low).
Raise TTL back to normal after the migration is stable. Low TTL increases DNS query volume and adds a few milliseconds of latency for first-visit users. Once the migration is confirmed stable (48–72 hours), set TTL back to 3600 or 86400.