I'm currently trying to migrate a PHP app that is in the middle of being converted from php file per page to a front controller based system, from a server running Apache to Nginx. The site has a couple of other PHP apps in sub folders that use their own front controllers, but keep running into iossues with try_files either not working for some of the old urls to files that no longer exist or the root try_files overwriting the sub folder try_files.
For example:
Requests for /section.php/123/1/slugtext should get sent to PHP as /front.php/section.php/123/1/slugtext
Requests for /en/section/123/1/slugtext should get sent to PHP as /front.php/en/section/123/1/slugtext
Requests for /admin/api/Ping should get sent to PHP as /admin/admin_api.php/Ping
Any requests under /news/ should get sent to PHP as /news/index.php
Of course these rewrites should only happen for non existent files/directories.
Config:
map $http_x_forwarded_proto $is_https{
https on;
}
server {
listen ip:80;
server_name mydomain.tld;
return 301 https://www.$server_name$request_uri;
}
server {
listen ip:80;
root /home/www/mydomain/shop/htdocs;
server_name www.mydomain.tld;
if ($http_x_forwarded_proto != "https") {
return 301 https://$server_name$request_uri;
}
rewrite ^(.*)\.v[\d]+\.(css|js|png|jpg|jpeg|gif|eot|svg|ttf|woff|woff2)$ $1.$2;
location ~* \.(?:ico|css|js|gif|jpe?g|png)$ {
expires 30d;
add_header Pragma public;
add_header Cache-Control "public";
}
location = /favicon.ico {log_not_found off;access_log off;}
location = /robots.txt {allow all;log_not_found off;access_log off;}
location ~ /\. {deny all;}
index index.php index.html index.htm;
location / {
try_files $uri $uri/ /front.php$uri;
}
location ~ ^/admin/api(.*) {
try_files $1 $1/ /admin/admin_api.php$1;
}
location ^~ /news {
alias /home/www/mydomain/wordpress/htdocs;
index index.php;
try_files $uri $uri/ /news/news/index.php?q=$uri&$args;
location ~ \.php$ {
try_files $uri =404;
include fastcgi_params;
fastcgi_pass unix:/run/php/php7.0-fpm-wordpress.sock;
fastcgi_param SCRIPT_FILENAME $request_filename;
fastcgi_param APPLICATION_ENV production;
fastcgi_param PHP_VALUE default_charset=UTF-8;
location ~* /(?:uploads|files)/.*\.php$ {deny all;}
}
location ~ /\. {deny all;}
}
location ~ [^/]\.php(/|$) {
include fastcgi_params;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param HTTPS $is_https if_not_empty;
fastcgi_param APPLICATION_ENV production;
fastcgi_index index.php;
fastcgi_param PHP_VALUE default_charset=ISO-8859-1;
fastcgi_pass unix:/run/php/php7.0-fpm-shop.sock;
}
}
This config is the closest I've got to working but when I make requests for /section.php, which doesn't exist anymore and the front controller should handle and generate a 301 to the new URL, it seems Nginx ignores the the try_files in the / location block (I guess because the PHP one is a better match), if I move the try_files directly into the server block it works the same, if I add it to the PHP block it overrides the /admin/api one and all API requests get routed to front.php.
I'd got this working in Apache using:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^admin/bbapi/(.*)$ /admin/admin_api.php/$1 [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !^/news/
RewriteRule ^(.*)$ /front.php/$1 [L]