Nginx使用变量定义root后所有URL跳转首页的问题咨询
问题成因
- Nginx 匹配优先级规则问题:正则匹配的优先级高于普通前缀匹配。你配置的
location ~ \.(php|phar)(/.*)?$属于正则匹配,优先级比普通前缀匹配的location /更高,所有PHP请求会直接命中这个PHP处理块,完全不会进入location /的逻辑,因此你在location /中设置的root $base_root/frontend/web对PHP请求完全不生效。 - 根路径继承错误:PHP处理块默认继承server层级的root配置,你server层的root是
$base_root = /var/www/html,当try_files把请求重写到/index.php后,PHP处理块拼接出的实际文件路径是/var/www/html/index.php,如果该路径下的文件就是你的前端首页,自然所有请求都会返回首页内容,无法触发路由解析。
修复方案
你要实现前后端分离的路径配置,只需要调整location匹配优先级,将PHP处理块嵌套到对应业务的location下即可,示例配置如下(假设后端接口统一用/api前缀,对应代码存放在/var/www/html/backend/web,你可以根据自己的实际路径调整):
server { set $base_root /var/www/html; root $base_root; index index.php index.html; # 后端接口配置 location ^~ /api/ { root $base_root/backend/web; try_files $uri $uri/ /api/index.php$is_args$args; # 嵌套PHP处理块,继承当前location的root location ~ \.(php|phar)(/.*)?$ { fastcgi_split_path_info ^(.+\.(?:php|phar))(/.*)$; fastcgi_intercept_errors on; fastcgi_index index.php; fastcgi_param QUERY_STRING $query_string; fastcgi_param REQUEST_METHOD $request_method; fastcgi_param CONTENT_TYPE $content_type; fastcgi_param CONTENT_LENGTH $content_length; fastcgi_param SCRIPT_NAME $fastcgi_script_name; fastcgi_param REQUEST_URI $request_uri; fastcgi_param DOCUMENT_URI $document_uri; fastcgi_param DOCUMENT_ROOT $document_root; fastcgi_param SERVER_PROTOCOL $server_protocol; fastcgi_param REQUEST_SCHEME $scheme; fastcgi_param HTTPS $https if_not_empty; fastcgi_param GATEWAY_INTERFACE CGI/1.1; fastcgi_param SERVER_SOFTWARE nginx/$nginx_version; fastcgi_param REMOTE_ADDR $remote_addr; fastcgi_param REMOTE_PORT $remote_port; fastcgi_param SERVER_ADDR $server_addr; fastcgi_param SERVER_PORT $server_port; fastcgi_param SERVER_NAME $server_name; fastcgi_param REDIRECT_STATUS 200; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_param PATH_INFO $fastcgi_path_info; fastcgi_pass php-fpm; } } # 前端站点配置 location ^~ / { root $base_root/frontend/web; try_files $uri $uri/ /index.php$is_args$args; # 嵌套PHP处理块,继承当前location的root location ~ \.(php|phar)(/.*)?$ { fastcgi_split_path_info ^(.+\.(?:php|phar))(/.*)$; fastcgi_intercept_errors on; fastcgi_index index.php; fastcgi_param QUERY_STRING $query_string; fastcgi_param REQUEST_METHOD $request_method; fastcgi_param CONTENT_TYPE $content_type; fastcgi_param CONTENT_LENGTH $content_length; fastcgi_param SCRIPT_NAME $fastcgi_script_name; fastcgi_param REQUEST_URI $request_uri; fastcgi_param DOCUMENT_URI $document_uri; fastcgi_param DOCUMENT_ROOT $document_root; fastcgi_param SERVER_PROTOCOL $server_protocol; fastcgi_param REQUEST_SCHEME $scheme; fastcgi_param HTTPS $https if_not_empty; fastcgi_param GATEWAY_INTERFACE CGI/1.1; fastcgi_param SERVER_SOFTWARE nginx/$nginx_version; fastcgi_param REMOTE_ADDR $remote_addr; fastcgi_param REMOTE_PORT $remote_port; fastcgi_param SERVER_ADDR $server_addr; fastcgi_param SERVER_PORT $server_port; fastcgi_param SERVER_NAME $server_name; fastcgi_param REDIRECT_STATUS 200; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_param PATH_INFO $fastcgi_path_info; fastcgi_pass php-fpm; } } }
如果觉得重复写PHP配置太冗余,可以把公共的PHP配置抽取为独立的配置文件,比如存到/etc/nginx/snippets/php-fpm.conf,然后在对应位置用include snippets/php-fpm.conf;引入即可。
核心修改点说明
- 用
^~修饰符提升location /和location /api/的匹配优先级,匹配到对应前缀后不会再走全局的正则PHP匹配 - 把PHP处理块嵌套到对应业务的location内部,自动继承当前location的root配置,保证PHP文件查找路径正确
- 前后端路径分开配置,互不干扰,不需要额外加rewrite规则
内容的提问来源于stack exchange,提问作者MikelG
相关产品推荐
相关产品推荐

