关键在于nginx按端口筛选后再依精确匹配>通配符>正则顺序比对server_name,未匹配时由default_server或首个server块兜底;重复server_name会导致后加载者被静默忽略。

排查多个 server 块因 server_name 冲突导致的请求错配,关键不是“有没有写”,而是“谁真正被选中”。Nginx 不报错、不中断,只悄悄把请求交给错误的 server 块——比如你访问 app.example.com,结果打开的是默认站点或另一个测试站。
看最终生效的配置结构
用 nginx -T 输出完整合并后的配置(含所有 include),直接搜索你的域名:
-
nginx -T 2>/dev/null | grep -A 10 "server_name.*app\.example\.com"—— 查是否被加载、在哪一个文件里 -
nginx -T 2>/dev/null | grep "listen.*80" -A 5—— 列出所有监听 80 的 server 块,观察顺序和 default_server 标记 - 重点检查:同一端口下是否有多个块都写了
server_name app.example.com,后加载者会被静默忽略(警告如 conflicting server name "app.example.com" on 0.0.0.0:80, ignored)
确认匹配优先级是否被绕过
Nginx 按固定顺序筛选,不是“找到就停”,而是逐级比对。你的域名可能被更高优先级的规则截走:
- 精确匹配(
server_name app.example.com)优先于通配符(*.example.com) - 通配符
*.example.com不匹配example.com,必须显式加上example.com - 若用了
www.app.example.com访问,但只配了app.example.com,则完全不匹配——要加server_name app.example.com www.app.example.com - 正则匹配(
~^app\..*)一旦命中立即终止,不再比较后续块
验证实际路由路径
别只信配置文件名或目录位置,用真实请求验证哪个块真正响应:
- 临时把目标配置改名为
00-app.conf,重启 Nginx;如果原来 404 的域名突然正常,说明是加载顺序/兜底冲突 - 用
curl -H "Host: app.example.com" http://127.0.0.1绕过 DNS,直连本地,确认是否仍进错块 - 在疑似“抢流量”的兜底块里加
return 444;或写日志access_log /var/log/nginx/catch-all.log;,看是否有意外请求打进来
检查 default_server 和隐式兜底
没设 default_server 并不等于安全——Nginx 会把第一个定义的 server 块当作隐式兜底:
- IP 直接访问(如
http://192.168.1.100)时,Host 头为空或非法,必然落入 default_server 或第一个块 - 查所有监听 80 的块:
nginx -T 2>/dev/null | awk '/^server {/,/^}/ {if (/listen.*80/) print FILENAME ":" NR; if (/server_name/) print " " $0}' - 确保兜底块(如
99-default.conf)明确带default_server,且不包含干扰性server_name











