This question should have been answered a longtime ago, but I can't seem to figure it out despite reading many common answers, can someone please point out why my configuration isn't working?
Goal: when upstream server_api is down (say, its worker processes has crashed), I want nginx to display my custom error page.
My configuration:
location @server {
proxy_pass http://server_api;
proxy_redirect off;
...
proxy_intercept_errors on;
error_page 502 /error-502.html;
}
error_page 502 /error-502.html;
location = /error-502.html {
internal;
root /srv/my-server/html;
}
My steps:
- I have my static error page at
/srv/my-server/html/error-502.html
ready, same permission and owners as other static assets. - I have stopped my upstream service, and see
[error] 2359#0: *25 connect() failed (111: Connection refused) while connecting to upstream
appearing in logs. - Now I try to make my custom error page show up for 502 errors.
- I have tried setting
error_page
at both or eitherserver
orlocation
block. - I have tried
error_page
withproxy_intercept_errors on
in thelocation
orserver
block;
None of them appear to persuade nginx to display my error page. Why not? What have I missed?
Best Answer
Thanks Justin and Michael for pointing me in the right direction, it indeed is a location block causing my troubles, in particular:
Basically, I was trying to be clever and catch
$uri/
error (403 happens when you try to access a folder that exists but has no index file or auto-indexing) and redirect it to@server
block as well.But isn't
try_files $uri $uri/ @server;
alone enough?Imagine you trying to access
http://example.com/
, nginx will say, oh this folder exists (it's yourroot
) but no index found, and throw 403 instead of passing onto@server
block.Thus my 403 solution, but I didn't realize it comes with a cost: this means nginx already caught an error and used
error_page
in the samelocation
block to handle it (by passing it to@server
).Couple this with my tests in the question, it suggests nginx (v1.7.x) will ignore further
error_page
directive at this point and use default 502 instead.The interesting part: how do we workaround this?
My solution is to setup an exact matching root route instead, now catching 403 on root isn't necessary anymore, and
error_page
works as intended.