Nginx根据子域名动态设置root根目录配置未生效排查
配置存在的问题
- 核心问题是滥用Nginx的
if指令触发已知bug:Nginx中server块层级的if属于rewrite模块,执行时会生成隐式的location上下文,很容易出现变量赋值不生效、配置继承错乱的问题,也就是Nginx社区长期提到的If is Evil坑,这是规则不生效的主要原因。 - 子域名匹配正则写得太松:规则里
(?<subdomain>.+)的.会匹配包含.在内的所有字符,会把test.src.mydomain.com这类多级子域名错误捕获,不符合只匹配xxx.mydomain.com格式二级子域名的需求。 - 缺少必要的请求处理逻辑:现有配置没有PHP解析规则、没有路径兜底逻辑,就算目录映射正确,也会出现PHP文件直接下载、前端路由404的问题。
修正方案
推荐两种写法,按需选择即可:
方案1:单server块+map映射(配置简洁)
map指令在请求早期阶段执行,不会有if的上下文bug,是做变量映射的官方推荐方案。
首先在Nginx配置的http层级(和server块平级,不能写在server块内部)添加映射规则:
map $subdomain $site_folder { default "dist"; "src" "public"; "api" "public"; }
然后修改server块配置:
server { listen 8080; listen [::]:8080; # 正则收紧为[^.]+,仅匹配不含点的二级子域名,避免多级域名误命中 server_name ~^(?<subdomain>[^.]+)\.mydomain\.com$; root /home/site/wwwroot/$site_folder; index index.php index.html; location / { # 路径兜底:先找对应文件/目录,找不到则走入口文件,适配静态资源、前端history路由、PHP单入口 try_files $uri $uri/ /index.php?$query_string; } # PHP解析规则,按需保留,fastcgi_pass地址根据自己的PHP运行环境调整(端口或sock文件路径) location ~ \.php$ { fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } }
如果站点是纯静态页面,不需要PHP支持,直接删掉PHP解析的location块,把try_files最后一段改成/index.html即可。
方案2:多server块精确匹配(兼容性最好)
完全不用正则捕获和变量,靠Nginx原生的server_name优先级匹配,逻辑直白,所有Nginx版本都兼容,没有任何隐式坑:
# 匹配src、api子域名,指向public目录 server { listen 8080; listen [::]:8080; server_name src.mydomain.com api.mydomain.com; root /home/site/wwwroot/public; index index.php index.html; location / { try_files $uri $uri/ /index.php?$query_string; } # 同样按需添加PHP解析规则 location ~ \.php$ { fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } } # 匹配其余所有二级子域名,指向dist目录 server { listen 8080; listen [::]:8080; server_name ~^[^.]+\.mydomain\.com$; root /home/site/wwwroot/dist; index index.php index.html; location / { try_files $uri $uri/ /index.php?$query_string; } # 同样按需添加PHP解析规则 location ~ \.php$ { fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } }
内容的提问来源于stack exchange,提问作者jssDev
相关产品推荐
相关产品推荐

