try_files ignored in combination with error_page and named locations

Ruslan Ermilov ru at
Wed Apr 4 08:16:10 UTC 2012

On Tue, Apr 03, 2012 at 10:30:39PM +0200, Džen wrote:
> For some reason the following nginx configuration snippet doesn't work
> as expected, try_files seems to be ignored. When / is requested (or any
> other URI which points to a file which doesn't exist), nginx's default
> 503 page is returned instead of the existing index.html. Requesting
> /index.html works correctly.
> 	location @maintenance {
> 		root		/var/nginx/$hostid-maintenance;
> 		index		index.html;
> 		try_files	$uri $uri/ / =500;
> 	}
> 	error_page 503 @maintenance;
> 	if ( -d $document_root/$hostid-maintenance ) {
> 		return 503;
> 	}
> Any thoughts? Running nginx version 1.0.12 here.

First, this is a wacky config, and I don't quite understand what
you're trying to achieve with it.  :)

Here's what happens with the request of "/", assuming that "if"
condition holds true.

The status code is set to 503, and further processing happends in
the named location @maintenance.

It tries "$uri", find that directory, but because argument does
not end with a slash (i.e., we're testing a file, not directory),
this variant is ignored.

It then tries "$uri/", and succeeds.  $uri is set to
"/$hostid-maintenance/".  As documentation of "try_files" says,
the further processing is done in thi same (named) location.

What happens next is since a request now ends with a slash, the
static module handler ignores it, and a request is processed by
the index module.  The index module then verifies that the
"/var/nginx/$hostid-maintenance/index.html" file exists and does
an internal redirect to a new $uri.  (The fact that it does an
internal redirect is also documented.)

This in turn gets processed by the server's default location
which is configured to return 503.  Because
"recursive_error_pages" aren't enabled, the server ends up
returning status code 503 with the standard content.

(What happens when you enable is left as an excercise to a

When OTOH you request "/index.html", try_files checks that the
_file_ exists, and the processing is performed by the static
module in the context of location @maintenance.  There are no
more internal redirects involved, so the server ends up sending
you the status code 503 with the contents of index.html.

I agree that this might not be obvious, but this is how it works.

The important bit here is that requests that end up with "/", and
get processed by the index module, do an internal redirect.  This
is quite logical if you think about it, because they *usually*
get processed by the static module, as if a request ended up with
"/" followed by the name of index file.

More information about the nginx mailing list