Issuing Certificates Before DNS Cutover
Problem Statement
You need www.example.com to serve valid TLS from a new origin at 203.0.113.10, but the certificate authority proves you control that hostname by fetching a file from whatever www.example.com currently resolves to — which is the legacy origin. Issue the certificate the usual way and it certifies a server you are about to switch off; skip issuance until after the DNS change and every visitor in the first minutes gets a browser interstitial. This circular dependency is the single most common reason a well-planned cutover produces a TLS outage, and it has a clean solution. This page sits under TLS & Certificate Cutover and covers obtaining and installing a valid certificate on a host that nothing yet resolves to.
When to Use This Approach
- You are moving a hostname to a new origin, new host, or new CDN and TLS terminates somewhere different afterwards.
- The hostname must keep serving through the switch with no certificate warning at any point.
- You control the DNS zone, or can have
_acme-challengeTXT records added on request. - You need to test the new origin’s TLS end to end before any traffic reaches it.
- The certificate must cover several hostnames, including some that do not yet exist publicly.
Step-by-Step Instructions
1. Choose the DNS-01 Challenge
An HTTP-01 challenge asks the authority to fetch a token over HTTP at the hostname being certified, which before cutover is answered by the legacy origin. A DNS-01 challenge instead asks you to publish a TXT record at _acme-challenge.<hostname>, which proves control of the name without involving whichever server currently answers for it. That distinction is the whole reason this works.
# certbot with a DNS plugin — no traffic to the new host is required
certbot certonly --dns-cloudflare \
--dns-cloudflare-credentials /root/.secrets/cf.ini \
-d example.com -d www.example.com -d api.example.com \
--preferred-challenges dns-01
2. Cover Every Hostname in One Request
List each name the new origin will serve, including any that do not resolve publicly yet. Adding a hostname later means a fresh issuance and a fresh deployment, so the cheapest moment to be thorough is now. Build the list from the DNS zone and the crawl inventory rather than from memory — the names that get missed are asset subdomains referenced only in stylesheets and API hosts called only by a mobile client.
# Enumerate candidate hostnames from the zone before requesting anything
dig AXFR @ns1.provider.com example.com | awk '$4 ~ /^(A|AAAA|CNAME)$/ {print $1}' | sort -u
Watch the rate limits while you iterate. Public authorities cap issuance per registered domain over a rolling window, and a cutover rehearsal that re-requests certificates on every attempt can exhaust that allowance at exactly the wrong moment. Use the staging environment for anything experimental, reserve production issuance for the certificate you intend to deploy, and use --dry-run for renewal testing so the exercise costs nothing.
3. Install and Test by IP, Before Any DNS Change
Deploy the certificate and its full chain on the new origin, then exercise the handshake against that host’s address while sending the real hostname as SNI. This tests certificate, chain, private key and cipher configuration end to end against a server that no visitor is reaching yet, so a failure costs nothing but the time to fix it.
# --resolve pins the connection to the new IP while sending the real SNI
curl -sIv --resolve www.example.com:443:203.0.113.10 \
https://www.example.com/ 2>&1 | grep -Ei 'subject:|issuer:|SSL certificate verify|^< HTTP'
4. Prove Renewal Before You Depend On It
A certificate obtained by hand to unblock a cutover expires ninety days later with nobody watching. Configure the renewal path on the new host and force a dry run so you know the credentials, the plugin and the post-renewal reload all work — then confirm the reload actually causes the new certificate to be served, which is a separate thing from the renewal succeeding.
# Exercise the whole renewal path without consuming rate limit
certbot renew --dry-run --dns-cloudflare \
--dns-cloudflare-credentials /root/.secrets/cf.ini
systemctl reload nginx && echo "reload hook works"
Worked Example
The sequence below is a hosting move where the hostname is unchanged and only the origin behind it differs — the case in which the circular dependency bites hardest.
A team is moving www.example.com from a legacy VM to a container platform at 203.0.113.10. Requesting a certificate with the default HTTP-01 flow succeeds — and installs a certificate on the legacy VM, which is not where they need it. They switch to DNS-01 using their provider’s API credentials, issuing one certificate covering example.com, www.example.com and assets.example.com, and install the resulting fullchain.pem on the new platform.
Testing with --resolve against the new IP reveals a second problem before any visitor could hit it: the platform was configured with cert.pem rather than fullchain.pem, so the handshake presented a leaf certificate with no intermediate. Their browsers accepted it — the intermediate was cached from other sites — and curl did not:
$ curl -sIv --resolve www.example.com:443:203.0.113.10 https://www.example.com/
* SSL certificate problem: unable to get local issuer certificate
They repoint the configuration at the full chain, re-test, and get a clean HTTP/2 200. Only then do they lower the TTL per How to Lower DNS TTL Before Domain Migration and schedule the record change. At cutover the handshake simply works, because it has already been working for two days against an origin nobody was using.
Keep the private key on the new host and never move it around casually. Certificate deployment tends to involve copying files between machines under time pressure, which is how keys end up in a shared drive, in a chat message, or committed to a repository. Generate the key where it will be used, transfer only the certificate, and if a key genuinely must move, treat it as a credential — encrypted channel, restrictive permissions on arrival, and a note to rotate it once the migration settles.
Verification
Prove the new origin is TLS-ready while the hostname still points elsewhere.
# 1. Handshake succeeds against the new IP with the real SNI
curl -sI --resolve www.example.com:443:203.0.113.10 https://www.example.com/ | head -1
# 2. At least two certificates are presented (leaf + intermediate)
openssl s_client -connect 203.0.113.10:443 -servername www.example.com \
-showcerts </dev/null 2>/dev/null | grep -c 'BEGIN CERTIFICATE'
# 3. Every intended hostname appears in the SANs
openssl s_client -connect 203.0.113.10:443 -servername www.example.com </dev/null 2>/dev/null \
| openssl x509 -noout -ext subjectAltName
A clean result is an HTTP/2 200 from the first command, a count of two or more from the second, and every hostname from your enumeration present in the third. Run all three again through the public hostname after the record changes.
FAQ
Can I use HTTP-01 if I temporarily point the hostname at the new origin? You can, and it defeats the purpose: pointing the hostname at a server with no valid certificate is exactly the outage you are trying to avoid, even briefly. The one variation that works is issuing against a different hostname that already points at the new origin and using a certificate covering both — but that requires the certificate to be issued for a name you can already validate, which brings you back to needing DNS-01 for the name you actually care about.
Does the _acme-challenge TXT record need to stay in place?
No. It is consumed during validation and can be removed afterwards, and most DNS plugins clean it up automatically. What does need to persist is the credential the plugin uses, because renewal repeats the same challenge — so the token is transient and the API access is not. Store that credential as a secret with an owner rather than in a personal account.
What if DNS is managed by another team and API access is not available?
Ask for a delegated _acme-challenge CNAME pointing at a zone you do control. This is the standard workaround: the other team makes one static change, and every subsequent validation and renewal happens in your zone without further involvement from them. It is far easier to get approved than ongoing API credentials, and it removes a recurring dependency from your renewal path.
How early should the certificate be issued? Early enough to test properly, which usually means several days before the window rather than the night before. Certificates are valid from issuance, so there is no cost to obtaining one early beyond starting the expiry clock — and the value of having the new origin’s TLS proven for days before cutover is that any problem surfaces while it is still cheap. Just confirm the expiry leaves comfortable room after the migration.
Related
- TLS & Certificate Cutover
- Validating Certificate Chains Across CDN and Origin
- How to Lower DNS TTL Before Domain Migration
← Back to TLS & Certificate Cutover