When implementing reverse proxies in Nginx, a common requirement is to strip away a URL prefix before forwarding requests to backend services. Here's the standard scenario:
location /foo {
proxy_pass http://localhost:3200;
proxy_redirect off;
proxy_set_header Host $host;
}
This configuration forwards /foo/bar
to the backend as /foo/bar
, but many applications expect the path without the prefix.
Many developers first try using rewrite
with permanent flags:
rewrite ^(.*)foo(.*)$ http://localhost:3200/$2 permanent;
This creates unwanted 302/301 redirects instead of internal path processing. The client sees the URL change in their browser - not what we want for API endpoints or web apps.
For seamless prefix removal without redirects, use this pattern:
location /foo {
proxy_pass http://localhost:3200/; # Note trailing slash
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
The magic happens with:
proxy_pass
with trailing slash: strips the matched prefix- No
rewrite
rules needed - Preserves original request headers
For more complex patterns, use regex locations:
location ~ ^/foo(/.*)?$ {
proxy_pass http://backend:3200$1;
# Additional proxy settings...
}
Verify with curl
:
curl -v http://localhost/foo/api/test
Check that:
- The response comes directly (no 301/302)
- Your backend receives
/api/test
- Original headers are preserved
When setting up Nginx as a reverse proxy, you might encounter situations where you need to remove a path prefix before forwarding requests to your backend application. The common approach using rewrite
with permanent
flag results in a 302 redirect, which isn't always desirable.
The rewrite
directive with the permanent
flag (or its numeric equivalent 301) is designed to tell clients to make a new request to the rewritten URL. This is fundamentally how HTTP redirects work.
Instead of using rewrite
, we can leverage Nginx's proxy_pass
with URI manipulation:
location /foo {
proxy_pass http://localhost:3200/;
proxy_redirect off;
proxy_set_header Host $host;
}
The key difference is the trailing slash after the proxy_pass URL. This tells Nginx to replace the matched prefix (/foo) with the specified URI (/).
Here's a more complete example with additional common proxy settings:
server {
listen 80;
server_name example.com;
location /foo/ {
proxy_pass http://localhost:3200/;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# Optional: Timeout settings
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
}
}
After making changes, always test your configuration:
sudo nginx -t
sudo systemctl reload nginx
Then verify with curl:
curl -v http://localhost/foo/bar
You should see the request being proxied to your backend at /bar
without any redirects.
For more complex scenarios where you need regex pattern matching, you can use:
location ~ ^/foo(/.*)$ {
proxy_pass http://localhost:3200$1;
# ... other proxy settings
}
This captures everything after /foo in $1 and passes it to the backend.
The solution using simple prefix matching (location /foo/
) is more efficient than regex-based approaches. Nginx processes prefix locations faster, especially under heavy load.