96

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 to http://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;
    }

}
That Brazilian Guy
  • 3,328
  • 5
  • 31
  • 49

4 Answers4

43

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.

guiccbr
  • 650
  • 5
  • 8
  • 17
    This still returns a 301 – Dave Apr 26 '18 at 22:12
  • 1
    Here's an explanation of the issue, and an actual solution: https://serverfault.com/a/812461 – CrushedPixel May 29 '18 at 17:16
  • 6
    From my understanding the question is not actually complaining about the 301 itself. The 301 is fine, and expected, the problem is that the redirection should point to the same server name *keeping* the port 8080. – guiccbr Jul 12 '18 at 22:20
  • 2
    This works fine for me. For the extra paranoid, you can keep `absolute_redirect off` scoped to a `location {}` block if you just need it for that particular location – Avindra Goolcharan Oct 08 '18 at 17:46
  • You only need `try_files $uri $uri/index.html $uri/ =404;` in your `server` block. But make sure you test it with `curl`. Browsers cache things. So if you hit the redirect once, it could keep doing that. – anakha Sep 20 '21 at 04:54
  • `absolute_redirect off` worked for me, Took many hours to figure out what's happening. My scenario is Angular app hosted in Nginx deployed in docker container having different host and container ports. – Muhammad Ummar Sep 22 '22 at 06:54
  • 1
    This is a working solution for most cases. For me, the server is behind a proxy that terminates SSL. without `absolute_redirect off;` NGINX always redirect to `http://` because it does not know the browser is using `https://`. – Jingshao Chen Jul 28 '23 at 02:04
42

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.

Liam
  • 27,717
  • 28
  • 128
  • 190
John Weldon
  • 39,849
  • 11
  • 94
  • 127
  • @maiconsanson - it seems to work for me with subfolders. Feel free to explain further. – John Weldon Sep 03 '15 at 20:37
  • 2
    Sorry, I mean, it works but the images inside the index.html are not found. By the way, I'm using to solve this with Dokku: `if (-d $request_filename) { rewrite [^/]$ $scheme://$http_host$uri/ permanent; }` [buildpack-nginx](https://github.com/florianheinemann/buildpack-nginx/blob/master/bin/compile#L115) – maiconsanson Sep 04 '15 at 00:24
  • It's likely that the relative paths in the index.html are broken somehow. Inspect the url that the page is trying to retrieve, and compare with the url that the image is actually at, and see if the issue becomes clearer. – John Weldon Sep 04 '15 at 00:32
  • The urls is alright (`1.png` and so on). Everything is in the root app (index.html and images). – maiconsanson Sep 04 '15 at 00:45
  • Upvote++ for try_files $uri $uri/index.html $uri/ =404; logic! it worked Thanks – Abhishek May 19 '17 at 18:55
  • Thanks, this worked for me. note that my: ```location /apple-app-site-association { root /usr/share/nginx/html; index index.json; try_files $uri $uri/index.json $uri/ =404; }``` – Arthur Cinader Jan 11 '18 at 19:04
  • using `try_files` does not prevent the redirect for me. No matter what I try, nginx will redirect `/foo` to `/foo/`. Can anyone tell what I'm missing? here is my conf: https://gist.github.com/city41/26254ca3875144c153c90c4a8b1ad26a I resorted to `absolute redirect off;` and just accepted the redirect, but I'd love to avoid it if possible. This nginx server is on heroku using their buildpack if that makes any difference. – Matt Greer Aug 11 '20 at 18:09
  • 1
    Only `try_files $uri $uri/index.html $uri/ =404;` worked for me. The second solution did not. – Pete Apr 26 '21 at 17:42
12

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;
        }
    }
}
luc2
  • 547
  • 1
  • 4
  • 11
5

Try changing

server_name  localhost;
# server_name_in_redirect off;

to

server_name  localhost:8080;
server_name_in_redirect on;
Dave Turner
  • 1,846
  • 16
  • 27