I am trying to remove any trailing slashes from the url. This works everywhere except the homepage.
Here's where it works:
- sub.example.com/ => sub.example.com
- sub.example.com/test/ => sub.example.com/test
- sub.example.com/test/// => sub.example.com/test
Here's where it doesn't work:
- sub.example.com/// => sub.example.com///
My config file:
server {
server_name sub.example.com;
root /var/www/example.com/;
index index.php;
charset utf-8;
rewrite ^/(.*)/$ /$1 permanent;
location / {
try_files $uri /index.php?$query_string;
}
location ~ \.php$ {
fastcgi_pass unix:/var/run/php/php8.0-fpm.sock;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
include fastcgi_params;
}
listen 443 ssl;
#SSL settings
}
CodePudding user response:
Looks like you don't understand some very important parts going under the hood.
1. HTTP GET
request can't contain an empty string as a path.
When you type sub.example.com/
at your browser address bar, it is a browser who hides a trailing slash. This is applied only for the root requests, in any other case (including sub.example.com//
, sub.example.com/test/
, sub.example.com/test//
, etc.) you'll see the full path at the address bar. No matter if you type that slash or not, HTTP request issued by the browser will look like
GET / HTTP/1.1
Host: sub.example.com
...
2. rewrite
nginx directive works with the normalized URI.
Both location
and rewrite
directive works with so-called normalized URIs:
The matching is performed against a normalized URI, after decoding the text encoded in the “%XX” form, resolving references to relative path components “.” and “..”, and possible compression of two or more adjacent slashes into a single slash.
That means, for all the requests like sub.example.com/test/
, sub.example.com/test//
, sub.example.com/test///
, etc., nginx see the normalized request URI as /test/
(that's the reason your rewrite rule works in a single step rather than the four-step sub.example.com/test///
-> sub.example.com/test//
-> sub.example.com/test/
-> sub.example.com/test
loop).
And the same is true for any of the sub.example.com/
, sub.example.com//
, sub.example.com///
, etc. requests, the normalized URI will be seen by nginx as /
making any rewrite rule unusable.
However, slashes compression can be turned off using the merge_slashes
directive (read the security considerations). And to prevent multiply redirects where each redirect removes only a single trailing slash, use a non-greedy *
and a greedy
quantifiers for your regex pattern:
merge_slashes off;
rewrite ^(/.*?)/ $ $1 permanent;