Vercel’s custom-domain UX is one of the cleanest in the industry, but clean is not the same as trap-free. This walkthrough gives you the exact DNS records (including the per-project CNAME Vercel now hands out), dig + curl verification you can paste, and the five mistakes behind roughly 90% of “my domain won’t go green” support threads. Current as of June 2026.
TL;DR
- Add
yourdomain.com(apex) in Vercel; accept thewwwprompt. - Copy the records the dashboard shows you, do not reuse a record from a blog post — the CNAME is now unique per project.
- Set an A record (
76.76.21.21) for apex and the per-project CNAME forwww, both DNS-only. - Verify with
dig, wait for the green check, confirm SSL withcurl -vI. - Pick one canonical (apex or www); the other gets an automatic 308 redirect.
If certs hang, the cause is almost always a stale record, a Cloudflare orange-cloud proxy, or a CAA record that blocks Let’s Encrypt.
What you need before starting
- A Vercel project already serving at
*.vercel.app. - A domain at a registrar you control (Cloudflare, Porkbun, Namecheap, etc.).
- The ability to edit DNS at that registrar (dashboard or API).
- A decision on canonical host (apex
yourdomain.comorwww.yourdomain.com) made before you add either one.
One business note for indie devs: Vercel’s Hobby plan is free but non-commercial as of June 2026. If your custom domain serves a product, paying clients, or anything that generates revenue, Vercel’s terms require the Pro plan ($20/seat/month). Hobby allows up to 50 custom domains per project, but that does not change the commercial-use rule. See Firebase vs Vercel for a commercial side project if the licensing matters to you — Firebase’s free Spark tier permits commercial use.
Before you change anything
- Lower the TTL on any existing A/CNAME records to 300s 24 hours before the swap, so old answers expire fast.
- Remove A/CNAME records still pointing at a previous host. A leftover record makes DNS round-robin between the live and dead origin.
- Confirm your domain’s DNS is actually managed where you think it is (the #1 split-DNS trap below).
Step by step
1. Add the domain in Vercel
Project → Settings → Domains → type yourdomain.com → Add Domain. When you add an apex domain, Vercel prompts you to also add the www prefix and recommends redirecting one to the other. Accept it.
2. Read the records Vercel shows you (this changed)
This is the part most stale guides get wrong. As of 2026 the dashboard gives every project a unique CNAME, not the generic one:
For apex (yourdomain.com):
Type Name Value TTL
A @ 76.76.21.21 300
For www (www.yourdomain.com):
Type Name Value TTL
CNAME www d1d4fc829fe7bc7c.vercel-dns-017.com. 300
The A value 76.76.21.21 is Vercel’s general-purpose anycast IP and is still correct for apex. The CNAME target is per-project — yours will look like d1d4fc829fe7bc7c.vercel-dns-017.com, not cname.vercel-dns.com. The legacy cname.vercel-dns.com still resolves, but copy the value your own dashboard prints. If you use the Vercel CLI, you can print the exact records anytime:
vercel domains inspect yourdomain.com
Why an A record for apex but CNAME for www? DNS RFC 1034 forbids a CNAME at a zone apex (the apex already needs NS/SOA records), so the apex gets an A record and only the subdomain gets a CNAME.
3. Apply the records at your registrar
Dashboard works for any registrar. If you script Cloudflare, the key is proxied: false:
curl -X POST "https://api.cloudflare.com/client/v4/zones/$ZONE/dns_records" \
-H "Authorization: Bearer $CF_TOKEN" \
-H "Content-Type: application/json" \
--data '{"type":"A","name":"@","content":"76.76.21.21","ttl":300,"proxied":false}'
curl -X POST "https://api.cloudflare.com/client/v4/zones/$ZONE/dns_records" \
-H "Authorization: Bearer $CF_TOKEN" \
-H "Content-Type: application/json" \
--data '{"type":"CNAME","name":"www","content":"d1d4fc829fe7bc7c.vercel-dns-017.com","ttl":300,"proxied":false}'
proxied: false keeps Cloudflare in DNS-only (grey cloud) mode. The orange-cloud proxy intercepts HTTPS, which blocks Vercel from completing Let’s Encrypt’s HTTP-01 challenge and you get “Failed to Generate Cert” / “Invalid Configuration”. Keep it grey at least until SSL is issued.
4. Verify DNS propagated before refreshing in Vercel
dig +short A yourdomain.com @1.1.1.1
# 76.76.21.21
dig +short CNAME www.yourdomain.com @1.1.1.1
# d1d4fc829fe7bc7c.vercel-dns-017.com.
If dig still returns the old host, the TTL has not expired. Wait — do not start deleting and re-adding the domain in Vercel yet.
5. Wait for “Valid Configuration” and confirm SSL
Vercel polls every few minutes and provisions the Let’s Encrypt cert automatically over HTTP-01, usually within minutes once DNS is correct. Confirm the cert subject and issuer:
curl -vI https://yourdomain.com 2>&1 | grep -E 'subject:|issuer:|HTTP'
# subject: CN=yourdomain.com
# issuer: C=US, O=Let's Encrypt, CN=...
# HTTP/2 200
If it sits on “Invalid Configuration” for more than an hour with correct DNS, the usual culprit is a CAA record that does not authorize Let’s Encrypt (see pitfall 5).
6. Confirm the 308 redirect on the non-canonical host
Once both apex and www are added, Vercel creates a 308 redirect from the non-canonical variant to the one you picked. Verify the direction:
curl -sI https://www.yourdomain.com | head -3
# HTTP/2 308
# location: https://yourdomain.com/
7. Point canonical, sitemap, and og:url at the chosen host
In your Astro layout:
<link rel="canonical" href={`https://yourdomain.com${Astro.url.pathname}`} />
Then grep the built output to catch any URL leaking the wrong host:
grep -ROIE 'rel="canonical"|og:url' dist | grep -v 'https://yourdomain.com' | head
# any line = a leak (vercel.app, the www variant, or http)
8. (Optional) Keep the Cloudflare proxy on
If you want the orange cloud for caching/WAF, turn it on only after Vercel has issued SSL. Then in Cloudflare set SSL/TLS mode to “Full (strict)”. Full works but skips origin-cert validation; Flexible causes an infinite redirect loop because Cloudflare talks to the origin over HTTP while Vercel forces HTTPS.
Verification checklist
| Check | Command / where | Expected |
|---|---|---|
| Apex resolves | dig +short A yourdomain.com | 76.76.21.21 |
| www resolves | dig +short CNAME www.yourdomain.com | your *.vercel-dns-017.com target |
| Both DNS-only | Cloudflare DNS tab | grey cloud on both records |
| Cert valid | curl -vI https://yourdomain.com | subject = domain, issuer = Let’s Encrypt |
| Redirect works | curl -sI https://www.yourdomain.com | 308 → canonical host |
| Canonical clean | grep over dist | no non-canonical URLs |
| Both green | Vercel → Domains | green check on apex and www |
The 5 traps behind most stuck domains
- Split DNS. You changed nameservers to your registrar but added the records somewhere else (or vice versa). Vercel sees nothing. Confirm with
dig NS yourdomain.comwhich provider actually answers, and edit records there. - Cloudflare orange cloud during issuance. The proxy intercepts the HTTP-01 challenge → “Failed to Generate Cert”. Set the records DNS-only (grey) until the cert is live.
- Only one of apex/www added. Half your traffic hits a 404 or no redirect. Add both; let Vercel handle the 308.
- Stale long-TTL records. You swapped DNS but old answers are still cached. Lower TTL to 300s before the swap, not after, then wait for the old TTL to expire.
- CAA record blocking Let’s Encrypt. If your zone has a CAA record, it must authorize Let’s Encrypt or issuance fails silently with “Invalid Configuration”. Add or fix it:
Type Name Value
CAA @ 0 issue "letsencrypt.org"
Check existing CAA with dig +short CAA yourdomain.com. No CAA record at all is fine (any CA may issue); a CAA that lists only other CAs is what breaks Vercel.
After launch
- Search Console: run URL Inspection on the new host; it should show “URL is on Google” within 1–2 weeks if the property was already verified.
- Lighthouse: loads over valid HTTPS with no mixed-content warnings.
- Vercel → Domains: green check on both apex and www.
FAQ
- How long does SSL really take? Usually a few minutes once DNS is correct, since Vercel uses Let’s Encrypt’s HTTP-01 challenge. If it is stuck past an hour, re-check the exact CNAME target, that the proxy is off, and your CAA record.
- The dashboard shows a weird CNAME like
d1d4fc...vercel-dns-017.com— is that right? Yes. As of 2026 each project gets a unique CNAME target. Copy what your dashboard shows; the old genericcname.vercel-dns.comstill resolves but is not what Vercel hands you now. - Apex or www as the canonical? Either works in 2026. Pick one and keep
canonical, sitemap, andog:urlconsistent site-wide. Vercel’s docs lean toward redirecting towww, but apex is equally valid. - Can I host the same project on multiple domains? Yes, but choose one canonical and 308 the rest to avoid duplicate-content SEO problems.
- Can I use a custom domain on the free Hobby plan? You can add it, but Hobby is non-commercial only. A revenue-generating site needs Pro ($20/seat). For a free commercial option, Firebase Hosting’s Spark tier allows commercial use.
- Same domain works on Vercel but is “needs setup” on Firebase? Vercel issues the cert straight from the A/CNAME record; Firebase requires a separate TXT ownership step first (why a domain works on Vercel but not Firebase).