Nginx PHP-FPM – Nginx 404 .php Extension with FPM

nginxphp-fpm

When I visit a non-existent url with .php extension I get a ngnix 404 error page, however url without .php extension it works as expected using the try_files. Where the 404 is handled via php application.

It has happened since I added this code as suggested

fastcgi_split_path_info ^(.+?\.php)(/.*)$;
if (!-f $document_root$fastcgi_script_name) {
    return 404;
}

Reason for adding this was to fix error in logs: FastCGI sent in stderr: "Primary script unknown" while reading response header from upstream
This error was happening when I visited non-existent.php file. I read lots of posts about the problem being to do with 'SCRIPT_FILENAME' being missing but this wasn't the case for me.

example.conf

server {
  listen 443 ssl;
  listen [::]:443 ssl;

  server_name example.com;

  root /var/www/example/public/public;

  access_log  /var/log/nginx/example.access.log main_ext;
  error_log  /var/log/nginx/example.error.log warn;

  ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

  include /etc/nginx/include.d/ssl.conf;

  # Laravel
  rewrite ^/index.php/(.*) /$1 permanent;
    
  location = / {
    try_files /page-cache/pc__index__pc.html /index.php?$query_string;
  }

  location / {
    try_files $uri $uri/ /page-cache/$uri.html /index.php?$query_string;
  }

  location ~ [^/]\.php(/|$) {
    include /etc/nginx/include.d/php.conf;
    fastcgi_pass unix:/var/run/php/php8.0-fpm-example.sock;
  }
}

php.conf

# Check file exists
try_files $uri =404;

# https://www.nginx.com/nginx-wiki/build/dirhtml/start/topics/examples/phpfcgi/
fastcgi_split_path_info ^(.+?\.php)(/.*)$;
if (!-f $document_root$fastcgi_script_name) {
    return 404;
}

fastcgi_index index.php;

# Mitigate https://httpoxy.org/ vulnerabilities
fastcgi_param HTTP_PROXY "";

fastcgi_intercept_errors off;

# include the fastcgi_param setting
include fastcgi_params;

fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;

Example URL:
https://example.com/foo – Works fine shows pretty 404 inside php app.
https://example.com/foo.php – Shows default ngnix 404.

Best Answer

If you want those URIs to be processed as any other non-existent URIs, change try_files $uri =404; to the try_files $uri /index.php?$query_string; in your php.conf file.


If your PHP app really makes use of PATH_INFO FastCGI variable (which I doubt about), you should use

fastcgi_split_path_info ^(.+\.php)(/.+)$;

try_files $fastcgi_script_name /index.php?$query_string;

set $path_info $fastcgi_path_info;
fastcgi_param PATH_INFO $path_info;

(see this nginx trac ticket).