Subdomain Not Resolving: blog.example.com Won't Load

Your apex domain works but blog.example.com gives NXDOMAIN or an SSL error. The fix is almost always a missing DNS row or a domain you forgot to attach at the host. Diagnose it in five buckets.

example.com works. You point blog.example.com to your blog host, wait 10 minutes, and it still gives DNS_PROBE_FINISHED_NXDOMAIN, This site can't be reached, or ERR_NAME_NOT_RESOLVED. The apex domain resolves; the subdomain doesn’t.

Fastest fix: run dig blog.example.com @1.1.1.1 +short. If it returns nothing, you never created the DNS row (Case 1). If it returns an IP but the page errors, DNS works and you forgot to attach the subdomain inside your host’s dashboard (Case 3). Those two account for the large majority of these reports. This is almost never a propagation wait or a browser problem.

This article walks the five buckets in the order they actually happen.

How to identify which case you’re in

Start with one query. Ask a public resolver directly so your laptop’s cache can’t lie to you:

dig blog.example.com +short
dig blog.example.com @1.1.1.1 +short
nslookup blog.example.com 8.8.8.8

Compare the result to expectations:

dig resultWhat it meansGo to
Empty / NXDOMAINNo DNS record exists for the subdomainCase 1
Returns a CNAME that chains to nothingRecord points at a dead targetCase 2
Returns an IP, but the page errors (ERR_SSL_PROTOCOL_ERROR, 404, “not found”)DNS works; host doesn’t recognize the subdomainCase 3
Returns the wrong IPAn old or wildcard record is shadowing itCase 4
Right IP from @1.1.1.1 but not your ISP resolverPropagation / negative-cache lagCase 5

Case 1: No DNS record exists for the subdomain

You added example.com (the apex) but never created a row for blog. DNS does not auto-create subdomains.

How to spot it: dig blog.example.com +short returns nothing. The DNS provider’s UI shows no row for blog (or blog.example.com, depending on display style).

Fix: at your authoritative DNS provider (find it with dig NS example.com +short — this is the host whose nameservers actually answer, which may differ from your registrar), add either an A or a CNAME row:

  • For static hosts (Vercel, Netlify, Cloudflare Pages, GitHub Pages): a CNAME, e.g. CNAME blog -> your-site.netlify.app. — use the exact target the host shows in its custom-domain panel.
  • For a server IP: A blog -> 203.0.113.42.
  • Apex (@) cannot be a CNAME, but subdomains can — use CNAME whenever the host gives you a hostname rather than an IP. See A vs CNAME confusion.

Case 2: Record exists but points at a wrong / dead target

dig returns a CNAME, but that CNAME chains to nothing, or to an IP that no longer hosts anything.

How to spot it:

dig blog.example.com +trace
# Watch the chain. If it ends with "no servers could be reached"
# or "NXDOMAIN", the final target died.

Fix: update the CNAME / A to the current target. If you migrated hosts, the old cname.heroku-app.com or similar is dead — replace it with the new host’s value. After a host migration, also delete any AAAA (IPv6) rows the old platform created; some hosts (Render, for one) are IPv4-only and a stale AAAA row sends part of your traffic into the void.

Case 3: DNS resolves but the host doesn’t recognize the subdomain

The classic Vercel / Netlify / Cloudflare Pages footgun, and the single most common cause after Case 1. DNS points correctly at the host, but the host’s project hasn’t added blog.example.com to its domain list, so its edge returns a generic 404, a “Site not found” page, or an SSL handshake error using the wrong certificate.

How to spot it:

curl -vI https://blog.example.com 2>&1 | head -30
# Symptoms:
# - SSL cert is for *.vercel.app instead of your domain
# - HTTP/2 404 with body "The deployment could not be found on Vercel"
# - Netlify "Site not found" / "Not Found" page
# - Cloudflare Error 1000 ("DNS points to prohibited IP") or a 522,
#   which on Pages means you added the CNAME before claiming the
#   domain in the Pages dashboard

Fix: in the host dashboard, add blog.example.com explicitly, then let it provision the certificate:

  • Vercel: Project -> Settings -> Domains -> Add. Note that as of June 2026 Vercel hands each project a unique CNAME target like d1d4fc829fe7bc7c.vercel-dns-017.com. (the legacy cname.vercel-dns.com. still works, but the dashboard shows the per-project value). Run vercel domains inspect example.com to print the exact records for your project.
  • Cloudflare Pages: Pages project -> Custom domains -> Set up. You must add the domain here first; pointing a CNAME at your-project.pages.dev. without claiming it in the dashboard returns a 522.
  • Netlify / Render / Fly: add the custom domain in the project, then click Verify.

This is a two-sided handshake: the DNS row at your provider and the domain attached at the host. Skip either side and it breaks. Add the domain at the host before the certificate can be issued — the host validates ownership via the DNS you just set, so DNS has to be live first.

Case 4: Wildcard or stale record shadowing the subdomain

A wildcard *.example.com CNAME -> some-old-host matches blog.example.com when no more specific record exists. Or you have two conflicting rows for blog (e.g. A + CNAME, which DNS forbids; or two A rows with different IPs).

How to spot it:

dig blog.example.com +short
# Returns an unexpected IP that matches another project of yours

Then check the DNS panel for a * row, a blog row created by an old teammate, or a blog row from a forgotten platform integration.

Fix: an explicit blog row always wins over *, so adding the correct row fixes it. Delete duplicates; keep exactly one row per record type for blog. See Wildcard DNS not matching subdomain.

Case 5: It is actually just propagation lag

Less common than people assume. If the blog row was just added and you had previously queried it while it did not exist, your resolver cached the NXDOMAIN with its own negative TTL (often the zone’s SOA minimum, commonly 5-60 minutes), so it keeps saying NXDOMAIN until that expires.

How to spot it: it works from dig @1.1.1.1 and @8.8.8.8 but not from your ISP’s resolver, or vice versa. whatsmydns.net shows green checks in some regions and X in others.

Fix: wait out the negative TTL, and flush your local cache:

# macOS
sudo dscacheutil -flushcache; sudo killall -HUP mDNSResponder

# Linux (systemd-resolved)
sudo resolvectl flush-caches

# Windows
ipconfig /flushdns

Then hard-refresh in a new incognito window. See DNS propagation confusion.

Shortest fix path

In hit-rate order:

  1. dig NS example.com +short — find the authoritative DNS provider. Add the subdomain there, not at the registrar, if those differ.
  2. Add the subdomain in your host dashboard too — Vercel, Netlify, Cloudflare Pages, Render, and Fly all require it. This is the step people skip.
  3. Wait a few minutes, then dig blog.example.com @1.1.1.1 +short and confirm you see the host’s hostname or IP.
  4. Check SSL provisioning in the host dashboard — usually 1-5 minutes after DNS validates, via Let’s Encrypt.
  5. If still failing, look for a wildcard or duplicate row shadowing the subdomain.

Reference: subdomain values per host

Values verified against vendor docs as of June 2026. Always copy the exact target your own dashboard shows — several hosts now mint per-project values.

HostDNS record at providerAction in host dashboard
VercelCNAME blog -> <unique>.vercel-dns-017.com. (or legacy cname.vercel-dns.com.)Project -> Settings -> Domains -> Add blog.example.com
NetlifyCNAME blog -> your-site.netlify.app.Site -> Domain management -> Add a domain
Cloudflare PagesCNAME blog -> your-project.pages.dev.Pages -> Custom domains -> Set up (add domain first)
Firebase HostingA to the two IPs shown in the Add Custom Domain wizardHosting -> Add custom domain
GitHub PagesCNAME blog -> username.github.io.Repo Settings -> Pages -> Custom domain
RenderCNAME blog -> your-service.onrender.com. (remove any AAAA)Service -> Settings -> Custom Domains -> Verify

CNAME values are case-insensitive but must not carry a leading https:// or a trailing /. The trailing dot makes the name fully qualified; most DNS UIs add it for you. On GitHub Pages, note that the repo’s CNAME file (uppercase, one domain only) must also survive your build — many static-site generators overwrite it, which silently breaks the custom domain on the next deploy.

How to confirm it’s fixed

  1. dig blog.example.com @1.1.1.1 +short returns the host’s hostname or IP (not empty, not the wrong IP).
  2. curl -sI https://blog.example.com | head -1 returns HTTP/2 200 (or your intended redirect), not a 404 / 522 / 1000.
  3. The TLS certificate matches your domain: echo | openssl s_client -connect blog.example.com:443 -servername blog.example.com 2>/dev/null | openssl x509 -noout -subject shows CN = blog.example.com (or a wildcard for your zone), not *.vercel.app or similar.
  4. In your host dashboard, the domain shows a green “Valid configuration” / “Active” state with SSL issued.

Prevention

  • Use a CNAME, not an A, for any subdomain pointing at a managed host. When the host rotates IPs (which they do, silently, for capacity), CNAME-followers keep working.
  • Don’t deploy a wildcard CNAME *.example.com unless you actually need it. Wildcards make new subdomains “just work” but also catch typos and shadow explicit rows.
  • Test new subdomains from a phone or @1.1.1.1 immediately. Your laptop’s DNS cache lies.
  • Document which host owns which subdomain in a team doc: blog -> Ghost, app -> Vercel, status -> a status provider. Much faster to debug six months later.
  • Keep TTL on subdomain CNAMEs around 3600 in steady state — cache-friendly, but switchable within an hour.

FAQ

Q: I added the CNAME 5 minutes ago, why doesn’t it resolve yet? A: New records reach public resolvers in seconds. But if you queried the subdomain before it existed, your resolver cached an NXDOMAIN with its own negative TTL (often 5-60 minutes). Wait it out, or query a fresh resolver: dig blog.example.com @1.0.0.1 +short.

Q: I get a Vercel/Netlify “Site not found” or a Cloudflare 522 page on the subdomain. A: DNS works (you reached the host’s edge) but the project hasn’t claimed this hostname. Add blog.example.com in the project’s domain settings. On Cloudflare Pages specifically, a 522 means you added the CNAME before claiming the domain under Custom domains.

Q: Does the subdomain need its own SSL certificate? A: Yes, but every modern host provisions it automatically via Let’s Encrypt within minutes of DNS being valid. If SSL is stuck after an hour, check for a blocking CAA record on the zone, then see custom domain SSL delay.

Q: Can I CNAME the apex (example.com) the same way I CNAME a subdomain? A: No. RFC 1034 forbids CNAME at the zone apex because it would conflict with the SOA / NS records. Use A records, or your DNS provider’s “CNAME flattening” / “ALIAS” / “ANAME” feature if they offer one (Cloudflare and DNSimple do).

Q: My subdomain works but redirects me to the apex domain. A: Either the host has a “force root domain” redirect setting, or your CMS / framework is sending Location: https://example.com server-side. Check with curl -I https://blog.example.com — a 301 to the apex means it’s a redirect, not a DNS issue.

Q: Vercel/GitHub says my DNS is wrong but dig looks right. A: The host validates against the exact target it expects. Vercel now issues per-project CNAME values, so a generic cname.vercel-dns.com. may not match what the dashboard wants — run vercel domains inspect example.com and copy that value. GitHub’s “DNS check unsuccessful” most often means the CNAME points at the wrong username.github.io or the repo’s uppercase CNAME file got overwritten by your build.

Tags: #Troubleshooting #DNS #Debug #Subdomain