nginx try_files, and the rewrite rule it replaces

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.