Nginx – Using nginx try_files and custom error pages for the main location block

http-status-code-404nginx

When using try_files in nginx, is there a way to specify and use a custom error_page only after it has tried each URI specified in the try_files directive?

The below configuration does not work:

location / {   
    if (-f $document_root/error_page.html ) {
        error_page 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 495 496 497 500 501 502 503 504 505 506 507 /error_page.html;
    }
    try_files $uri $uri/ @redirect_store;
}

It would seem that if you use an error_page directive, when nginx can't find the passed in URI, it immediately returns the custom 404 error page instead of trying the next entry in try_files. It seems that the error_page directive overrides try_files?

I can only get this to work when no error_page directive is specified:

location / {   
    try_files $uri $uri/ @redirect_store;
}

But in the above case, if each entry is tried and it's still not found, it returns the default 404 error page, but I want it to return a custom one.

Anyone know how to achieve this, or is it not possible? Is this a bug in nginx? I should be able to use a custom error_page with try_files assuming a URI was not found in any of the try_files entries.

To summarize, try_files does not go through the chain of entries if the error_page directive is specified.

Best Answer

There are two problems with what you are trying to do:

  • the if block is not behaving as you would like
  • any 404 response is unlikely to originate from within your location / block

This document explains why the if block should only be used in very specific situations.

The final action of your location / block is to call the named location @redirect_store. If any 404 response is generated, it is likely to occur after processing has left the location / block. Therefore any error_page directive declared only within the location / block's scope will be ignored (irrespective of the if block issues noted above).

The final line of the error_page document states that:

If uri processing leads to an error, the status code of the last occurred error is returned to the client.

Which means that your protective if statement is unnecessary anyway.

Try this instead:

error_page 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 495 496 497 500 501 502 503 504 505 506 507 /error_page.html;

location / {   
    try_files $uri $uri/ @redirect_store;
}