The front-controller pattern gets written as a rewrite with a regular expression roughly as often as it gets written correctly, and try_files expresses the same intent as a list.
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ .php$ {
include fastcgi_params;
fastcgi_pass php:9000;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_split_path_info ^(.+.php)(/.+)$;
}
It reads as: serve the file if it exists, then the directory, then fall back — which is the actual requirement. The fastcgi_split_path_info line matters for any application using path info after the script name and is missing from most copied configurations. Worth knowing that try_files with a named location behaves differently from one with a URI, and mixing them up produces an internal redirect loop that nginx reports without much detail.