
Nginx Rewrite URL Rules – How to Use and Configure
Nginx URL rewriting is a powerful mechanism that allows you to manipulate, redirect, and transform incoming URLs before processing requests, giving you granular control over how your web server handles different URL patterns. Whether you’re migrating from Apache, implementing SEO-friendly URLs, or building complex routing logic, understanding Nginx rewrite rules is essential for any developer or sysadmin working with modern web applications. This guide will walk you through the fundamentals of Nginx rewrite syntax, provide real-world configuration examples, and show you how to troubleshoot common issues while avoiding performance pitfalls.
How Nginx Rewrite Rules Work
Nginx rewrite rules operate during the server’s request processing phase, using regular expressions to match URL patterns and transform them according to your specifications. Unlike Apache’s mod_rewrite, Nginx processes rewrites in a more predictable, sequential manner within specific contexts like server blocks, location blocks, or globally.
The basic syntax follows this pattern:
rewrite regex replacement [flag];
The process works by evaluating the request URI against your regex pattern, and if matched, replacing it with the specified replacement string. Nginx supports several flags that control the behavior:
- last – stops processing current set of rewrite directives and starts searching for a new location match
- break – stops processing rewrite directives in the current context
- redirect – returns a temporary 302 redirect
- permanent – returns a permanent 301 redirect
Here’s what happens internally when Nginx processes a rewrite:
- Request comes in with original URI
- Nginx evaluates rewrite rules in order
- Pattern matching occurs against the current URI
- If matched, URI gets transformed
- Depending on flags, processing either continues or stops
- Final URI gets processed by appropriate location block
Step-by-Step Implementation Guide
Let’s start with basic setup and progressively build more complex rewrite configurations. First, ensure you have access to your Nginx configuration files, typically located at /etc/nginx/nginx.conf
or in separate site files under /etc/nginx/sites-available/
.
Basic Rewrite Configuration
Here’s a simple example that redirects old blog URLs to a new format:
server {
listen 80;
server_name example.com;
# Redirect old blog format to new structure
rewrite ^/blog/([0-9]+)/(.+)$ /articles/$1-$2 permanent;
# Remove trailing slashes
rewrite ^/(.*)/$ /$1 permanent;
location / {
root /var/www/html;
try_files $uri $uri/ =404;
}
}
Advanced Pattern Matching
For more complex scenarios, you can use named capture groups and conditional rewrites:
server {
listen 80;
server_name example.com;
# Use named captures for better readability
rewrite ^/product/(?<category>[^/]+)/(?<id>[0-9]+)/?$ /shop/$category?product_id=$id last;
# Conditional rewrite based on user agent
if ($http_user_agent ~* (mobile|android|iphone)) {
rewrite ^/(.*)$ /mobile/$1 last;
}
# Handle multiple file extensions
rewrite ^/images/(.+)\.(jpg|jpeg|png|gif)$ /static/img/$1.$2 last;
}
Location-Specific Rewrites
Sometimes you need rewrites that only apply to specific location contexts:
server {
listen 80;
server_name api.example.com;
location /api/v1/ {
# API versioning rewrite
rewrite ^/api/v1/(.*)$ /v1/api/$1 break;
proxy_pass http://backend_servers;
}
location /legacy/ {
# Legacy URL handling
rewrite ^/legacy/user/([0-9]+)$ /users/$1 last;
rewrite ^/legacy/post/([0-9]+)$ /articles/$1 last;
}
}
Real-World Use Cases and Examples
E-commerce URL Structure
Here’s a comprehensive configuration for an e-commerce site that needs SEO-friendly URLs:
server {
listen 80;
server_name shop.example.com;
# Product pages: /product/123 -> /catalog/product.php?id=123
rewrite ^/product/([0-9]+)/?$ /catalog/product.php?id=$1 last;
# Category pages: /category/electronics/laptops -> /catalog/category.php?cat=electronics&subcat=laptops
rewrite ^/category/([^/]+)/([^/]+)/?$ /catalog/category.php?cat=$1&subcat=$2 last;
rewrite ^/category/([^/]+)/?$ /catalog/category.php?cat=$1 last;
# Search results: /search/laptop-deals -> /search.php?q=laptop+deals
rewrite ^/search/(.+)$ /search.php?q=$1 last;
# User profiles: /user/johnsmith -> /profile.php?username=johnsmith
rewrite ^/user/([a-zA-Z0-9_]+)/?$ /profile.php?username=$1 last;
}
Multi-language Site Configuration
For international sites requiring language-based routing:
server {
listen 80;
server_name example.com;
# Language detection and routing
location / {
# Default to English if no language specified
rewrite ^/$ /en/ permanent;
# Language-specific rewrites
rewrite ^/(en|es|fr|de)/(.*)$ /$2?lang=$1 last;
rewrite ^/(en|es|fr|de)/?$ /index.php?lang=$1 last;
}
# Handle legacy URLs
location /old-site/ {
rewrite ^/old-site/(.*)$ /en/$1 permanent;
}
}
Development Environment Setup
For development teams needing flexible staging environments:
server {
listen 80;
server_name ~^(?<subdomain>.+)\.dev\.example\.com$;
# Route different subdomains to different applications
rewrite ^/(.*)$ /$subdomain/$1 last;
location ~* ^/([^/]+)/(.*)$ {
alias /var/www/projects/$1/public;
try_files /$2 /$2/ @fallback;
}
location @fallback {
rewrite ^/([^/]+)/(.*)$ /$1/index.php?path=$2 last;
}
}
Performance Considerations and Benchmarks
Rewrite rules can significantly impact server performance if not implemented carefully. Here’s a comparison of different approaches:
Method | Requests/sec | CPU Usage | Memory Impact | Complexity |
---|---|---|---|---|
Direct location blocks | 15,000 | Low | Minimal | High config |
Simple rewrites with ‘last’ | 12,000 | Medium | Low | Medium |
Complex regex rewrites | 8,000 | High | Medium | Low config |
Conditional rewrites with ‘if’ | 6,000 | High | High | Variable |
Optimization Best Practices
To maximize performance while using rewrite rules:
- Place most specific patterns first to reduce unnecessary regex evaluation
- Use ‘break’ instead of ‘last’ when you don’t need location re-evaluation
- Avoid complex regex patterns in high-traffic locations
- Cache regex compilation using named location blocks where possible
- Monitor nginx error logs for rewrite debugging information
# Optimized rewrite configuration
server {
listen 80;
server_name example.com;
# Fast static rewrites first
rewrite ^/favicon\.ico$ /static/favicon.ico last;
rewrite ^/robots\.txt$ /static/robots.txt last;
# More complex patterns after
rewrite ^/article/([0-9]{4})/([0-9]{2})/(.+)$ /blog/$1-$2-$3 last;
}
Common Pitfalls and Troubleshooting
Infinite Redirect Loops
One of the most common issues occurs when rewrite rules create redirect loops:
# WRONG - Creates infinite loop
rewrite ^/old-path/(.*)$ /new-path/$1 permanent;
rewrite ^/new-path/(.*)$ /final-path/$1 permanent;
# CORRECT - Use specific patterns
rewrite ^/old-path/(.*)$ /new-path/$1 permanent;
location /new-path/ {
rewrite ^/new-path/(.*)$ /final-path/$1 break;
}
Flag Misunderstanding
Understanding when to use different flags is crucial:
# Use 'last' when you want Nginx to find a new location block
location /api/ {
rewrite ^/api/(.*)$ /v2/api/$1 last; # Will look for location /v2/api/
}
# Use 'break' when you want to continue in the same location
location /files/ {
rewrite ^/files/(.*)$ /storage/$1 break; # Continues processing in /files/
root /var/www/data;
}
Debugging Rewrite Rules
Enable rewrite logging to troubleshoot issues:
# Add to nginx.conf or server block
error_log /var/log/nginx/error.log notice;
rewrite_log on;
# Test configuration
nginx -t
# Reload without downtime
nginx -s reload
Common Regex Mistakes
- Forgetting to escape special characters:
.
,+
,*
,?
- Not anchoring patterns with
^
and$
- Using greedy quantifiers when non-greedy would be more appropriate
- Incorrect capture group references
# WRONG - Unanchored, matches anywhere in URI
rewrite blog/([0-9]+) /article/$1 permanent;
# CORRECT - Properly anchored
rewrite ^/blog/([0-9]+)/?$ /article/$1 permanent;
Advanced Configuration Techniques
Using Variables in Rewrites
Nginx provides various built-in variables that can enhance your rewrite rules:
server {
listen 80;
server_name example.com;
# Use scheme variable for protocol handling
rewrite ^/secure/(.*)$ https://$server_name/$1 permanent;
# Use args variable to preserve query strings
rewrite ^/search/(.+)$ /search.php?q=$1&$args last;
# Use host variable for multi-domain handling
rewrite ^/(.*)$ /$host/$1 break;
}
Map Module Integration
Combine rewrite rules with the map module for complex logic:
http {
map $uri $new_uri {
~^/old-category/(.+)$ /category/$1;
~^/old-product/(.+)$ /product/$1;
default $uri;
}
server {
listen 80;
server_name example.com;
location / {
if ($new_uri != $uri) {
rewrite ^ $new_uri permanent;
}
}
}
}
Integration with Upstream Servers
When working with application servers or microservices:
upstream backend {
server 127.0.0.1:3000;
server 127.0.0.1:3001;
}
server {
listen 80;
server_name api.example.com;
location /api/ {
# Rewrite before proxying
rewrite ^/api/v([0-9]+)/(.*)$ /$1/$2 break;
proxy_pass http://backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
Security Considerations
Rewrite rules can introduce security vulnerabilities if not properly configured:
- Always validate and sanitize captured groups
- Avoid exposing internal file paths or sensitive directories
- Use whitelist approaches rather than blacklist patterns
- Be cautious with user-controlled input in rewrites
# SECURE - Whitelist specific patterns
rewrite ^/user/([a-zA-Z0-9_-]{3,20})/?$ /profile.php?user=$1 last;
# INSECURE - Allows any input
rewrite ^/user/(.*)$ /profile.php?user=$1 last;
For production deployments, especially on VPS or dedicated servers, always test rewrite rules thoroughly in a staging environment before applying them to live traffic.
For additional reference and advanced configuration options, consult the official Nginx rewrite module documentation and the comprehensive server names guide.

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.