
How to Create Temporary and Permanent Redirects with Nginx
Web redirects are a fundamental aspect of server management that every developer and sysadmin encounters. Whether you’re restructuring your site, implementing SEO best practices, or handling temporary maintenance, Nginx provides powerful redirect capabilities that can make or break your user experience. This guide will walk you through implementing both 301 permanent and 302 temporary redirects in Nginx, covering everything from basic syntax to advanced redirect patterns, common troubleshooting scenarios, and performance considerations that matter in production environments.
Understanding HTTP Redirects and Status Codes
Before diving into Nginx configurations, let’s clarify the difference between redirect types. A 301 redirect tells browsers and search engines that a resource has permanently moved to a new location, passing along most of the original page’s SEO value. A 302 redirect indicates a temporary move, suggesting the original URL will eventually be restored.
Nginx handles redirects through the return
directive and the rewrite
module. The return
directive is generally preferred for simple redirects because it’s more efficient and doesn’t require regex processing.
Status Code | Type | Use Case | SEO Impact |
---|---|---|---|
301 | Permanent | Site restructuring, domain changes | Passes link equity |
302 | Temporary | Maintenance, A/B testing | Preserves original URL ranking |
307 | Temporary (HTTP/1.1) | Method preservation required | Similar to 302 |
308 | Permanent (HTTP/1.1) | Method preservation required | Similar to 301 |
Basic Redirect Configuration
The simplest way to implement redirects in Nginx is using the return
directive within server blocks or location contexts. Here’s the basic syntax:
server {
listen 80;
server_name old-domain.com;
# Permanent redirect (301)
return 301 https://new-domain.com$request_uri;
}
server {
listen 80;
server_name example.com;
location /old-page {
# Temporary redirect (302)
return 302 /new-page;
}
location /temporary-maintenance {
return 302 /maintenance.html;
}
}
The $request_uri
variable preserves the original path and query parameters, ensuring users land on the equivalent page at the new location. This is crucial for maintaining user experience and SEO value.
Advanced Redirect Patterns
Real-world scenarios often require more sophisticated redirect logic. Here are some common patterns:
# Redirect specific file extensions
location ~* \.(asp|aspx|php)$ {
return 301 /;
}
# Redirect based on user agent
location / {
if ($http_user_agent ~* "mobile|android|iphone") {
return 302 https://m.example.com$request_uri;
}
}
# Conditional redirects with multiple conditions
location /api {
if ($request_method = POST) {
return 405;
}
if ($args ~ "version=old") {
return 301 /api/v2$request_uri;
}
}
# Redirect with parameter manipulation
location /search {
if ($args ~ "^q=(.+)") {
return 301 /find?query=$1;
}
}
While if
statements work, they should be used sparingly as they can impact performance. The Nginx documentation specifically warns about overusing conditionals.
Using Rewrite Rules for Complex Redirects
When you need more complex pattern matching or URL transformation, the rewrite
directive provides regex-based solutions:
server {
listen 80;
server_name example.com;
# Rewrite with capture groups
rewrite ^/user/(\d+)/profile$ /users/$1 permanent;
rewrite ^/blog/(\d{4})/(\d{2})/(.+)$ /articles/$1-$2-$3 permanent;
# Multiple rewrites with flags
rewrite ^/old-category/(.*)$ /new-category/$1 permanent;
rewrite ^/products/([^/]+)/([^/]+)$ /shop/$1-$2 permanent;
# Conditional rewrites
location ~* ^/admin {
if ($remote_addr !~ "^192\.168\.1\.") {
rewrite ^.*$ /access-denied permanent;
}
}
}
The rewrite flags control processing flow:
permanent
– Issues a 301 redirectredirect
– Issues a 302 redirectlast
– Stops processing and searches for new locationbreak
– Stops processing within current location
Real-World Use Cases and Examples
Here are some practical scenarios you’ll encounter in production environments:
Domain Migration
# Complete domain migration with SSL
server {
listen 80;
listen 443 ssl;
server_name old-domain.com www.old-domain.com;
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
return 301 https://new-domain.com$request_uri;
}
WWW to Non-WWW Redirect
server {
listen 80;
listen 443 ssl;
server_name www.example.com;
return 301 $scheme://example.com$request_uri;
}
E-commerce Category Restructuring
# Old structure: /category/subcategory/product
# New structure: /shop/category-subcategory/product
location ~* ^/category/([^/]+)/([^/]+)/(.+)$ {
return 301 /shop/$1-$2/$3;
}
# Redirect discontinued products to similar items
location ~* ^/products/discontinued-item-(\d+)$ {
return 301 /products/recommended?similar_to=$1;
}
API Versioning
location /api/v1 {
return 301 /api/v2$request_uri;
}
location ~* ^/api/legacy/(.*)$ {
add_header X-Deprecated-API "true";
return 301 /api/v3/$1;
}
Performance Considerations and Best Practices
Redirect performance can significantly impact user experience and server resources. Here are key optimization strategies:
Method | Performance | Use Case | Resource Usage |
---|---|---|---|
return directive | Fastest | Simple redirects | Minimal |
rewrite (simple) | Good | Pattern matching | Low |
rewrite (complex regex) | Slower | Complex transformations | Higher |
if statements | Slowest | Complex conditions | Highest |
Performance best practices include:
- Use
return
instead ofrewrite
when possible - Place most specific matches first in your configuration
- Avoid nested
if
statements - Use
map
directive for large redirect lists - Implement redirect caching where appropriate
Optimizing Large Redirect Lists
For sites with hundreds of redirects, use the map
directive for better performance:
map $request_uri $new_uri {
/old-page-1 /new-page-1;
/old-page-2 /new-page-2;
/old-page-3 /new-page-3;
# hundreds more...
}
server {
listen 80;
server_name example.com;
if ($new_uri) {
return 301 $new_uri;
}
}
Common Issues and Troubleshooting
Even experienced developers encounter redirect issues. Here are the most common problems and solutions:
Redirect Loops
The classic infinite redirect scenario happens when redirect rules create circular references:
# WRONG - Creates redirect loop
location /page1 {
return 301 /page2;
}
location /page2 {
return 301 /page1; # Don't do this!
}
# CORRECT - Check your logic
location /old-section {
return 301 /new-section$request_uri;
}
Debug redirect loops using curl:
curl -I -L http://example.com/problematic-url
Variable Scope Issues
Variables don’t always behave as expected in different contexts:
# Variables in if statements can be tricky
location /api {
set $redirect_url "";
if ($request_method = GET) {
set $redirect_url "/api/v2$request_uri";
}
if ($redirect_url) {
return 301 $redirect_url;
}
}
SSL Certificate Issues with Redirects
When redirecting from HTTPS, ensure certificates are valid for both domains:
# Ensure both domains have valid certificates
server {
listen 443 ssl;
server_name old-domain.com;
ssl_certificate /path/to/old-domain-cert.pem;
ssl_certificate_key /path/to/old-domain-key.pem;
return 301 https://new-domain.com$request_uri;
}
Testing and Validation
Proper testing prevents redirect disasters in production. Use these tools and techniques:
# Test redirect status codes
curl -I http://example.com/test-url
# Follow redirects and show each step
curl -I -L http://example.com/test-url
# Test with specific user agents
curl -H "User-Agent: Mozilla/5.0 (Mobile)" -I http://example.com/
# Validate redirect chains
curl -w "%{url_effective}\n" -I -L -s -o /dev/null http://example.com/
Online tools like HTTP Status can help validate redirect chains and identify issues.
Security Considerations
Redirects can introduce security vulnerabilities if not properly implemented:
- Validate redirect destinations to prevent open redirects
- Use whitelist-based redirect validation for user-input destinations
- Implement rate limiting for redirect-heavy endpoints
- Monitor redirect logs for suspicious patterns
# Secure redirect validation
map $arg_return_to $safe_redirect {
~^/[^/].*$ $arg_return_to; # Relative URLs only
~^https://example\.com/ $arg_return_to; # Same domain only
default /; # Fallback to home
}
location /login {
# After authentication
return 302 $safe_redirect;
}
Setting up proper redirects in Nginx requires understanding both the technical implementation and the business requirements. Whether you’re managing a simple blog migration or a complex e-commerce restructuring, the key is to start with simple return
directives and only add complexity when necessary. Remember to test thoroughly, monitor performance impact, and always have a rollback plan ready.
For production environments, consider hosting your Nginx configurations on reliable infrastructure. VPS solutions provide the flexibility needed for complex redirect scenarios, while dedicated servers offer the performance required for high-traffic sites with extensive redirect requirements.

This article incorporates information and material from various online sources. We acknowledge and appreciate the work of all original authors, publishers, and websites. While every effort has been made to appropriately credit the source material, any unintentional oversight or omission does not constitute a copyright infringement. All trademarks, logos, and images mentioned are the property of their respective owners. If you believe that any content used in this article infringes upon your copyright, please contact us immediately for review and prompt action.
This article is intended for informational and educational purposes only and does not infringe on the rights of the copyright owners. If any copyrighted material has been used without proper credit or in violation of copyright laws, it is unintentional and we will rectify it promptly upon notification. Please note that the republishing, redistribution, or reproduction of part or all of the contents in any form is prohibited without express written permission from the author and website owner. For permissions or further inquiries, please contact us.