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. Apr 4, 2015 at 20:17
  • @MichaelHampton Thx, I figured it out finally, please see if there are any flaws in my answer.
    – bitinn
    Apr 5, 2015 at 7:22

2 Answers 2

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, 2015 at 7:22

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .