Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

nginx: fallback to try_files when proxy_pass fails requires unusual config

I am using Nginx to server a single page app. Basically we just need to serve the index.html page whenever no matching file is found. The location looks like this and has been working just fine:

location / {
   try_files $uri $uri/ /index.html
}

Now I would like to query an upstream server, and only if that fails, use the try_files directive as above

If the try_files is just moved to a fallback location like

location @fallback {
  try_files $uri $uri/ /index.html;
}

location / {
  proxy_pass http://127.0.0.1:8080;
  proxy_intercept_errors on;
  error_page 400 403 502 503 504 @fallback;
}

then - when the upstream server is unavailable - the client sees the Nginx 502 error page instead of the files served from the file system.

I finally found a solution that works by using a double slash in front of the /index.html fallback. This is the whole config file which can be used with the official nginx docker image for testing

events {
} 

http {

  error_log /var/log/nginx/error.log;
  access_log /var/log/nginx/access.log;

  server {

    listen 80;

    root /usr/share/nginx/html/;

    location / { 
      proxy_pass http://127.0.0.1:9990;
      proxy_intercept_errors on; 
      error_page 400 403 502 503 504 = @fallback;
    }

    location @fallback {
      try_files $uri?$args /index.html //index.html;
    }
  }
}

which can be run with a command like

docker run -v /path/to/www/folder:/usr/share/nginx/html:ro -v /path/to/config/nginx.conf:/etc/nginx/nginx.conf -d -p 8080:80 nginx

In case no double slash is present before the last index.html fallback like

location @fallback {
  try_files $uri?$args /index.html;
}

Then nginx constructs a path on the filesystem like <root>index.html, which has a missing delimiter instead of the correct <root>/index.html, whenever a url which is not the root url is requested.

Final question: why does this setup require a double slash within the try_files directive? Why can't one just use the try_files section from a regular config and move it to a fallback location used when intercepting errors?

like image 330
st-h Avatar asked Apr 19 '19 15:04

st-h


1 Answers

I was presented with a similar situation, and I solved this going the other way around, using the suggestion from this page of common pitfalls. That is, first serve the static files, and then fallback to the proxy:

location / {
    try_files $uri $uri/ @proxy;
}
location @proxy {
    proxy_pass http://127.0.0.1:9990;
}

In this case, this would first look for the presence of the files as static files in the root, then proxy the request to http://127.0.0.1:9000. This is functionnally equivalent unless you want the files from the proxy to shadow the static files.

like image 174
Félix Adriyel Gagnon-Grenier Avatar answered Nov 15 '22 09:11

Félix Adriyel Gagnon-Grenier