# Try\_files and location blocks

**URL:** <https://www.ruby-forum.com/t/try-files-and-location-blocks/208674>\
**Category:** NGINX\
**Created:** [June 23, 2011, 11:37pm UTC](https://www.ruby-forum.com/t/try-files-and-location-blocks/208674 "2011-06-23T23:37:46Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![dubstep](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/cdc98d/32.png) [@dubstep](https://www.ruby-forum.com/u/dubstep)\
**Post date:** [June 23, 2011, 11:37pm UTC](https://www.ruby-forum.com/t/try-files-and-location-blocks/208674/1 "2011-06-23T23:37:46Z")

</div>

Hello. 🙂 Could someone please correct my understanding of location  
blocks and try files? I’m trying to get http errors to be very graceful,  
normally being handled by php but in extreme cases returning the proper  
numeric error. For my example, just consider 404:

server {  
…  
try\_files $uri $uri/ /error.php?c=404

```
 error_page 404 = @error_404;
 location @error_404 {
     try_files /error.php @not_found;
     rewrite ^ $scheme://$server_name/error.php?c=404
 }
 location @not_found {
     return 404;
 }

```

}

I’m not clear why this does not work. I rewrite the above example  
as:

server {  
…  
location / {  
try\_files $uri $uri/ /error.php?c=404;  
}

```
 location /error.php {
    try_files /error.php @not_found;
 }

 error_page 404 = @not_found;
 location @not_found {
     return 404;
 }

```

}

and it appears to work. I think the downside of this is that  
I have to have the location /error.php explicitly invoke php.

While I enjoy hacking at something, I also enjoy understanding something  
just as well. So what am I confused about?

## Thanks in advance.

Dave H. - Consultant - Altadena CA, USA - removed\_email\_address@domain.invalid

> > > The opinions expressed above are entirely my own \<\<\<

“That’s a very dangerous lake, Nasrudin. People who swim in  
it are always being found dead at the bottom.”

“That’s alright, friend”, replied Nasrudin. “I’ll keep well  
away from the bottom…”

---

<div class="post-metadata">

**Author:** ![daveh](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/85e7bf/32.png) [@daveh](https://www.ruby-forum.com/u/daveh)\
**Post date:** [June 24, 2011, 12:03am UTC](https://www.ruby-forum.com/t/try-files-and-location-blocks/208674/2 "2011-06-24T00:03:42Z")

</div>

On 23 Jun 2011 22h37 WEST, [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> Hello. 🙂 Could someone please correct my understanding of location  
> blocks and try files? I’m trying to get http errors to be very  
> graceful, normally being handled by php but in extreme cases  
> returning the proper numeric error. For my example, just consider  
> 404:

My take on it.

> return 404;  
> }  
> }

There are no “regular” locations, meaning, regex or others. Only  
“special” named locations. They must be invoked explicitly in your  
config.

NGX\_HTTP\_TRY\_FILES\_PHASE happens at server level. Tries to serve the  
requested  
URI either as a file or a dir. Fallbacks to error.php with arg c=404;

If the file is not found then signals a 404, error\_page directive  
redirects to @error\_404 location.

@error\_404 location runs rewrite phase directive, rewriting to  
$scheme://$server\_name/error.php?c=404

Try files phase runs again and serves the URI /error.php with arg c=404.

> try\_files /error.php @not\_found;  
> }
> 
> error\_page 404 = @not\_found;  
> location @not\_found {  
> return 404;  
> }  
> }

Now the processing will try to find a matching location. If none is  
found than use the ‘/’ “catch-all” location.

Any URI != error.php will be served by handlers you have specified in  
the ‘/’ location and those that are inherited from outside (the rule  
with some exceptions).

In this case runs the try\_files directive like above, fallbacks to  
error.php with arg c=404.

Now enters /error.php location, runs try\_files again, tries error.php  
fallbacks to @not\_found. Location @not\_found runs rewrite phase  
directive return 404. Status 404 is returned. No more processing here.

Note that the error\_page directive is only invoked if you don’t have  
the error.php file in place. Otherwise it will never run.

> and it appears to work. I think the downside of this is that  
> I have to have the location /error.php explicitly invoke php.
> 
> While I enjoy hacking at something, I also enjoy understanding  
> something just as well. So what am I confused about?

HTH,  
— appa

PS: You can verify this flow in your error log by using the debug flag  
with the error\_log directive.

---

<div class="post-metadata">

**Author:** ![daveh](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/85e7bf/32.png) [@daveh](https://www.ruby-forum.com/u/daveh)\
**Post date:** [June 24, 2011, 12:11am UTC](https://www.ruby-forum.com/t/try-files-and-location-blocks/208674/3 "2011-06-24T00:11:07Z")

</div>

On 23 Jun 2011 23h02 WEST, [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> Note that the error\_page directive is only invoked if you don’t have  
> the error.php file in place. Otherwise it will never run.

Oops. Should be:

Note that the error\_page directive is only redirects to @not\_found  
if you don’t have the error.php file in place. Otherwise the  
redirect to @not\_found will never run.

— appa

---

<div class="post-metadata">

**Author:** ![daveh](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/85e7bf/32.png) [@daveh](https://www.ruby-forum.com/u/daveh)\
**Post date:** [June 24, 2011, 12:19am UTC](https://www.ruby-forum.com/t/try-files-and-location-blocks/208674/4 "2011-06-24T00:19:44Z")

</div>

On 23 Jun 2011 23h09 WEST, removed\_email\_address@domain.invalid wrote:

Also your later config could be simplified:

server {  
…  
location / {  
try\_files $uri $uri/ /error.php?c=404 =404;  
}  
}

— appa

---

<div class="post-metadata">

**Author:** ![daveh](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/85e7bf/32.png) [@daveh](https://www.ruby-forum.com/u/daveh)\
**Post date:** [June 24, 2011, 12:30am UTC](https://www.ruby-forum.com/t/try-files-and-location-blocks/208674/5 "2011-06-24T00:30:14Z")

</div>

Thanks very much for looking at this.

[removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) writes:

> Also your later config could be simplified:  
> server {  
> …  
> location / {  
> try\_files $uri $uri/ /error.php?c=404 =404;  
> }  
> }

Where is this “=” notation documented? That try\_files line looks exactly  
like what I’m trying to do and appears much more elegant.

I was under some impression that try\_files could not take arguments with  
a URI, which may be an assumption based on the name of the directive.  
It’s not really documented that try\_files can do this either, unless  
I’m looking in the wrong place?

[GitHub - nginxinc/nginx-wiki: ARCHIVED -- Source for the now archived NGINX Wiki section of https://www.nginx.com · GitHub](http://wiki.nginx.org/CoreModule#try_files)

Right?

## Finally, exactly what happens if you have location blocks but none of them match and you haven’t specified a default?

Dave H. - Consultant - Altadena CA, USA - [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)

> > > The opinions expressed above are entirely my own \<\<\<

It is only knowledge that will destroy bias.

---

<div class="post-metadata">

**Author:** ![daveh](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/85e7bf/32.png) [@daveh](https://www.ruby-forum.com/u/daveh)\
**Post date:** [June 24, 2011, 1:01am UTC](https://www.ruby-forum.com/t/try-files-and-location-blocks/208674/6 "2011-06-24T01:01:41Z")

</div>

On 23 Jun 2011 23h46 WEST, [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> [Модуль ngx\_http\_core\_module](http://sysoev.ru/nginx/docs/http/ngx_http_core_module.html#try_files)
> 
> Use google translate 🙂 Yes it’s missing from the wiki ☹

It’s no longer missing. Feel free to improve it.

> **[GitHub - nginxinc/nginx-wiki: ARCHIVED -- Source for the now archived NGINX Wiki...](https://github.com/nginxinc/nginx-wiki)**
>
> ARCHIVED -- Source for the now archived NGINX Wiki section of https://www.nginx.com

— appa

---

<div class="post-metadata">

**Author:** ![daveh](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/85e7bf/32.png) [@daveh](https://www.ruby-forum.com/u/daveh)\
**Post date:** [June 24, 2011, 12:48am UTC](https://www.ruby-forum.com/t/try-files-and-location-blocks/208674/7 "2011-06-24T00:48:07Z")

</div>

On 23 Jun 2011 23h29 WEST, [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> Where is this “=” notation documented? That try\_files line looks  
> exactly like what I’m trying to do and appears much more elegant.

> **[Модуль ngx\_http\_core\_module](http://nginx.org/ru/docs/http/ngx_http_core_module.html)**

Use google translate 🙂 Yes it’s missing from the wiki ☹

> I was under some impression that try\_files could not take arguments  
> with a URI, which may be an assumption based on the name of the  
> directive. It’s not really documented that try\_files can do this  
> either, unless I’m looking in the wrong place?

It’s explicitly stated in the wiki that you _must_ specify the args  
because in the try\_files directive they’re not preserved as opposed to  
what happens in a rewrite directive.

> [GitHub - nginxinc/nginx-wiki: ARCHIVED -- Source for the now archived NGINX Wiki section of https://www.nginx.com · GitHub](http://wiki.nginx.org/CoreModule#try_files)
> 
> Right?

Yep.

> Finally, exactly what happens if you have location blocks but none  
> of them match and you haven’t specified a default?

You should get a 404.

— appa

---

<div class="post-metadata">

**Author:** ![daveh](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/85e7bf/32.png) [@daveh](https://www.ruby-forum.com/u/daveh)\
**Post date:** [June 24, 2011, 8:15pm UTC](https://www.ruby-forum.com/t/try-files-and-location-blocks/208674/8 "2011-06-24T20:15:38Z")

</div>

[removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) writes:

> Also your later config could be simplified:  
> server {  
> …  
> location / {  
> try\_files $uri $uri/ /error.php?c=404 =404;  
> }  
> }

In this case, it seems to me that try files is looking for a file  
named “/error.php?c=404” and not “/error.php”. Try\_files does not  
appear to strip the arguments from the uri when trying. My evidence  
for this is this debug line:

2011/06/24 03:11:58 [debug] 20773#0: \*1 try to use file:  
“/error.php?c=403?”  
“/home/www/testhome/error.php?c=403?”

This means that I can’t see if error.php exists before I try to throw an  
error with it. Right now it seems that my solution is:

location / {  
try\_files $uri $uri/ =404;  
}

location ~ .php$ {  
\<..fastcgi stuff..\>  
}

error\_page 404 = /error.php?c=404;

location = /error.php {  
try\_files /error.php @low\_level\_404  
\<..the -same- fastcgi stuff as above..\>  
}

location @low\_level\_404 {  
return 404;  
}

I am really trying hard not to use “if” but I am weakening here because  
an “if” would let me use one and only one instance of fastcgi:

location / {  
try\_files $uri $uri/ =404;  
}

location ~ .php$ {  
\<..fastcgi stuff..\>  
}

error\_page 404 = @error\_404  
location @error\_404 {  
if (! -f $document\_root/error.php) {  
return 404;  
}  
rewrite ^ $scheme://$server\_name/error.php?c=404  
}

## I’m also curious (in an academic way) as to what use case exists when try\_files has to match url arguments as a filename? I usually strongly discourage the use of ‘?’ and ‘&’ characters in a filename.

Dave H. - Consultant - Altadena CA, USA - [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)

> > > The opinions expressed above are entirely my own \<\<\<

Treat people as if they are what they ought to be, and you  
help them to become what they are capable of being.

---

<div class="post-metadata">

**Author:** ![daveh](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/85e7bf/32.png) [@daveh](https://www.ruby-forum.com/u/daveh)\
**Post date:** [June 24, 2011, 8:50pm UTC](https://www.ruby-forum.com/t/try-files-and-location-blocks/208674/9 "2011-06-24T20:50:12Z")

</div>

On 24 Jun 2011 19h14 WEST, [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> named “/error.php?c=404” and not “/error.php”. Try\_files does not  
> appear to strip the arguments from the uri when trying. My evidence  
> for this is this debug line:
> 
> 2011/06/24 03:11:58 [debug] 20773#0: \*1 try to use file:  
> “/error.php?c=403?” “/home/www/testhome/error.php?c=403?”

No. It doesn’t. Check the code. It tries a named location otherwise  
invokes ngx\_http\_split\_args(). That’s just a concise way of writing a  
debug line in the error log.

> This means that I can’t see if error.php exists before I try to  
> throw an error with it. Right now it seems that my solution is:

Yes you can.

> location = /error.php {  
> try\_files /error.php @low\_level\_404  
> \<..the -same- fastcgi stuff as above..\>  
> }

This doesn’t make sense. This is an exact location. It’s entered from  
a try\_files, a rewrite or when you request that file directly. If the  
file doesn’t exist it signals a 404.

> }
> 
> location ~ .php$ {  
> \<..fastcgi stuff..\>  
> }

No need for an if. At least that’s what I conclude from the previous  
discussion. This should be all you need for the situation you  
presented.

location / {  
try\_files $uri $uri/ /error.php?c=404 =404;  
}

location = /error.php {  
(…) # fastcgi stuff  
}

> I’m also curious (in an academic way) as to what use case exists  
> when try\_files has to match url arguments as a filename? I usually  
> strongly discourage the use of ‘?’ and ‘&’ characters in a filename.

You’re taking the peculiar way the debug line is written as the real  
way things are done.

Here’s the relevant code from the http\_core\_module.c source (starting  
at line 1241):

ngx\_log\_debug3(NGX\_LOG\_DEBUG\_HTTP, r-\>connection-\>log, 0,  
“try to use %s: "%s" "%s"”,  
test\_dir ? “dir” : “file”, name, path.data);

— appa

---

<div class="post-metadata">

**Author:** ![daveh](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/85e7bf/32.png) [@daveh](https://www.ruby-forum.com/u/daveh)\
**Post date:** [June 25, 2011, 1:03am UTC](https://www.ruby-forum.com/t/try-files-and-location-blocks/208674/10 "2011-06-25T01:03:20Z")

</div>

[removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) writes:

> No. It doesn’t. Check the code. It tries a named location otherwise  
> invokes ngx\_http\_split\_args(). That’s just a concise way of writing a  
> debug line in the error log.

Ok, I checked the code. As far as I can tell, it uses the actual  
path output in the debug line. The code only calls the split\_args()  
thing is if tf-\>lengths == NULL and tf-\>name.len == 0…and also  
if that is true then it appears to redirect:

```
    ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   "try to use %s: \"%s\" \"%s\"",
                   test_dir ? "dir" : "file", name, path.data);

    if (tf->lengths == NULL && tf->name.len == 0) {

        if (tf->code) {
            ngx_http_finalize_request(r, tf->code);
            return NGX_OK;
        }

        path.len -= root;
        path.data += root;

        if (path.data[0] == '@') {
            (void) ngx_http_named_location(r, &path);

        } else {
            ngx_http_split_args(r, &path, &args);

            (void) ngx_http_internal_redirect(r, &path, &args);
        }

        ngx_http_finalize_request(r, NGX_DONE);
        return NGX_OK;
    }
    ...
    if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, 

```

r-\>pool)  
!= NGX\_OK)  
{

If I’m correct (and I might not be) if split\_args() gets called then  
an internal redirect is done to that path.

I checked this two ways.

a) I compared the debug output of

try\_files /error.php @some\_other\_location

2011/06/24 15:40:33 [debug] 66904#0: \*1 try files phase: 11  
2011/06/24 15:40:33 [debug] 66904#0: \*1 try to use file: “/error.php”  
“/home/test/error.php”  
2011/06/24 15:40:33 [debug] 66904#0: \*1 try file uri: “/error.php”

with

try\_files /error.php?c=404 @some\_other\_location

2011/06/24 15:39:05 [debug] 66770#0: \*1 try to use file:  
“/error.php?c=403”  
“/home/test/error.php?c=403”  
2011/06/24 15:39:05 [debug] 66770#0: \*1 try to use file:  
“@real\_error\_403” “/home/test/@real\_error\_403”

b) I added to the code this:

- 

```
  ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,

```

- 

```
                  "really truly try to use %s: \"%s\" \"%s\"",

```

- 

```
                  test_dir ? "dir" : "file", name, path.data);
  if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, 

```

r-\>pool)

So it’s right above the open (which ostensibly does the file check).  
This gives me:

2011/06/24 16:00:15 [debug] 70121#0: \*1 try files phase: 11  
2011/06/24 16:00:15 [debug] 70121#0: \*1 try to use file:  
“/error.php?c=403”  
“/home/test/error.php?code=403”  
2011/06/24 16:00:15 [debug] 70121#0: \*1 really truly try to use file:  
“/error.php?c=403” “/www/home/test/website/error.php?code=403”  
2011/06/24 16:00:15 [debug] 70121#0: \*1 try to use file:  
“@real\_error\_403”  
“//home/test/@real\_error\_403”

## Even with this evidence, I don’t know the code all that well so if I’m missing something please correct me. 🙂 I am using nginx 1.0.3, maybe that is the issue?

Dave H. - Consultant - Altadena CA, USA - [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)

> > > The opinions expressed above are entirely my own \<\<\<

The concept, the label, is perpetually hiding from us all  
the nature of the real. --Joyce Cary
