Dev.to WebDev 🛠 Dev 👁 0 📖 7 min read

Why Your Site Loads on www but Not on the Bare Domain (and How to Fix It)

Someone types your domain without the www and gets an error page, a certificate warning or a browser that spins until it gives up. Type it with www and the site is fine. Or the exact reverse. The cause is almost always

Why Your Site Loads on www but Not on the Bare Domain (and How to Fix It)

Someone types your domain without the www and gets an error page, a certificate warning or a browser that spins until it gives up. Type it with www and the site is fine. Or the exact reverse.

The cause is almost always simple: example.com and www.example.com are two separate names, and each one needs its own DNS record, its own spot on the certificate and its own line in the web server config. Miss any one of those for one name and you get a domain not working without www (or with it). Here's how to find which piece is missing, layer by layer.

Four addresses, one site

Add http and https to the two names and a visitor can reach your site four different ways. All four should end on the same URL, through a single 301 redirect at most.

Diagram of the four ways to reach one site: http://example.com, http://www.example.com and https://www.example.com each send a 301 redirect to https://example.com/, the one canonical URL that answers 200, with a note that each name needs a DNS record, a place on the certificate and a server_name entry

Pick the one you want people to see and treat the other three as doors that redirect to it. The checks below follow the order a browser hits them: DNS, the server, the certificate, then the redirects.

Layer 1: does each name have a record?

Ask for both names directly:

dig +short example.com A
dig +short www.example.com A
dig +short example.com AAAA
dig +short www.example.com AAAA

An empty answer for one name is often the whole problem: the apex got an A record at launch and www never did, or the reverse after a move. If you want the full picture of what dig is telling you, we have a separate guide on reading dig output.

A common healthy setup is an A record on the apex and a CNAME on www pointing at it. This is real output from a domain set up that way:

$ dig www.github.com +noall +answer
www.github.com.     3210  IN  CNAME  github.com.
github.com.         20    IN  A      20.29.134.23

The CNAME on www means it follows whatever address the apex has, so you only maintain one A record. Our walkthrough on how to add a CNAME record covers the panel side.

Why the apex can't be a CNAME

The reverse doesn't work. A CNAME can't share a name with any other record, and the apex always carries SOA and NS records, plus MX and TXT for most domains. So example.com CNAME something.host.net is against the DNS rules. Most panels refuse it, and the ones that accept it can break mail and other records at the apex.

If your host gives you a hostname instead of an IP, look for a record type called ALIAS or ANAME, or a feature called CNAME flattening. Those resolve the target on the DNS server and answer with plain A and AAAA records at the apex, so it works without breaking the rules. If your DNS host has none of those, ask the host for a fixed IP to use on the apex and keep the CNAME on www.

The AAAA record nobody remembers

Sometimes the A records were updated during a move, but the old AAAA record still points at the previous server. Visitors on IPv4 get the new site. Visitors on IPv6, which today means a lot of mobile networks, may get the old server, an empty default page or a timeout. Browsers do fall back to IPv4 when IPv6 fails to connect, but if the old address still answers, there's nothing to fall back from.

If one name has an AAAA and the other doesn't, or the AAAA doesn't belong to your current server, update it or delete it. Then test it on its own:

curl -6 -sI https://example.com/

Layer 2: is the server answering for that name?

DNS can be perfect and the server can still serve the wrong thing. A web server picks the site by the hostname in the request, so if the config only lists example.com, a request for www.example.com lands on the default site. That's the classic "www shows the hosting company's welcome page" situation.

Check the first response for all four:

curl -sI http://example.com/  | grep -iE '^(HTTP|location)'
curl -sI http://www.example.com/  | grep -iE '^(HTTP|location)'
curl -sI https://example.com/ | grep -iE '^(HTTP|location)'
curl -sI https://www.example.com/ | grep -iE '^(HTTP|location)'

You want one 200 (on your canonical URL) and three 301s whose location is that same URL. A 200 on two of them means two copies of the site. In Nginx, check that both names appear in a server_name line somewhere; in Apache, look for ServerAlias.

Layer 3: does the certificate cover both names?

This one is easy to miss, because DNS and the server are fine and the browser just shows a scary warning page. A certificate lists the names it's valid for, and a request for any other name gets a browser warning, even if the next step would have redirected away.

openssl s_client -connect example.com:443 -servername www.example.com </dev/null 2>/dev/null \
  | openssl x509 -noout -ext subjectAltName

Run it once with each name after -servername. Both names need to be in the list. Note that a wildcard like *.example.com covers www but not the bare example.com, so a wildcard certificate usually lists the apex as well. With Certbot, ask for both names in one certificate:

certbot --nginx -d example.com -d www.example.com

If you just renewed and still see the old name list, the server may be holding the old file in memory. Our guide to checking SSL certificate expiry shows how to spot a renewed certificate that never got loaded.

Layer 4: redirects that go in circles

A redirect loop shows up as "too many redirects" in the browser. Follow the chain and the loop prints itself:

curl -sIL --max-redirs 5 https://www.example.com/ | grep -iE '^(HTTP|location)'

The usual causes:

  • The server redirects www to the bare name while the app (in WordPress, the Site Address under Settings > General) redirects the bare name back to www. Make both agree.
  • A proxy or CDN in front talks to your server over plain HTTP, and your server redirects every HTTP request to HTTPS. The proxy asks again over HTTP, forever. Switch the proxy to full HTTPS to the origin, or redirect based on the forwarded protocol header.
  • Two rules, one in the server config and one in .htaccess, each "fixing" the other.

Table matching what you see to where to look: no response or name not resolved on one name means a missing A or AAAA record, checked with dig; the host welcome page means the name is missing from server_name or ServerAlias, checked with curl -sI; a certificate warning on one name means the certificate does not list it, checked with openssl s_client; too many redirects means two rules, or a proxy talking plain HTTP to the server, checked with curl -sIL; and working on some networks only means a stale AAAA record, checked with curl -6

Pick one name and 301 the rest

Once DNS, certificate and server all cover both names, send everything to one place. For a bare canonical name in Nginx:

server {
    listen 80;
    server_name example.com www.example.com;
    return 301 https://example.com$request_uri;
}
server {
    listen 443 ssl;
    server_name www.example.com;
    ssl_certificate     /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
    return 301 https://example.com$request_uri;
}

The real site then lives in a third server block with listen 443 ssl and server_name example.com. On Apache or shared hosting, the same thing in .htaccess:

RewriteEngine On
RewriteCond %{HTTPS} off [OR]
RewriteCond %{HTTP_HOST} ^www\. [NC]
RewriteRule ^ https://example.com%{REQUEST_URI} [L,R=301]

Two habits save a lot of pain. Test with a 302 first and switch to 301 once it works, because browsers cache a 301 and keep following a wrong one even after you fix the server. And keep $request_uri (or %{REQUEST_URI}) in the target so deep links land on the same page instead of the home page.

Check all four in one go

Running those commands for every variant gets tedious, so we wrote a read-only script that does it. It looks up A, AAAA and CNAME for both names, requests all four variants pinned to the address DNS returned, follows the redirects, reads the certificate each name serves and tells you whether every variant ends on the same URL.

./dns/www-apex-check.sh example.com
./dns/www-apex-check.sh --doh example.com   # ask 1.1.1.1 over HTTPS instead of the local resolver

Terminal screenshot of www-apex-check.sh run against progineous.com: both names have the same two A records and two AAAA records and no CNAME, http and https on www and the bare name all end on https://progineous.com/ with HTTP 200, the certificate on both names lists progineous.com and *.progineous.com and covers both, the IPv6 test is skipped because the test machine has no IPv6 route, and the result is OK with exit code 0

That run is against our own domain. Every variant ends on https://progineous.com/ and the certificate covers both names, but http://www takes two hops (to https www, then to the bare name). A single rule straight to the final URL would save a round trip. When something is wrong, the script ends with FAIL or WARN lines that name the problem, such as a CNAME at the apex, a certificate that only covers one name or a redirect loop, and exits with 1 or 2 so you can use it in monitoring.

The script is free in our server toolkit on GitLab: dns/www-apex-check.sh. If you're setting up a new site anyway, Pro Gineous has shared hosting at $29 for the first year with the code new-2026 (valid until December 1, 2026) and VPS plans from $6.96/mo.

Quick answers

Should you use www or the bare domain?

Either works. The bare name is shorter to type, while www makes CDNs and cookie scoping a little easier on big setups. What matters is picking one and redirecting the other three variants to it.

Domain not working without www, but DNS looks right?

Then check the certificate and the server config next. Run the openssl command above with the bare name after -servername, and make sure that name is in server_name or ServerAlias.

How long until a fixed record works everywhere?

As long as the old record's TTL, which is often an hour or less but can be a day. A missing record can also be cached as "doesn't exist" for a while, based on the zone's SOA record.

Originally published on the Pro Gineous blog.

📰 Read the original article on Dev.to WebDev

Originally published by Dev.to WebDev. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.