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