This is one of those tasks that looks trivial and then quietly causes SEO headaches, duplicate content warnings, and broken SSL certificates when it’s done wrong. I’ve inherited more than one server where example.com and www.example.com both served the exact same content independently, with no redirect between them — which search engines treat as two separate sites with duplicate content, splitting your SEO value between two URLs instead of consolidating it on one.
This guide covers doing the www redirect properly: picking a canonical domain, setting up the redirect correctly (301, not 302), making sure it works with HTTPS, and avoiding the common mistakes that break this in subtle ways.
Why This Matters
A few concrete reasons to get this right, beyond “it looks tidier”:
- SEO consolidation. Search engines see
example.comandwww.example.comas different URLs. Without a redirect, your backlinks, social shares, and search ranking signals get split between the two instead of concentrated on one canonical version. - Cookie and session consistency. Some cookies are scoped to
www.example.comspecifically and won’t be sent on requests to bareexample.com(or vice versa), which can cause confusing login/session bugs depending on which URL a user happens to land on. - SSL certificate coverage. If your certificate only covers one variant and someone hits the other, they’ll see a certificate error before your redirect even has a chance to run.
- Consistent analytics. Traffic split across two hostnames makes your analytics data harder to interpret correctly.
Step 1: Decide Your Canonical Domain
This is genuinely a business/branding decision, not a technical one — I’m choosing “redirect non-www to www” for this guide since that’s the specific direction you asked about, but the reverse (www to non-www) is equally valid and follows the identical pattern, just swapped. Once you decide, stick with it everywhere: your DNS records, your marketing materials, your social profiles, all should point people at the version you’re keeping canonical.
Step 2: Set Up DNS for Both Variants
Before touching Nginx, make sure both example.com and www.example.com actually resolve to your server. In your DNS provider:
Arecord forexample.com→ your server’s IPA(orCNAME) record forwww.example.com→ your server’s IP (orCNAMEtoexample.com)
If www doesn’t resolve at all, no Nginx configuration in the world will let you redirect it — the DNS lookup fails before the request even reaches your server.
Step 3: Get a Certificate Covering Both Variants
This step trips people up constantly. You need a single certificate valid for both hostnames, or the redirect will trigger a certificate warning before it can even execute (since the browser validates TLS before processing any HTTP-level redirect).
Using Certbot:
sudo apt install certbot python3-certbot-nginx -y
sudo certbot --nginx -d example.com -d www.example.com
Passing both -d flags issues a single certificate covering both names via Subject Alternative Names (SAN). Confirm it worked:
sudo certbot certificates
You should see both hostnames listed under the same certificate.
Step 4: Configure the Redirect in Nginx
Here’s the clean, correct way to do this — one server block that only exists to redirect, and one server block that serves your actual content:
# Block 1: catches the non-www domain (both HTTP and HTTPS) and redirects to www
server {
listen 80;
listen 443 ssl;
server_name example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
return 301 https://www.example.com$request_uri;
}
# Block 2: the real site, served only from www
server {
listen 80;
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;
# Redirect HTTP to HTTPS on the www host too
if ($scheme = http) {
return 301 https://www.example.com$request_uri;
}
root /var/www/example.com/public;
index index.html;
location / {
try_files $uri $uri/ =404;
}
}
Let’s break down why this is structured the way it is:
return 301— a 301 is a permanent redirect, which is what tells search engines “consolidate ranking signal onto the new URL, this isn’t temporary.” Using a 302 (temporary redirect) here is the single most common mistake — it technically works for users but tells search engines not to transfer SEO value, defeating half the point of doing this at all.$request_uri— this preserves the full path and query string.https://example.com/blog/post-1?ref=twittercorrectly becomeshttps://www.example.com/blog/post-1?ref=twitter, not just a blind redirect to the homepage. Forgetting this is the second most common mistake I see.- Both
listen 80andlisten 443 sslin the redirect block — this handles someone hitting either the plain HTTP or HTTPS version of the non-www domain; both get redirected straight to the final HTTPS+www destination in one hop, rather than redirect-chaining (HTTP→HTTPS→www, three separate round trips) which is slower and looks worse to both users and search engine crawlers evaluating redirect chains.
A cleaner alternative that avoids the if directive (which Nginx’s own documentation recommends minimizing use of) is to split the www block into two separate listen blocks instead:
server {
listen 80;
server_name www.example.com;
return 301 https://www.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;
root /var/www/example.com/public;
index index.html;
location / {
try_files $uri $uri/ =404;
}
}
This is functionally identical but avoids the if block, which I’d generally recommend as the more idiomatic Nginx pattern.
Enable and test:
sudo ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
Step 5: Update Your Canonical Tags
Nginx-level redirects handle the HTTP layer, but it’s worth also confirming your HTML includes a matching canonical tag, reinforcing the same signal directly to search engines and crawlers that read page content:
<link rel="canonical" href="https://www.example.com/blog/post-1" />
This isn’t an Nginx configuration step, but I mention it because I’ve seen sites get the redirect right at the server level while their CMS or static site generator still emits canonical tags pointing at the non-www version — sending mixed signals that undermine the whole point of the redirect.
Testing Your Setup
Use curl -I to inspect the redirect chain directly:
curl -I http://example.com/some-page
Expected output includes:
HTTP/1.1 301 Moved Permanently
Location: https://www.example.com/some-page
Test all four combinations to be thorough:
curl -I http://example.com
curl -I https://example.com
curl -I http://www.example.com
curl -I https://www.example.com
The first three should each return a 301 pointing at https://www.example.com; the last should return your actual site content with a 200.
Also test that query strings and paths survive the redirect intact:
curl -I "http://example.com/products?category=shoes&sort=price"
The Location header should show the identical path and query string, just on the www HTTPS host.
Troubleshooting Common Issues
Redirect loop (ERR_TOO_MANY_REDIRECTS) — Usually caused by both server blocks matching the same server_name, or a CDN/load balancer in front of Nginx doing its own www redirect that conflicts with Nginx’s. Double check server_name values are distinct and that nothing upstream (Cloudflare page rules, for example) is also redirecting.
Certificate warning before redirect appears — The certificate doesn’t cover both hostnames. Re-run Certbot with both -d flags, or check openssl s_client -connect example.com:443 -servername example.com and inspect the certificate’s SAN list.
Redirect works but drops the path — $request_uri was omitted from the return directive. Every redirect to / regardless of the original path is the telltale symptom.
Redirect works for HTTP but not HTTPS (or vice versa) — Check that both listen 80 and listen 443 ssl are present in the redirecting server block, and that the SSL certificate paths are valid there too — Nginx needs a valid cert even just to serve the 301 over HTTPS.
Search engines still showing both versions weeks later — 301s are respected by crawlers but re-indexing takes time. Submit both URL versions in Google Search Console and confirm the canonical is registering correctly; this is patience, not a configuration bug at that point.
Security Considerations
- Ensure both hostnames are covered by your certificate renewal, not just initial issuance — check your renewal hook or cron job covers the SAN list correctly:
sudo certbot renew --dry-run
- Don’t skip the HTTPS redirect while you’re in here anyway — every non-canonical HTTP request should end up on HTTPS, not just the www consolidation.
- Add HSTS once you’re confident the redirect setup is stable, to tell browsers to always use HTTPS for this domain going forward, skipping the initial HTTP round-trip entirely on repeat visits:
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
Be cautious with HSTS — once a browser caches it, that policy is hard to undo for users, so only add it once you’re confident in your HTTPS setup’s stability.
Performance Tips
- Consolidate to a single redirect hop. As shown above, handle the protocol upgrade (HTTP→HTTPS) and the domain canonicalization (non-www→www) in one
301, not two sequential redirects — this halves the round trips for every non-canonical request. - Cache DNS lookups appropriately — this isn’t Nginx-specific, but a short TTL on your DNS records makes future changes easier without meaningfully hurting performance for a redirect-only host.
- Keep the redirect block minimal. Don’t load unnecessary modules, logging, or processing into a server block that exists purely to issue a 301 — it should be about as lightweight as Nginx configuration gets.
Real-World Use Cases
- A marketing site migrating from
wwwto bare domain (or vice versa) as part of a rebrand, where getting the 301 (not 302) right was essential to preserving years of accumulated SEO ranking during the transition. - An e-commerce store consolidating duplicate product page indexing — search console reports had flagged both www and non-www versions of thousands of product pages as duplicate content prior to the fix.
- A company merging two previously separate subdomains’ worth of traffic onto one canonical hostname after a platform migration, using this exact redirect pattern combined with
$request_uripreservation to avoid breaking any existing inbound links from years of link-building and press coverage.
Best Practices Recap
- Pick one canonical domain (www or non-www) and stick to it everywhere — DNS, marketing, canonical tags, redirect configuration.
- Always use
301, never302, for a permanent domain consolidation. - Always preserve the full path and query string with
$request_uri. - Get a single certificate covering both hostnames via SAN.
- Collapse HTTP→HTTPS and non-www→www into a single redirect hop where possible.
- Test all four URL combinations (http/https × www/non-www) after any change.
- Reinforce the redirect with matching
rel="canonical"tags in your HTML.
It’s a small piece of configuration, but getting it right the first time saves you from untangling split SEO signals and confused analytics data months down the line.