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?
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With