Nginx+PHP-FPM: Let php handle file extensions

extensionnginxphp-fpmstatic-content

I am trying to serve a PHP script that handles some RESTful URIs and to know which format end user needs data, I handled that as the extension in the URI, eg.:

example.com/foo/bar.json?q=x&a=y --> data in ajax format
example.org/foo/bar.xml?q=x&a=y  --> data in xml format

I use Apache httpd + modphp in my development machine and it works just fine, but the stage server uses CentOS + Nginx + PHP. There, the nginx intercepts and tries handling an static json file and returns 404.

How can I prevent Nginx from handling certain file types (eg. json, xml) and let PHP handle those?

My Nginx config:

server {

  # listen [::]:443 ssl http2 accept_filter=dataready;  # for FreeBSD
  # listen 443 ssl http2 accept_filter=dataready;  # for FreeBSD
  # listen [::]:443 ssl http2 deferred;  # for Linux
  # listen 443 ssl http2 deferred;  # for Linux
  listen [::]:443 ssl http2;
  listen 443 ssl http2;

  # The host name to respond to
  server_name example.com;

  include h5bp/directive-only/ssl.conf;
  include ssl/conf/example.com;

  # Path for static files
  root /var/www/example.com/app/public;
  index index.php index.html index.htm;

  #Specify a charset
  charset utf-8;

  # Custom 404 page
  error_page 404 /404.html;

  # Include the basic h5bp config set
  include h5bp/basic.conf;

  # log settings
  access_log off;
  error_log  /var/log/www/example.com/nginx/error/error.log error;

  # turn off access logs and prevents logging
  # an error if robots.txt and favicon.ico are not found
  location = /favicon.ico { access_log off; log_not_found off; }
  location = /robots.txt  { access_log off; log_not_found off; }


  # check if a file or directory index file exists,
  # else pass the request to the index.php as a query parameter.
  location / {
    try_files $uri $uri/ /index.php?$query_string;
  }

  # handle execution of PHP files
  # set php5-fpm socket
  # tell NGINX to proxy requests to PHP FPM via the FCGI protocol
  location ~ \.php$ {
    fastcgi_split_path_info ^(.+\.php)(/.+)$;
    fastcgi_pass localhost:9003;
    fastcgi_index index.php;
    include fastcgi_params;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    fastcgi_intercept_errors off;
    fastcgi_buffer_size 16k;
    fastcgi_buffers 4 16k;
    fastcgi_connect_timeout 300;
    fastcgi_send_timeout 300;
    fastcgi_read_timeout 300;
  }

  # block access to .htaccess files
  location ~ /\.ht {
    deny all;
  }

}

Update: It did work finally, I put the json-related location inside the main / location and changed the $script_file_name for the json-related location to a static script name. Thanks to Tim.

Best Answer

Tell PHP to pass requests for json files to the PHP interpreter. You can make more precise path matches if required, for example only json files in the "/api/scripts" directory, you just need to work out the regular expression.

Change your PHP location to this

location ~ \.(php|json)$ {