If you're trying to rewrite clean URLs like /results/summer-meet to /results/view.php?slug=summer-meet in Nginx, everything might seem simple... until your .php files start downloading instead of executing.
Here’s what’s going wrong — and how to fix it.
location ~ ^/(results|standards|meet|heat-sheets|psych-sheets)/ {
try_files $uri $uri/ @rewrite_view;
}
location @rewrite_view {
rewrite ^/(results|standards|meet|heat-sheets|psych-sheets)/([a-z0-9\-]+)$ /$1/view.php?slug=$2 last;
}
Why it fails:
The location ~ block is a regex match.
Nginx gives regex blocks higher priority, and once it matches this block, it does not fallback to your global .phphandler like:
location ~ \.php$ { ... }
Result: /results/view.php gets matched by the regex block, and since there's no .php handler inside, Nginx serves it as a static file — or downloads it.
The safest way is to avoid regex and use one location per folder:
location /results/ {
try_files $uri $uri/ @rewrite_results;
}
location @rewrite_results {
rewrite ^/results/([^/]+)$ /results/view.php?slug=$1 last;
return 404;
}
Repeat for each folder (/standards/, /meet/, etc.).
This works because:
location /results/ is a prefix match, not regex
If the file exists (like view.php), it falls through to the global .php$ handler correctly
No more downloads. Clean, clear routing.
.php HandlerIf you really want to keep the compact regex style, you must re-define .php handling for those folders:
location ~ ^/(results|standards|meet|heat-sheets|psych-sheets)/ {
try_files $uri $uri/ @rewrite_view;
}
location ~ ^/(results|standards|meet|heat-sheets|psych-sheets)/.*\.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php8.2-fpm-swimsnap.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
This ensures PHP files inside those folders (like view.php) still get routed through PHP-FPM correctly.
Prefer prefix-based blocks (location /results/) unless you have a strong reason for regex
If you use location ~, you must handle .php within the same scope or via more specific regex
Always verify with nginx -t and test .php execution directly to avoid silent errors
If you're seeing downloads or blank responses, chances are it's not your rewrite — it's Nginx falling into the wrong block.