Nginx causes 301 redirect if there's no trailing slash
I'm running nginx in a Virtual Machine using NAT and I'm having redirection issues when I access it from the host machine.
Works as expected
-
http://localhost:8080/test/index.htm
: works. -
http://localhost:8080/test/
: works.
Doesn't work as expected
-
http://localhost:8080/test
: redirects tohttp://localhost/test/
. This is not what I want. (notice it strips the port number)
What I've tried
Based on what I've googled, I tried server_name_in_redirect off;
and rewrite ^([^.]*[^/])$ $1/ permanent;
, both with no success.
My default.conf:
server {
listen 80;
server_name localhost;
# server_name_in_redirect off;
location / {
root /usr/share/nginx/html;
index index.html index.htm index.php;
}
location ~ \.php$ {
# rewrite ^([^.]*[^/])$ $1/ permanent;
root /usr/share/nginx/html;
try_files $uri =404;
#fastcgi_pass 127.0.0.1:9000;
fastcgi_pass unix:/tmp/php5-fpm.sock;
fastcgi_index index.php;
include fastcgi_params;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
I posted a possible solution to this problem on serverfault; reproduced here for convenience:
If I understand the question correctly, you want to automatically serve, without using a 301 redirect, http://example.com/foo/index.html when the request is for http://example.com/foo with no trailing slash?
Basic solution that works for me
If so I've found this try_files configuration to work:
try_files $uri $uri/index.html $uri/ =404;
- The first
$uri
matches the uri exactly- The second
$uri/index.html
matches a directory containing the index.html where the last element of the path matches the directory name, with no trailing slash- The third
$uri/
matches the directory- The fourth
=404
returns the 404 error page if none of the preceding patterns match.
Taken from Serverfault answer
My updated version
If you add in the server
block:
index index.html index.htm;
And modify try_files
to look like this:
try_files $uri $uri/ =404;
It should work too.
A somewhat simpler solution, that worked for me, is to disable absolute redirects with absolute_redirect off;
as in the following example:
server {
listen 80;
server_name localhost;
absolute_redirect off;
location /foo/ {
proxy_pass http://bar/;
}
If I run curl on on http://localhost:8080/foo
, I can see that the Location
header in the redirect HTTP response is given as /foo/
and not http://localhost/foo/
.
$ curl -I http://localhost:8080/foo
HTTP/1.1 301 Moved Permanently
Server: nginx/1.13.8
Date: Tue, 03 Apr 2018 20:13:28 GMT
Content-Type: text/html
Content-Length: 185
Connection: keep-alive
Location: /foo/
From that, I assume any web-browser would do the right thing with the relative location. Tested on Chrome and it works fine.
try :
server {
listen 80;
server_name localhost;
location / {
root /usr/share/nginx/html;
index index.html index.htm index.php;
if (-d $request_filename) {
rewrite [^/]$ $scheme://$http_host$uri/ permanent;
}
}
}