124

I looked at the nginx documentation and it still confuses me utterly.

How does try_files work? Here is what the documentation says:

From NginxHttpCoreModule

try_files

syntax: try_files path1 [path2] uri

default: none

context: server, location

availability: 0.7.27

Checks for the existence of files in order, and returns the first file that is found. A trailing slash indicates a directory - $uri /. In the event that no file is found, an internal redirect to the last parameter is invoked. The last parameter is the fallback URI and must exist, or else an internal error will be raised. Unlike rewrite, $args are not automatically preserved if the fallback is not a named location. If you need args preserved, you must do so explicitly:

I don't understand how it checks the paths and what if I don't want an internal error but have it resume the rest of the path in an effort to find another file?

If I want to try a cached file at /path/app/cache/url/index.html and if it fails to try /path/app/index.php how would I write that? If I wrote:

try_files /path/app/cache/ $uri
include /etc/nginx/fastcgi_params;
fastcgi_pass unix:/var/run/php-fastcgi/php-fastcgi.socket;
fastcgi_param SCRIPT_FILENAME $document_root/index.php;

I have index index.php index.html index.htm;. When I visit /urlname, will it try checking /path/app/cache/urlname/index.php then /path/app/cache/urlname/index.html? If we ignore everything after try_files is it possible for try_files to check the cache folder? I have been trying and have failed.

2 Answers 2

104

try_files tries the literal path you specify in relation to the defined root directive and sets the internal file pointer. If you use for instance try_files /app/cache/ $uri @fallback; with index index.php index.html; then it will test the paths in this order:

  1. $document_root/app/cache/index.php
  2. $document_root/app/cache/index.html
  3. $document_root$uri

before finally internally redirecting to the @fallback named location. You can also use a file or a status code (=404) as your last parameter but if using a file it must exist.

You should note that try_files itself will not issue an internal redirect for anything but the last parameter. Meaning you cannot do the following: try_files $uri /cache.php @fallback; as that will cause nginx to set the internal file pointer to $document_root/cache.php and serve it, but since no internal redirect takes place the locations aren't re-evaluated and as such it will be served as plain text. (The reason it works with PHP files as the index is that the index directive will issue an internal redirect)

7
  • 4
    That is MUCH more clear. Thanks. I'm a little unsure how the named location works. If @fallback has lines for fastcgi php that would serve it as a php file rather then text? Is fallback used when everything before it fails?
    – user274
    Commented Nov 11, 2011 at 5:13
  • 5
    A named location is just functionally identical to a normal location except it can only be accessed via internal mechanisms such as error_page and try_files. The fallback in try_files is only used when none of the specified paths result in a valid file. You still need a location to catch \.php$ URIs as otherwise try_files will trigger on $uri if the file exist and serve it as plain-text. Commented Nov 11, 2011 at 20:33
  • 1
    Thank you for this answer .. I still have a question here : Is try_files executed right away or will nested location be tried before ?
    – Stphane
    Commented Jan 6, 2016 at 23:20
  • 1
    @Stphane You are moving into murky waters here. Inheritance in nginx is complex, messy and wholly inconsistent. I had to review my old notes just to remember this so no guarantees, but it seems that for try_files, specifically when dealing with nested locations only, won't execute if the inner location matches. I'd recommend testing it, though. Commented Jan 11, 2016 at 6:07
  • @MartinFjordvald i have been facing one issue since 2 days i could find any answer for it nginx is configuring only normal routes not nested routes my app please could you help me in this one, here is the stackoverflow post stackoverflow.com/questions/74374786/…
    – jsBug
    Commented Nov 10, 2022 at 7:41
16

Here's another convenient use of try_files, as unconditional redirects to named locations. The named locations are effectively acting as subroutines, saving duplication of code. When the first argument to try_files is _ the fallback redirect is always taken (assuming that _ is not an existing filename). Because nginx needs a goto statement but doesn't have one.

    location =/wp-login.php { try_files _ @adminlock; }
    location ^~ /wp-admin/  { try_files _ @adminlock; }
    location @adminlock  {
            allow 544.23.310.198;
            deny all;
            try_files _ @backend;
            # wp-admin traffic is tiny so ok to send all reqs to backend 
    }
    location ~ \.php {  try_files _ @backend; }
    location / { try_files $uri $uri/ =403; }
    location @backend {
            fastcgi_pass 127.0.0.1:9000;
            include snippets/fastcgi-php.conf;
    }
3
  • 3
    actually, all this does is try the file _, fail, and then use the fallback. If you create the file _ in your document_root, all these rules will fail.
    – w00t
    Commented Dec 2, 2019 at 11:45
  • 1
    @w00t - That's a good point which requires awareness. Would be useful if Nginx had a goto statement. Commented Dec 2, 2019 at 14:39
  • 2
    @w00t You can use an empty parameter instead as I described here, it should make such a configuration more reliable. Commented May 18, 2022 at 15:23

You must log in to answer this question.