example.com and www.example.com are different hostnames. If both serve the same site, search engines may treat them as duplicates, cookies and analytics split, and links point both ways. Pick one canonical version, and 301-redirect the other to it, keeping the path and query string.
Which should you choose?
Either works for SEO. Common reasons to pick one:
- Non-www (
example.com): shorter, modern look. - www (
www.example.com): lets you scope cookies towwwonly, and CNAME it to a CDN. Some DNS providers can’t CNAME the bare domain.
What matters is consistency: the redirect, internal links, canonical tags, sitemaps, and the app’s base URL all use the same host.
Nginx: non-www as canonical
# redirect HTTP (both hosts) → https://example.com
server {
listen 80;
server_name example.com www.example.com;
return 301 https://example.com$request_uri;
}
# redirect HTTPS www → non-www
server {
listen 443 ssl;
http2 on;
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
server {
listen 443 ssl;
http2 on;
server_name example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
root /var/www/example.com;
# …
}
For www as canonical, swap the names. Use return 301 (fast and clear) rather than rewrite or if blocks. See Nginx HTTP to HTTPS redirect.
The certificate must cover both names, or visitors to https://www.example.com see a certificate error before the redirect happens:
sudo certbot --nginx -d example.com -d www.example.com
See Let’s Encrypt with Certbot.
Apache
<VirtualHost *:80>
ServerName example.com
ServerAlias www.example.com
Redirect permanent / https://example.com/
</VirtualHost>
<VirtualHost *:443>
ServerName www.example.com
SSLEngine on
# SSLCertificateFile …
Redirect permanent / https://example.com/
</VirtualHost>
Or with mod_rewrite in .htaccess:
RewriteEngine On
RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC]
RewriteRule ^ https://%1%{REQUEST_URI} [R=301,L]
Cloudflare
If the site is behind Cloudflare, you can redirect at the edge with a Redirect Rule: when the hostname equals www.example.com, dynamically redirect to concat("https://example.com", http.request.uri.path), with the query string preserved, as a 301. The www DNS record must exist and be proxied (orange cloud). See using Cloudflare with a VPS.
Update the application
- WordPress: set the Site Address and WordPress Address to the canonical URL. Mismatches cause redirect loops. See change the WordPress site URL and WordPress too many redirects.
- Frameworks: set the base or app URL (Laravel
APP_URL, DjangoALLOWED_HOSTSand canonical links). - Search Console: add both properties, or a Domain property, and submit the sitemap with canonical URLs.
Test
curl -sI http://www.example.com/blog/?a=1 | grep -iE '^(HTTP|location)'
curl -sI https://www.example.com/blog/?a=1 | grep -iE '^(HTTP|location)'
curl -sI http://example.com/ | grep -iE '^(HTTP|location)'
Each should be a single 301 to https://example.com/…, with the path and query intact. Avoid chains (http://www → https://www → https://non-www) where possible.
301 vs 302
Use 301 (permanent) for canonical-host redirects, so search engines transfer signals. 302 means temporary. Avoid it for this. Browsers cache 301s aggressively, so test with curl rather than your browser while experimenting.
Quick reference
| Task | How |
|---|---|
| Nginx | Separate server block → return 301 https://example.com$request_uri; |
| Apache | Redirect permanent or mod_rewrite |
| Certificate | Must include both names |
| Cloudflare | Redirect Rule (301, keep query) |
| Test | curl -sI for each variant |
Related: Nginx multiple domains with SSL and WordPress redirects.