When accessing foobar.com/test
, Nginx automatically issues a 301 redirect to foobar.com/test/
before the request reaches your backend Apache server. This happens because:
- Nginx's default behavior treats directories differently than files
- Your configuration has separate
location
blocks for both variants - The proxy setup doesn't properly preserve the original URI formatting
The root cause lies in how Nginx processes location matching when acting as a reverse proxy. Unlike direct Apache access where the server handles the URI as-is, Nginx applies normalization rules before proxying.
In your current configuration:
location /test {
proxy_pass http://1.1.1.1:80/;
# other proxy settings...
}
location /test/ {
proxy_pass http://1.1.1.1:80/;
# other proxy settings...
}
Nginx sees these as distinct endpoints and prefers the trailing-slash version for directory-like paths.
Here are three proven approaches to eliminate the unwanted redirect:
Option 1: Unified Location Block
Combine both variants into a single regex-based location:
location ~ ^/test(/|$) {
proxy_pass http://1.1.1.1:80;
proxy_redirect off;
# preserve other proxy settings...
}
The regex matches both /test
and /test/
without redirection.
Option 2: Absolute URI in proxy_pass
Modify the proxy_pass directive to include the full path:
location /test {
proxy_pass http://1.1.1.1:80$request_uri;
proxy_redirect off;
# other settings...
}
This preserves the exact request URI including the slash presence.
Option 3: Disable Directory Processing
Add this directive to prevent Nginx from treating paths as directories:
location /test {
proxy_pass http://1.1.1.1:80/;
proxy_redirect off;
absolute_redirect off;
# other settings...
}
The absolute_redirect off
prevents canonical URL formation.
After making changes, verify with:
nginx -t
curl -I http://foobar.com/test
You should see either a 200 response or a proxy to your backend without 301 redirects.
Each solution has different implications:
- Regex locations have slightly higher CPU overhead
- Absolute URIs in proxy_pass may reveal backend structure
- Disabling directory processing might affect other legitimate redirects
For most proxy setups, Option 2 provides the best balance of simplicity and reliability.
When working with Nginx as a reverse proxy, you might encounter automatic 301 redirects that add trailing slashes to URIs. This happens because Nginx's default behavior treats /test
and /test/
differently:
# Default behavior:
foobar.com/test → 301 → foobar.com/test/
Your observation is correct - Apache doesn't automatically redirect URIs without trailing slashes. This is because:
- Apache's DirectorySlash directive defaults to On but handles things differently
- Nginx's location matching rules are more strict about URI termination
The problem stems from how Nginx handles location blocks. In your current setup:
location /test {
# This matches '/test' but not '/test/'
proxy_pass http://1.1.1.1:80/;
}
location /test/ {
# This matches '/test/' but not '/test'
proxy_pass http://1.1.1.1:80/;
}
Nginx sees these as two distinct locations and applies its default normalization rules.
Here's the proper way to handle this proxy scenario:
server {
listen 80;
server_name fooBar.com;
# Combined location that handles both cases
location ~ ^/test(/|$) {
proxy_redirect off;
proxy_pass http://1.1.1.1:80/;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-Host $http_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;
}
}
If you're dealing with static files rather than proxying, you could use:
location /test {
autoindex off;
try_files $uri $uri/ =404;
}
After making changes, always:
- Test syntax:
nginx -t
- Reload config:
nginx -s reload
- Verify with curl:
curl -I http://foobar.com/test
The response should show HTTP 200 instead of 301 when the trailing slash is omitted.