Home > Enterprise >  Nginx tryfiles fallback skipped for non-existant php file
Nginx tryfiles fallback skipped for non-existant php file

Time:12-06

Have a server running nginx php-fpm and all running fine except for inconsistent handling of 404s.

example.com/fakepath 
example.com/fakepath.php

The first link passes through to our app which handles 404 page, logging etc. The second link returns an error outside our app with a blank page showing just "File not found."

Is this being caused by the nginx php block, or the php-fpm side? Any setting to get php files that don't exist passed back to the index.php instead of the not found error?

        location / {
                index index.php index.html;
                try_files $uri $uri/ /index.php$is_args$args;

        }
        location ~ \.php$ {
                fastcgi_index                   index.php;
                fastcgi_param SCRIPT_FILENAME   $document_root/$fastcgi_script_name;
                fastcgi_param QUERY_STRING      $query_string;
                fastcgi_param PATH_INFO         $fastcgi_path_info;
                fastcgi_split_path_info ^(. \.php)(/. )$;

                include fastcgi_params;
                fastcgi_pass unix:/run/php/php7.4-fpm.sock;
        }

CodePudding user response:

This happens because priority of regex matching locations like location ~ \.php$ { ... } is greater than prefix locations like location / { ... }. ​An exact location selection algorithm decribed in the location directve documentation:

A location can either be defined by a prefix string, or by a regular expression. Regular expressions are specified with the preceding “~*” modifier (for case-insensitive matching), or the “~” modifier (for case-sensitive matching). To find location matching a given request, nginx first checks locations defined using the prefix strings (prefix locations). Among them, the location with the longest matching prefix is selected and remembered. Then regular expressions are checked, in the order of their appearance in the configuration file. The search of regular expressions terminates on the first match, and the corresponding configuration is used. If no match with a regular expression is found then the configuration of the prefix location remembered earlier is used.

...

If the longest matching prefix location has the “^~” modifier then regular expressions are not checked.

Also, using the “=” modifier it is possible to define an exact match of URI and location. If an exact match is found, the search terminates. For example, if a “/” request happens frequently, defining “location = /” will speed up the processing of these requests, as search terminates right after the first comparison.

The above means than when you get a /fakepath.php request, it's processing goes directly to the location ~ \.php { ... } where you didn't have any try_files directive. Error you've got is coming from PHP-FPM daemon response when you pass a non-existent file path to it via SCRIPT_FILENAME FastCGI parameter. The most simple is to add another try_files directive to the second location block:

location ~ \.php$ {
    try_files $uri /index.php$is_args$args;
    ...
}

However due to try_files directive behavior described here you'll be unable to set PATH_INFO FastCGI parameter using your current config. I don't think you really need it for you PHP web app since with your regex PATH_INFO will be always empty anyway (and if you really do, change your regex to \.php($|/) like shown here and use a suggested workaround). The only modern software I know that is really using PATH_INFO nowadays is the Craft CMS, most of them (including most popular like WordPress, Laravel Framework, etc.) relies on REQUEST_URI FastCGI parameter instead. Most probably you can safely remove those fastcgi_split_path_info ^(. \.php)(/. )$; and fastcgi_param PATH_INFO $fastcgi_path_info; lines from your config (as I already said, using \.php$ regex with the location directive those lines don't do anything anyway).

  • Related