nginx infinite loop with try_files and index

gdbj asked:

using the following config for Nginx, I’m noticing I get an infinite loop of location processing. Based on my understanding from the docs, I’d expect a request to http://localhost:8080 to simply return my index.html file based on my index directive. Instead the request maps to location / in a loop, appending a / each time, based on what I can see from my X-debug header. The output from my debugging message is:

X-debug-one:location / /////////// /var/www/content

As you can see, the $uri keeps growing for a few iterations. What’s the point of the index directive if it isn’t respected? I would expect the index to be tested at some point in the process?

Here’s my config. I must be missing something obvious here. Just a note, this is running from inside a Docker container, with port mapping to 8080.

server {
  server_name _;
  listen 80 default_server;

  root /var/www/content;
  index index.html;

  access_log /dev/stdout;
  error_log /dev/stdout info;

  add_header X-debug-base "base $uri $document_root" always;

  location / {
    add_header X-debug-one "location / $uri $document_root" always;
    try_files $uri $uri/;
  }
}

Edit:

Here’s the response from curl (curl -sSL -D – “localhost:8080” -o /dev/null) from both outside Docker (localhost:8080), and inside docker (localhost:80)

HTTP/1.1 500 Internal Server Error
Server: nginx/1.10.3
Date: Sat, 06 Jan 2018 22:55:35 GMT
Content-Type: text/html
Content-Length: 193
Connection: close
X-debug-one: location / /////////// /var/www/content

Here are the logs, capturing my curl and I think there’s a Chrome request there too.

unyozi_1    | 2018-01-06 22:57:23,869 DEBG 'nginx' stdout output:
unyozi_1    | 127.0.0.1 - - [06/Jan/2018:22:57:23 +0000] "GET / HTTP/1.1" 500 193 "-" "curl/7.52.1"
unyozi_1    | 
unyozi_1    | 2018-01-06 22:57:37,722 DEBG 'nginx' stdout output:
unyozi_1    | 2018/01/06 22:57:37 [error] 11#0: *13 rewrite or internal redirection cycle while internally redirecting to "////////////", client: 127.0.0.1, server: _, request: "GET / HTTP/1.1", host: "localhost"
unyozi_1    | 
unyozi_1    | 2018-01-06 22:57:37,722 DEBG 'nginx' stdout output:
unyozi_1    | 127.0.0.1 - - [06/Jan/2018:22:57:37 +0000] "GET / HTTP/1.1" 500 193 "-" "curl/7.52.1"
unyozi_1    | 
unyozi_1    | 2018-01-06 22:58:43,546 DEBG 'nginx' stdout output:
unyozi_1    | 2018/01/06 22:58:43 [error] 11#0: *14 rewrite or internal redirection cycle while internally redirecting to "/sockjs-node/info///////////", client: 172.19.0.1, server: _, request: "GET /sockjs-node/info?t=1515279507454 HTTP/1.1", host: "localhost:8080", referrer: "http://localhost:8080/"
unyozi_1    | 
unyozi_1    | 2018-01-06 22:58:43,547 DEBG 'nginx' stdout output:
unyozi_1    | 172.19.0.1 - - [06/Jan/2018:22:58:43 +0000] "GET /sockjs-node/info?t=1515279507454 HTTP/1.1" 500 595 "http://localhost:8080/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36"
unyozi_1    | 

My answer:


The problem is here:

    try_files $uri $uri/;

Adding a / to the end of an argument in try_files causes it to try that URL with the paths specified in the index directive, in your case index.html.

When you load /, try_files first tries $uri, which doesn’t match, then it gets to $uri/ and tries /index.html, which re-enters the same location block. Because index.html doesn’t exist, it gets to $uri/ again, goes back to try /index.html again, re-enters the location block, and gives you the rewrite or internal redirection cycle error.

To fix this, specify a reasonable default for when a static file is not found in your try_files. If you have a static-only site, this could be =404. If you are going to run a web app, then it could be a location for that app. For example:

    try_files $uri $uri/ =404;        # Static site
    try_files $uri $uri/ /index.php;  # PHP front controller
    try_files $uri $uri/ @uwsgi;      # pass to a named location

View the full question and answer on Server Fault.

Creative Commons License
This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.