When working with Nginx as a reverse proxy, a common requirement is to forward requests from one path to a different backend service while modifying the request path. The key challenge emerges when you need to remove or rewrite parts of the original URI during the proxy pass.
Consider this common but problematic configuration:
location /route {
proxy_pass http://127.0.0.1:9000;
}
This forwards http://localhost/route/abc
to http://localhost:9000/route/abc
when what we actually want is http://localhost:9000/abc
.
Here are three effective approaches to solve this routing issue:
1. Using URI Rewriting in Location Block
location /route/ {
rewrite ^/route/(.*) /$1 break;
proxy_pass http://127.0.0.1:9000;
}
2. Proxy Pass with Trailing Slash
location /route/ {
proxy_pass http://127.0.0.1:9000/;
}
Note the crucial trailing slash after both the location and proxy_pass URLs.
3. Advanced Regex Matching
location ~ ^/route/(?.*)$ {
proxy_pass http://127.0.0.1:9000/$path;
}
When implementing these solutions:
- Always include the trailing slash in both location and proxy_pass for consistency
- Test with various path depths to ensure proper rewriting
- Consider adding proxy headers for better debugging:
proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
Here's a complete working configuration for a Node.js application:
server {
listen 80;
server_name localhost;
location /api/ {
proxy_pass http://127.0.0.1:3000/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
}
When working with Nginx's proxy_pass
directive, a common requirement is to forward requests while stripping a specific path prefix. The default behavior preserves the original URI path, which isn't always what we want.
With this configuration:
location /route {
proxy_pass http://127.0.0.1:9000;
}
A request to http://localhost/route/abc
gets forwarded to http://localhost:9000/route/abc
, maintaining the /route
prefix.
To remove the /route
prefix before forwarding, use one of these approaches:
Method 1: Regex Location with Capture Group
location ~ ^/route(/.*)$ {
proxy_pass http://127.0.0.1:9000$1;
}
Method 2: Rewrite Directive
location /route {
rewrite ^/route(.*)$ $1 break;
proxy_pass http://127.0.0.1:9000;
}
Here's a full server block demonstrating the solution:
server {
listen 80;
server_name localhost;
# Option 1: Regex location
location ~ ^/route(/.*)$ {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_pass http://127.0.0.1:9000$1;
}
# Option 2: Rewrite + prefix location
location /alt-route/ {
rewrite ^/alt-route(/.*)$ $1 break;
proxy_pass http://127.0.0.1:9000;
}
}
When implementing this solution:
- Always include
proxy_set_header Host $host
for proper header forwarding - Use the
break
flag with rewrite to prevent further rewrites - Test with trailing slashes in both original and target paths
- Consider adding
proxy_redirect
if the backend generates redirects
Both methods automatically preserve query strings. For example:
# Request: /route/abc?param=value
# Becomes: http://127.0.0.1:9000/abc?param=value