An Nginx redirect from www to non-www is usually a server-block decision, not an application rewrite. A small server block can catch www.example.com, send a permanent 301 response, and preserve the original path and query string with $request_uri.
The same pattern also works for a 301 non-www to www redirect when www.example.com is the canonical host. Use one canonical hostname, keep both DNS names and TLS names valid, then verify the final Location header before sending real traffic through the change.
Choose an Nginx WWW or Non-WWW Redirect
A www/non-www redirect solves a hostname canonicalization problem. The URI path, query string, and application route should stay the same; only the hostname changes. That is why return 301 is cleaner than rewrite for this job.
These Nginx pieces matter most for www and non-www redirects:
| Nginx item | Context or source | Role in www redirects |
|---|---|---|
server_name | server block | Chooses which hostname a block handles, such as example.com or www.example.com. |
return | server, location, rewrite-module if | Sends the redirect response immediately. For these examples, return 301 is the primary method. |
$request_uri | Embedded variable | Preserves the original path and query string, such as /about?ref=test. |
rewrite | server, location, rewrite-module if | Uses regex for URI transformations. Keep it for complex path changes, not simple host canonicalization. |
A 301 redirect is permanent and may be cached by browsers. Test with
curlor a private browser session before assuming a browser refresh shows the current server behavior.
Choose the Canonical Host and Scheme
Choose the final hostname before editing Nginx. A redirect rule should catch the non-canonical hostname and send it to the one hostname search engines, certificates, analytics, and application settings should use.
| Reader goal | Redirecting hostname | Canonical destination | Common return target |
|---|---|---|---|
| Redirect www to non-www | www.example.com | example.com | https://example.com$request_uri |
| Redirect non-www to www | example.com | www.example.com | https://www.example.com$request_uri |
| Redirect both HTTP hostnames to HTTPS non-www | example.com and www.example.com on port 80 | https://example.com | https://example.com$request_uri |
| Redirect both HTTP hostnames to HTTPS www | example.com and www.example.com on port 80 | https://www.example.com | https://www.example.com$request_uri |
Use one permanent canonical route after testing. Keeping both opposite directions active creates a redirect loop, and splitting canonical decisions between Nginx, a CDN, a hosting panel, and the application can make the final Location header hard to predict.
Nginx Redirect Prerequisites
Before placing redirect blocks, confirm the server already has the basics in place:
- Nginx installed and running: If the base package is missing, use the matching guide for installing Nginx on Ubuntu, installing Nginx on Debian, or installing Nginx on Fedora.
- DNS for both hostnames: Both
example.comandwww.example.commust resolve to the server or proxy layer that will issue the redirect. - A working site block: Start from a site that already serves content on the hostname you plan to keep. If the virtual host is not ready, configure Nginx server blocks and virtual hosts first.
- Certificates for both HTTPS names: A redirect from
https://www.example.comtohttps://example.comstill needs a certificate that coverswww.example.com, because TLS negotiation happens before Nginx can return the redirect.
This raw-config workflow requires access to the Nginx files that serve the public hostname. If Cloudflare, a hosting panel, Nginx Proxy Manager, or another reverse proxy owns that hostname, configure the canonical redirect there or make sure only one layer performs it. Duplicate redirects are a common cause of loops.
Replace example.com and www.example.com in every snippet with the actual hostnames for your site before testing or reloading Nginx.
Place Nginx Redirect Server Blocks
Nginx configuration paths vary by package and operating system. Debian and Ubuntu packages commonly use /etc/nginx/sites-available/ with symlinks into /etc/nginx/sites-enabled/. Fedora, RHEL-family packages, nginx.org packages, and many source builds commonly load virtual host files from /etc/nginx/conf.d/.
Use grep with extended regex to show which include paths your main config loads:
grep -E "include.*(sites-enabled|conf\.d)" /etc/nginx/nginx.conf
Relevant lines may include one or both common layouts:
include /etc/nginx/conf.d/*.conf; include /etc/nginx/sites-enabled/*;
Back up the file you plan to edit before changing a live site block. For a Debian or Ubuntu sites-available layout, back up the source site file:
sudo cp /etc/nginx/sites-available/example.com /etc/nginx/sites-available/example.com.bak
For a conf.d layout, back up the matching virtual host file instead:
sudo cp /etc/nginx/conf.d/example.com.conf /etc/nginx/conf.d/example.com.conf.bak
Redirect WWW to Non-WWW in Nginx
To redirect www.example.com to example.com in Nginx, create a dedicated redirect block for the www hostname and keep the bare domain in the main site block. The core 301 pattern is return 301 https://example.com$request_uri;; switch the scheme to http:// only for an HTTP-only site.
HTTP WWW to Non-WWW Redirect
For an HTTP-only site, redirect the www hostname and serve the bare hostname:
server {
listen 80;
listen [::]:80;
server_name www.example.com;
return 301 http://example.com$request_uri;
}
server {
listen 80;
listen [::]:80;
server_name example.com;
root /var/www/example.com/html;
index index.html index.htm;
# Your site configuration continues here
}
A request for http://www.example.com/about?ref=test now returns a 301 redirect to http://example.com/about?ref=test. The $request_uri variable keeps the path and query string intact.
HTTPS WWW to Non-WWW Redirect
For a production HTTPS site, handle HTTP-to-HTTPS and www-to-non-www as separate responsibilities in clear server blocks:
# Redirect all HTTP requests to the canonical HTTPS host
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
return 301 https://example.com$request_uri;
}
# Redirect HTTPS www requests to the bare domain
server {
listen 443 ssl;
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;
}
# Serve the canonical HTTPS site
server {
listen 443 ssl;
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;
root /var/www/example.com/html;
index index.html index.htm;
# Your site configuration continues here
}
The certificate path is reused here because a single Let’s Encrypt certificate can include both example.com and www.example.com. If your certificate files use separate names, adjust the paths to match the real certificate that covers each hostname.
Redirect Non-WWW to WWW in Nginx
For a 301 non-www to www redirect in Nginx, reverse the hostname roles. The bare-domain block redirects, and the www block serves the site. The core HTTPS pattern is return 301 https://www.example.com$request_uri;.
HTTP Non-WWW to WWW Redirect
For HTTP-only traffic, redirect the bare hostname to the www hostname:
server {
listen 80;
listen [::]:80;
server_name example.com;
return 301 http://www.example.com$request_uri;
}
server {
listen 80;
listen [::]:80;
server_name www.example.com;
root /var/www/example.com/html;
index index.html index.htm;
# Your site configuration continues here
}
A request for http://example.com/about?ref=test now returns a 301 redirect to http://www.example.com/about?ref=test. The redirect changes only the hostname.
HTTPS Non-WWW to WWW Redirect
For HTTPS traffic, redirect all HTTP requests to the canonical HTTPS www host, then redirect HTTPS bare-domain requests to the same canonical host:
# Redirect all HTTP requests to the canonical HTTPS www host
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
return 301 https://www.example.com$request_uri;
}
# Redirect HTTPS bare-domain requests to www
server {
listen 443 ssl;
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;
}
# Serve the canonical HTTPS www site
server {
listen 443 ssl;
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/html;
index index.html index.htm;
# Your site configuration continues here
}
Control Path and Query String Handling in Nginx Redirects
Most hostname redirects should preserve the original path and query string. Nginx’s $request_uri variable contains the full original request URI with arguments, so it keeps a request such as /about?ref=test intact while changing only the scheme or host.
| Redirect behavior | Use this return target | Example result |
|---|---|---|
| Keep the original path and query string | https://example.com$request_uri | /about?ref=test stays /about?ref=test. |
| Drop the query string intentionally | https://example.com$uri | /about?ref=test becomes /about. |
| Test without browser-caching a permanent redirect | https://example.com$request_uri with return 302 | Use temporarily, then switch back to return 301 after verification. |
Use $uri only when dropping the query string is intentional. It uses Nginx’s normalized current URI, while $request_uri keeps the original request URI and arguments that reached Nginx.
This block redirects the www hostname to the bare HTTPS hostname while preserving both path and query string:
server {
listen 80;
listen [::]:80;
server_name www.example.com;
return 301 https://example.com$request_uri;
}
This variant drops query strings during the hostname redirect. Use it only for a deliberate cleanup or migration, because it can remove tracking, search, pagination, or application parameters that the destination route still expects:
server {
listen 80;
listen [::]:80;
server_name www.example.com;
return 301 https://example.com$uri;
}
Use Nginx Rewrite Rules Only for Complex Redirects
The rewrite directive still appears in older Nginx examples, but it is not the best first choice for a simple www redirect. Use rewrite when the URL path itself needs regex-based transformation; use return when only the scheme or hostname changes.
Host canonicalization is narrower than URL migration. If the path, port, method, or upstream response changes, use the broader guide to redirect URLs in Nginx and keep this page focused on hostname choice.
This rewrite equivalent redirects www to non-www, but it adds regex processing without improving the result:
server {
listen 80;
listen [::]:80;
server_name www.example.com;
rewrite ^(.*)$ http://example.com$1 permanent;
}
In this example, ^(.*)$ captures the normalized URI path, while Nginx preserves the original query string unless the replacement defines new arguments or ends with a question mark. The permanent flag returns a 301 redirect. For path migrations, regex captures, or query-string control, use the dedicated guide to create rewrite rules in Nginx instead of expanding this canonical-host article into a broader rewrite tutorial.
Test and Apply Nginx Redirect Configuration
After adding the redirect blocks, test Nginx syntax before reloading the service. A syntax error anywhere in the loaded configuration can stop the reload.
sudo nginx -t
A successful syntax test returns:
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful
Reload Nginx only after the syntax test passes:
sudo systemctl reload nginx
Test Redirects Before DNS Changes
When DNS still points somewhere else, test the new Nginx origin by resolving the hostname to the origin IP for one request. Replace 203.0.113.10 with the server IP that should answer the redirect.
curl --noproxy '*' --resolve www.example.com:80:203.0.113.10 -sS -D - -o /dev/null http://www.example.com/about?ref=test
For HTTPS, the same pattern preserves the hostname for SNI and certificate checks while sending the request to the chosen IP:
curl --noproxy '*' --resolve www.example.com:443:203.0.113.10 -sS -D - -o /dev/null https://www.example.com/about?ref=test
The --noproxy '*' option prevents local proxy environment variables from sending the test through a different layer. That matters when a CDN, corporate proxy, or development proxy would hide the origin Nginx response.
Test Redirects After DNS Is Live
Verify the live redirect by checking the response headers from a normal request. The curl command with -sS -D - -o /dev/null prints response headers, suppresses the body, and still uses a GET request that most sites handle normally:
curl -sS -D - -o /dev/null http://www.example.com/about?ref=test
Relevant headers for a www-to-non-www HTTPS redirect include:
HTTP/1.1 301 Moved Permanently Location: https://example.com/about?ref=test
Test both hostname directions and both schemes that your configuration accepts. For a canonical www setup, the Location header should point to https://www.example.com/... instead.
For a complete canonical-host check, run the same header test against each source URL your server accepts:
curl -sS -D - -o /dev/null http://example.com/about?ref=test
curl -sS -D - -o /dev/null http://www.example.com/about?ref=test
curl -sS -D - -o /dev/null https://example.com/about?ref=test
curl -sS -D - -o /dev/null https://www.example.com/about?ref=test
The canonical hostname should return the final page or application response, while the non-canonical hostname should return one redirect to the canonical hostname. More than one hop can be valid during an HTTP-to-HTTPS migration, but the chain should not bounce between hostnames.
Roll Back Nginx Redirect Changes
If the redirect sends traffic to the wrong host or causes a loop, restore the backup for the layout you edited. For Debian or Ubuntu sites-available layouts, restore the site file:
sudo cp /etc/nginx/sites-available/example.com.bak /etc/nginx/sites-available/example.com
For a conf.d layout, restore the matching virtual host file instead:
sudo cp /etc/nginx/conf.d/example.com.conf.bak /etc/nginx/conf.d/example.com.conf
If the backup is older than later site edits, remove only the redirect server block you added instead of overwriting the whole file. Test and reload after either rollback path:
sudo nginx -t
sudo systemctl reload nginx
Troubleshoot Nginx WWW Redirect Issues
Redirect Loop or ERR_TOO_MANY_REDIRECTS
A redirect loop usually means more than one layer is trying to canonicalize the host, scheme, or path. Nginx may redirect to a hostname that a CDN, proxy manager, CMS, or application redirects back.
A browser may show ERR_TOO_MANY_REDIRECTS when the redirect chain repeats.
Check the redirect chain from the terminal. The -L flag follows redirects so each Location header appears in sequence:
curl -sS -L -D - -o /dev/null http://www.example.com/ | grep -Ei "^(HTTP/|Location:)"
A loop often alternates between the same two hostnames:
HTTP/1.1 301 Moved Permanently Location: https://example.com/ HTTP/2 301 Location: https://www.example.com/
Keep one canonical redirect path and remove the opposing rule. If proxy_pass is involved and the backend also redirects, review the guide to create a reverse proxy in Nginx so the proxy and backend agree on forwarded host and scheme headers.
HTTPS Certificate Warning Before Redirect
A browser certificate warning before the redirect means TLS failed before Nginx could send the 301 response. Check that the certificate presented for the source hostname includes both names:
sudo openssl x509 -in /etc/letsencrypt/live/example.com/fullchain.pem -text -noout | grep -A1 "Subject Alternative Name"
Relevant output should include both hostnames:
X509v3 Subject Alternative Name:
DNS:example.com, DNS:www.example.com
If one name is missing, issue or select a certificate that covers both hostnames before relying on HTTPS redirects.
Path or Query String Missing from the Redirect
If the Location header loses the path or query string, inspect the exact redirect response instead of testing only the homepage:
curl -sS -D - -o /dev/null 'http://www.example.com/about?ref=test' | grep -Ei '^(HTTP/|Location:)'
A broken redirect may point only to the canonical root or drop the arguments:
HTTP/1.1 301 Moved Permanently Location: https://example.com/about
Use $request_uri in the return target when the destination should keep the original path and query string. Use $uri only when the redirect should intentionally drop arguments, then retest the same URL with curl -sS -D - -o /dev/null.
Nginx Redirect Not Working After Reload
If curl still returns the old destination after a successful reload, confirm Nginx loaded the server block you edited:
sudo nginx -T 2>/dev/null | awk '/^# configuration file / {file=$0; shown=0} /server_name .*example\.com/ {if (!shown) {print file; shown=1} print}'
Relevant lines should show both the owning file and the hostnames from the active configuration:
# configuration file /etc/nginx/sites-enabled/example.com:
server_name example.com www.example.com;
server_name www.example.com;
If those lines are missing, enable the site file or move the block into an included path such as sites-enabled or conf.d. If the lines are present, retest with curl -sS -D - -o /dev/null rather than a browser that may cache a previous 301 redirect. For reload failures, use the tail command to check the active file and line number in the error log:
sudo tail -20 /var/log/nginx/error.log
Look for the first error line that names the configuration file, line number, and directive that failed.
If a CDN or proxy manager sits in front of Nginx, check that layer’s redirect settings before changing more origin config.
Conclusion
Nginx can now send every visitor to one canonical hostname with a permanent 301 redirect while preserving paths and query strings. After the hostname decision is stable, check adjacent site behavior such as configuring Nginx security headers or proxy forwarding before broadening the redirect rules.


Formatting tips for your comment
You can use basic HTML to format your comment. Useful tags currently allowed in published comments:
<code>command</code>command<strong>bold</strong><em>italic</em><blockquote>quote</blockquote>