Nginx Redirect Configuration Guide
Contents
Nginx is one of the most widely deployed web servers, and redirect configuration is a routine part of running it. The two main tools โ return and rewrite โ are often confused, leading to inefficient or broken configs.
return vs rewrite
return (recommended)
return 301 https://example.com;
- โ Fast โ sends the HTTP response directly, no regex engine involved
- โ Simple syntax, hard to get wrong
- โ Official recommendation for most redirect use cases
- โ Can't capture and reuse URL segments
rewrite (powerful but slower)
rewrite ^/old-path/(.*)$ /new-path/$1 permanent;
- โ Supports regex capture groups
- โ Can transform URL structure
- โ Slower than
return - โ Complex syntax, easy to create infinite loops
๐ก Rule of thumb
Use return whenever possible. Only reach for rewrite when you need regex capture groups or complex URL transformation.
Basic examples
301 permanent redirect
server {
listen 80;
server_name old-domain.com;
return 301 https://new-domain.com$request_uri;
}
302 temporary redirect
server {
listen 80;
server_name example.com;
location /maintenance {
return 302 /maintenance.html;
}
}
Single page redirect
location = /old-page.html {
return 301 /new-page.html;
}
HTTP to HTTPS
Recommended: separate server blocks
server {
listen 80;
server_name example.com www.example.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
server_name example.com www.example.com;
ssl_certificate /path/to/fullchain.pem;
ssl_certificate_key /path/to/privkey.pem;
# site config...
}
โ ๏ธ Avoid the if directive
The Nginx community has a saying: "if is evil." The if directive can cause unexpected behavior in certain contexts. Stick to separate server blocks for HTTPS redirects.
www canonicalization
non-www โ www
server {
listen 80;
listen 443 ssl http2;
server_name example.com;
ssl_certificate /path/to/fullchain.pem;
ssl_certificate_key /path/to/privkey.pem;
return 301 https://www.example.com$request_uri;
}
www โ non-www
server {
listen 80;
listen 443 ssl http2;
server_name www.example.com;
ssl_certificate /path/to/fullchain.pem;
ssl_certificate_key /path/to/privkey.pem;
return 301 https://example.com$request_uri;
}
Path redirects
# Redirect a directory, stripping the prefix
location /blog/ {
rewrite ^/blog/(.*)$ /articles/$1 permanent;
}
# Bulk redirects with map (efficient for large lists)
map $uri $new_uri {
/old-page-1 /new-page-1;
/old-page-2 /new-page-2;
}
server {
if ($new_uri) { return 301 $new_uri; }
}
Regex redirects
# Remove .html extension
location ~ ^(.+)\.html$ {
return 301 $1;
}
# Strip date-based URL prefix
location ~ ^/\d{4}/\d{2}/\d{2}/(.+)$ {
return 301 /$1;
}
Common pitfalls
1. rewrite loop
# โ Infinite loop
location /old/ {
rewrite ^/old/(.*)$ /new/$1;
}
# โ
Use permanent flag or return
location /old/ {
return 301 /new$request_uri;
}
2. Lost query strings
# โ Query string dropped
location /old { return 301 /new; }
# โ
Preserve query string
location /old { return 301 /new$is_args$args; }
3. Missing SSL config on HTTPS target
If you redirect HTTP โ HTTPS but haven't configured the HTTPS server block with a valid certificate, users will get a connection error. Always verify the HTTPS block exists and the cert is valid before enabling the redirect.
Performance tips
- Prefer
returnoverrewriteโ no regex engine overhead - Collapse redirect chains: redirect directly from A to C, not A โ B โ C
- Use
mapfor large redirect tables โ it's evaluated at config load time, not per request - Avoid unnecessary regex in
locationblocks; use prefix or exact matches where possible - Always run
nginx -tafter changes to catch syntax errors before reloading
After configuring redirects, verify them with 301check.com.