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?