# Try\_files ignored in combination with error\_page and named locations

**URL:** <https://www.ruby-forum.com/t/try-files-ignored-in-combination-with-error-page-and-named-locations/218548>\
**Category:** NGINX\
**Created:** [April 3, 2012, 10:31pm UTC](https://www.ruby-forum.com/t/try-files-ignored-in-combination-with-error-page-and-named-locations/218548 "2012-04-03T22:31:20Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![luislavena](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/l/0ea827/32.png) [@luislavena](https://www.ruby-forum.com/u/luislavena)\
**Post date:** [April 3, 2012, 10:31pm UTC](https://www.ruby-forum.com/t/try-files-ignored-in-combination-with-error-page-and-named-locations/218548/1 "2012-04-03T22:31:20Z")

</div>

Hello,

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.

Kind regards

–  
Džen

---

<div class="post-metadata">

**Author:** ![SSDS\_enSS\_SSS](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/ed655f/32.png) [@SSDS\_enSS\_SSS](https://www.ruby-forum.com/u/SSDS_enSS_SSS)\
**Post date:** [April 4, 2012, 10:16am UTC](https://www.ruby-forum.com/t/try-files-ignored-in-combination-with-error-page-and-named-locations/218548/2 "2012-04-04T10:16:31Z")

</div>

On Tue, Apr 03, 2012 at 10:30:39PM +0200, Džen wrote:

> }
> 
> 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  
reader.)

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.

---

<div class="post-metadata">

**Author:** ![SSDS\_enSS\_SSS](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/ed655f/32.png) [@SSDS\_enSS\_SSS](https://www.ruby-forum.com/u/SSDS_enSS_SSS)\
**Post date:** [April 4, 2012, 10:48am UTC](https://www.ruby-forum.com/t/try-files-ignored-in-combination-with-error-page-and-named-locations/218548/3 "2012-04-04T10:48:47Z")

</div>

Thank you very much for your clarifying explanation. Seems like the only  
thing missing was “recursive\_error\_pages on” for it to work like I  
wanted it to have.

On 04/04/12 12:16pm, Ruslan E. wrote:

> […]
> 
> First, this is a wacky config, and I don’t quite understand what  
> you’re trying to achieve with it. 🙂

Just to make you understand what I was trying to achieve with this  
config: my maintenance page contains img tags pointing to images located  
in $document\_root. I used to add a simple

try\_files /$hostid-maintenance/ @backend;

to my configuration, but as expected a request to /foo.png returns the  
contents of /$hostid-maintenance/index.html instead. Thus I was looking  
for a solution to use a whole directory as an error page (being able to  
request other files which are located inside the maintenance  
$document\_root).

> 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.

That’s OK in my case, since the maintenance “environment” might contain  
other directories.

> 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.

I’m not really sure whether $uri is set to “/$hostid-maintenance/” if  
“$uri/” is tried (since root is set to /var/nginx/$hostid-maintenance/  
already). That works as expected and a request to / will actually just  
try / relative to $document\_root.

> returning status code 503 with the standard content.  
> Thanks, that’s what I forgot about.

> 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.

Thanks again and kind regards

–  
Džen

---

<div class="post-metadata">

**Author:** ![SSDS\_enSS\_SSS](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/ed655f/32.png) [@SSDS\_enSS\_SSS](https://www.ruby-forum.com/u/SSDS_enSS_SSS)\
**Post date:** [April 4, 2012, 11:04am UTC](https://www.ruby-forum.com/t/try-files-ignored-in-combination-with-error-page-and-named-locations/218548/4 "2012-04-04T11:04:54Z")

</div>

2012/4/4 Džen [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid):

> Just to make you understand what I was trying to achieve with this

location /maintenance-static/ {

}

location / {  
try\_files /$hostid-maintenance/ @backend;  
}

---

<div class="post-metadata">

**Author:** ![SSDS\_enSS\_SSS](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/ed655f/32.png) [@SSDS\_enSS\_SSS](https://www.ruby-forum.com/u/SSDS_enSS_SSS)\
**Post date:** [April 4, 2012, 7:28pm UTC](https://www.ruby-forum.com/t/try-files-ignored-in-combination-with-error-page-and-named-locations/218548/5 "2012-04-04T19:28:02Z")

</div>

On 04/04/2012 11:03, Edho A. wrote:  
[…]

> location /maintenance-static/ {
> 
> }
> 
> location / {  
> try\_files /$hostid-maintenance/ @backend;  
> }

Right, this would work just fine. However, requests to  
/maintenance-static/  
would still be possible even if /$hostid-maintenance/ doesn’t exist  
(minor  
problem, but maybe the backend uses /maintenance-static/ for some  
reason).

Unfortunately, I still haven’t found a solution which pleases me. Just  
to  
clarify, this is how I want the request to be processed (el-cheapo  
pseudo  
code):

if the directory /maintenance/ exists, then  
set root to /maintenance/  
if the file $uri exists, then  
serve $uri with errcode 503  
otherwise  
serve index.html with errcode 503  
otherwise  
proxy\_pass [http://backend](http://backend)

My new attempt:

recursive\_error\_pages on;  
error\_page 599 @maintenance;

if ( -d $document\_root/$hostid-maintenance ) {  
return 599;  
}

location @maintenance {  
root /var/nginx/$hostid-maintenance;  
index index.html;  
try\_files $uri $uri/ /index.html /;  
}

I used error code 599 because I noticed that for some reason the backend  
might  
raise an 503 error although $document\_root/$hostid-maintenance doesn’t  
exist.  
The result in such a situation would be unexpected (an infinite redirect  
loop?).  
By using an unused error code like 599, nginx’s default 503 error page  
will be  
displayed instead, if the backend raises 503.

This configuration seems to work, but the 599 error code in the HTTP  
header  
isn’t that nice. Unfortunately, something like

error\_page 599 =503 @maintenance;

doesn’t result in what I expected (it will again just return nginx’s  
default  
503 error page, although error 503 is correctly set in the HTTP header).

I still think that I misunderstood something, am I right?

Kind regards

–  
Džen
