You added a custom domain on Vercel, Cloudflare Pages, Netlify, or Firebase. The dashboard says “Provisioning SSL certificate”, “Issuing certificate”, or “Pending validation” and hours later (sometimes a day or two) it is still not green. Visiting https://yourdomain.com returns NET::ERR_CERT_AUTHORITY_INVALID or just refuses to connect.
TL;DR (the fix 90% of the time): Run dig +short yourdomain.com @1.1.1.1 and confirm it returns the exact value your host’s dashboard told you to set. If it doesn’t, your DNS is wrong or hasn’t propagated, and no cert will ever issue. If DNS is correct, run dig CAA yourdomain.com +short next; an old CAA record that excludes your host’s CA blocks issuance silently. Fix the record, then click “Refresh”/“Retry” in the host dashboard. Most hosts issue from Let’s Encrypt or Google Trust Services, and the actual signing takes seconds, so a stall is nearly always a validation problem, not a slow CA.
This article runs the checks in the order they actually fail: DNS, then CAA, then the host-specific HTTP-01 / proxy issues.
Which bucket are you in?
Run these three commands first. The result tells you which section to jump to.
| Command | If you see this | Go to |
|---|---|---|
dig +short yourdomain.com @1.1.1.1 | Empty, or an IP/CNAME that does NOT match the dashboard | Cause 1 (DNS) |
dig CAA yourdomain.com +short | A line like 0 issue "digicert.com" and your host isn’t listed | Cause 2 (CAA) |
curl -sI http://yourdomain.com/.well-known/acme-challenge/test | HTTP/.. 301 redirecting to https:// | Cause 3 (forced HTTPS) |
If all three look clean, it’s probably a rate-limit or DNSSEC issue (Causes 4 and 5).
Common causes
Ordered by hit rate.
1. DNS hasn’t propagated, or points to the wrong place
The most common by far. After adding the A / CNAME at your registrar, the old TTL hasn’t expired yet, or the record type/value is wrong: an apex (root) domain can’t be a CNAME but was set to one, or the A record points at a stale IP. The host can’t verify domain ownership, so the CA never gets asked to sign anything.
The host dashboard shows the exact expected values. One change to note as of June 2026: Vercel now hands out project-specific DNS targets (for example an A record IP from an Anycast pool, or a CNAME like xyz.vercel-dns-016.com) instead of one global value. The legacy 76.76.21.21 and cname.vercel-dns.com still resolve and work, but use whatever your project’s Settings → Domains screen shows; copy it character for character.
How to spot it:
dig +short yourdomain.com
dig +short www.yourdomain.com
# Compare each against the exact value in the host dashboard
2. CAA record blocks the host’s CA
The apex has a CAA record restricting who may issue certs (for example only digicert.com), but your host issues from letsencrypt.org or pki.goog (Google Trust Services). The CA reads CAA, sees it isn’t allowed, refuses to issue, and the host sits in Pending forever. There is no useful error in most dashboards, which is why this one wastes the most hours.
Typical trigger: you migrated from an enterprise DNS platform or a previous host and the old CAA records came along.
How to spot it:
dig CAA yourdomain.com +short
# Example output: 0 issue "digicert.com"
# If letsencrypt.org / pki.goog is not in the allow list, that's your problem
3. HTTP-01 challenge blocked by forced HTTPS / WAF
Let’s Encrypt defaults to the HTTP-01 challenge: it places a file at http://yourdomain.com/.well-known/acme-challenge/TOKEN and fetches it over plain HTTP. If you front the site with Cloudflare and have “Always Use HTTPS” on (or the encryption mode set to “Full (strict)”), that plain-HTTP request gets a 301 to HTTPS, but HTTPS isn’t ready yet, so the challenge fails. Cloudflare’s “Automatic HTTPS Rewrites” and aggressive caching of the .well-known/ path cause the same failure.
WAF / firewall rules that block .well-known/ do this too.
How to spot it:
curl -sI http://yourdomain.com/.well-known/acme-challenge/test
# An HTTP 301 -> https location means the redirect is killing the challenge
4. Rate limit or old cert conflict
The domain previously had a cert (including a wildcard *.yourdomain.com) issued elsewhere, or several projects request the same exact hostname set and the requests collide. Vercel and others sometimes surface Failed to issue certificate: too many certificates already issued.
The Let’s Encrypt limits that bite here, as of June 2026:
- 5 duplicate certificates per exact set of hostnames per 7 days (the most common one to hit when you keep re-adding/removing a domain).
- 50 certificates per registered domain per 7 days (the broader cap; harder to hit on a single small site).
Renewals are exempt from these. Note that Let’s Encrypt is shortening default certificate lifetime: a 45-day profile is opt-in from mid-2026, the default classic profile drops to 64 days in early 2027, and to 45 days in 2028. You will see renewals more often, but that does not change these issuance limits.
How to spot it: Open crt.sh and count how many certs were issued for that exact name in the last 7 days.
5. DNSSEC misconfigured at the registrar
DNSSEC is enabled but the DS record never made it to the registry, or the signing chain is broken. Recursive resolvers return SERVFAIL, so the CA’s validation lookup fails just like a human’s would.
How to spot it:
dig yourdomain.com +dnssec
# Look for SERVFAIL; or run a visual check at https://dnsviz.net
Shortest path to fix
Step 1: Check DNS from multiple regions
Don’t trust your local cache. Query several global resolvers:
dig +short yourdomain.com @8.8.8.8 # Google
dig +short yourdomain.com @1.1.1.1 # Cloudflare
dig +short yourdomain.com @9.9.9.9 # Quad9
For a worldwide view use whatsmydns.net, which checks roughly 20 nodes. Every resolver should return the host’s expected IP / CNAME. If only some do, propagation is still in progress: wait for the old TTL to expire (usually 1-4 hours; if the previous TTL was 86400, up to 24 hours).
Host-expected records, quick reference (as of June 2026; always prefer the exact value your dashboard shows):
| Host | Apex (@) | Subdomain (www) |
|---|---|---|
| Vercel | A to the project IP shown (legacy 76.76.21.21 still works) | CNAME to the project value (legacy cname.vercel-dns.com) |
| Cloudflare Pages | CNAME to your-project.pages.dev (CNAME flattening at apex) | CNAME to your-project.pages.dev |
| Netlify | A 75.2.60.5 | CNAME to your-project.netlify.app |
| Firebase Hosting | Two A records (shown in dashboard) | CNAME or A per dashboard |
| GitHub Pages | Four A records: 185.199.108.153, 185.199.109.153, 185.199.110.153, 185.199.111.153 | CNAME to username.github.io |
Step 2: Inspect and fix CAA
dig CAA yourdomain.com +short
If records exist but exclude your host’s CA, add the right ones at your DNS provider. For a host on Let’s Encrypt and/or Google Trust Services:
yourdomain.com. 3600 IN CAA 0 issue "letsencrypt.org"
yourdomain.com. 3600 IN CAA 0 issue "pki.goog"
yourdomain.com. 3600 IN CAA 0 issuewild "letsencrypt.org"
If there are no CAA records at all, any CA may issue and you need to change nothing. CAA is checked at the registered (apex) domain; subdomains inherit it.
Step 3: Stop forced HTTPS from eating the challenge
If Cloudflare proxies your DNS (orange cloud on):
- SSL/TLS → Overview → temporarily set the mode to “Flexible” or “Off” for the validation window only. (New zones may default to “Automatic SSL/TLS”; switch it to a fixed mode while you debug so behavior is predictable.)
- SSL/TLS → Edge Certificates → turn off “Always Use HTTPS” and “Automatic HTTPS Rewrites” until the cert is live.
- Rules → add a rule matching
yourdomain.com/.well-known/acme-challenge/*that sets Cache to Bypass and does not redirect to HTTPS. (Page Rules still work but Cloudflare is steering everyone to the newer Rules → Redirect Rules / Cache Rules, so prefer those if your dashboard offers them.)
The simplest reliable option: turn off Cloudflare’s orange cloud (set the records to “DNS only”) until the host finishes issuing, then re-enable proxied.
For any WAF / firewall, allowlist .well-known/acme-challenge/* so challenge requests skip your security rules.
Step 4: Trigger re-validation in the host dashboard
Once DNS and CAA are correct, the host won’t always retry on its own. Force it:
- Vercel: Project → Settings → Domains → the
...menu next to the domain → Refresh. - Cloudflare Pages: the project → Custom domains → the domain → Retry verification.
- Netlify: Domain management → HTTPS → Verify DNS configuration / Renew certificate.
- Firebase: Hosting → the custom domain → remove and re-add (the cleanest reset).
Watch the dashboard. It should flip from Pending to Active within 1-5 minutes once validation passes.
Step 5: Still stuck? Rate limits and DNSSEC
# Count certs issued for the exact name in the last 7 days (open in a browser)
# https://crt.sh/?q=yourdomain.com
# Check DNSSEC health
dig yourdomain.com +dnssec
# Or a visual report: https://dnsviz.net/d/yourdomain.com/dnssec/
If you hit the duplicate-cert limit, wait out the 7-day window or switch challenge type (some hosts support DNS-01, which sidesteps the HTTP redirect problem entirely). If DNSSEC is broken, disable DNSSEC at the registrar, let the DS record clear from the registry, then re-run validation.
How to confirm it’s fixed
Once the dashboard shows Active, verify the live chain rather than trusting a green checkmark:
# Should print a valid notAfter date and the issuer (Let's Encrypt / Google Trust Services)
curl -vI https://yourdomain.com 2>&1 | grep -Ei "issuer|expire|subject"
# Or inspect the cert directly
echo | openssl s_client -connect yourdomain.com:443 -servername yourdomain.com 2>/dev/null \
| openssl x509 -noout -issuer -subject -dates
A correct result shows your domain in the subject, a known CA as the issuer, and a future notAfter date. Then load https://yourdomain.com in a fresh incognito window (no cached redirect) and confirm there’s no certificate warning.
FAQ
How long should SSL provisioning actually take?
Seconds to a few minutes once DNS validation passes. If you’re past ~15 minutes with correct DNS and no CAA block, something is failing validation, not “still issuing.” Start re-checking from Step 1.
My DNS looks right but it’s still pending. Now what?
Run dig CAA yourdomain.com +short (Cause 2) and the curl redirect check (Cause 3). A silent CAA block or a forced-HTTPS redirect on .well-known/ are the two failures that survive correct DNS. Both produce zero useful error text in the dashboard.
Do I have to wait 48 hours for “DNS propagation”?
Usually no. Propagation is bounded by the old record’s TTL, not a fixed 48 hours. If the previous TTL was 300, changes are global in minutes; the worst case is a previous TTL of 86400 (24 hours). Check progress on whatsmydns.net instead of guessing.
Can I keep Cloudflare’s proxy (orange cloud) on during issuance?
You can, but turn off “Always Use HTTPS” and “Automatic HTTPS Rewrites” and allowlist .well-known/acme-challenge/* first, or the HTTP-01 challenge gets redirected to a not-yet-valid HTTPS endpoint. The lowest-friction path is to set the records to “DNS only” until the cert issues, then re-enable proxied.
It says “too many certificates already issued.” How long until I can retry? That’s a Let’s Encrypt rate limit. The duplicate-certificate limit (5 per exact hostname set per 7 days) clears on a rolling 7-day window from each issuance. Check crt.sh to see the timestamps and wait out the oldest one, or have your host issue from a different CA / use DNS-01.
Prevention
- Before adding any new domain, run
dig CAA yourdomain.comand confirmCAAallows the host’s CA before you touch the dashboard. - Keep all DNS records in one place (your registrar or one dedicated DNS provider). Don’t split half on Cloudflare and half on Route 53.
- Set a short TTL (300-1800s) on critical records so emergency switches don’t take hours to propagate.
- When adding a domain behind Cloudflare, set records to “DNS only” / turn off “Always Use HTTPS” first; re-enable after the cert is live.
- Monitor expiry: schedule the
curl -vI https://yourdomain.com 2>&1 | grep -i expirecheck above and alert at 30 days remaining. (Lifetimes are getting shorter, so verify auto-renewal works rather than assuming a 90-day window.)
Related
Tags: #Hosting #Debug #Troubleshooting