11

I copied this config when setting up a basic Nginx / PHP-FPM webserver

server {
    listen 80 default_server;
    listen [::]:80 default_server ipv6only=on;

    root /usr/share/nginx/html;
    index index.php index.html index.htm;

    server_name server_domain_name_or_IP;

    location / {
        try_files $uri $uri/ =404;
    }

    location ~ \.php$ {
        try_files $uri =404;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass unix:/var/run/php5-fpm.sock;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
    }
}

It works as it should, but I dont understand how the try_files in location ~ \.php$ { .... } block works when serving a request for a php file, e.g. domain.com/test.php.
I thought this line

try_files $uri =404; 

tells nginx to just go ahead and try serving the static file - i.e. append $uri to root directory, if the file exists - nginx would simply send the static file and the request would be over wouldn't it? And therefore the fastcgi_pass wouldn't occur? but php-fpm does get it and execute the script.
Why doesn't the try_files prevent the fastcgi_pass?

2 Answers 2

15

try_files does not tell nginx to serve the static file. Reaching the closing brace in the absence of any other operation causes it to serve the static file. try_files tests for the existence of the file in the local file system and may rewrite the URL.

So try_files $uri =404; is one of a number of common tricks to overcome a particular script injection exploit by ensuring the the PHP file is a real file before sending the URL to the upstream interpreter.

5
  • Oh ok, so try_files check for the existence of $root$uri , if it does exist, it only remembers it - then continues processing the rest of the location block . If nothing else specifies what to do with the request/file - then nginx serves the static file as a last resort? Nov 26, 2015 at 15:19
  • 1
    @user4668401 Yes. But a location block is not required to contain a try_files directive in order for nginx to serve static files from that location. Nov 26, 2015 at 17:31
  • I see,and if you do have a try_files in a location block and it doesn't match a to a file, then it stops any more processing of the current location block and generates an new internal redirect using the final value of the try_files? Nov 26, 2015 at 17:38
  • 1
    Yes. There are a number of directives that can do that. Nov 26, 2015 at 17:45
  • DUDE... I spent HOURS trying to figure out why doesn't try_files work, when I had made sure the files exist, tried with and without root, tried with actually hardcoded paths, etc... always 404!!! Your first paragraph was CRUCIAL to make me finally understand why try_files doesn't work. I needed to do a manual rewrite first, to remove the prefix of the URL, for try_files to work. It all made sense after learning that try_files does NOT serve the files! Thank you very much! +1
    – Nuno
    Aug 27, 2023 at 14:23
2

Why do you think it should? Nginx documentation doesn't say anything like that.

Checks the existence of files in the specified order and uses the first found file for request processing; the processing is performed in the current context. [...] If none of the files were found, an internal redirect to the uri specified in the last parameter is made.

As long as the file is found, the request is processed normally, i.e. passed to fastcgi. Otherwise a 404 will be sent.

1
  • oh so, try files is kind of like a guard that says If I can't find the underlying file - then no further processing of this location block will take place ? the fallback will be used and an internal redirect will send processing back to the start again? Nov 26, 2015 at 15:21

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .