2

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 either server or location block.
  • I have tried error_page with proxy_intercept_errors on in the location or server block;

None of them appear to persuade nginx to display my error page. Why not? What have I missed?

2
  • Post the complete server block. – Michael Hampton Apr 4 '15 at 20:17
  • @MichaelHampton Thx, I figured it out finally, please see if there are any flaws in my answer. – bitinn Apr 5 '15 at 7:22
6

Thanks Justin and Michael for pointing me in the right direction, it indeed is a location block causing my troubles, in particular:

location / {
    try_files   $uri $uri/ @server;
    error_page  403 = @server;
}

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 your root) 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 same location 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.

error_page 502 /error-502.html;

location = /error-502.html {
    internal;
    root /srv/example.com/html;
}

location = / {
    try_files $uri @server;
}

location / {
    try_files $uri $uri/ @server;
}
1

It's tough to say for sure without seeing your entire configuration, because this works for me without any of the extra measures you've taken. I first tried all of your config, then stripped away bits one by one to see if anything changed.

It shouldn't be necessary to use proxy_intercept_errors, because the 502 is generated by nginx itself when it fails to connect to the backend. I confirmed that this worked for me with this set and unset.

All I've added, inside of my server block is:

error_page 502 /error-502.html;

location = /error-502.html {
  internal;
  root /srv/www/errors;
}

In my setup, my static error pages are in /srv/www/errors, but nothing else is different.

You must have configuration elsewhere that is server-wide or in your server block which interferes or overrides. Pay attention to the precedence rules for locations, that could be a factor.

1
  • Thx, I figured it out finally, please see if there are any flaws in my answer. – bitinn Apr 5 '15 at 7:22

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.