Nginx的server_name匹配优先级固定为:精确匹配 > 前导通配符 > 尾随通配符 > 正则匹配;泛域名(如*.example.com)绝不会优先于精确匹配(如api.example.com),若出现“泛域名抢请求”,必因配置错误或SNI/Host头异常导致。

这其实是个常见误解:泛域名(如 *.example.com)**不会**优先于精确匹配(如 api.example.com)。Nginx 的 server_name 匹配有明确且固定的优先级,泛域名天然排在精确匹配之后。如果你观察到“泛域名抢了精确域名的请求”,说明配置中存在干扰因素,不是优先级本身出了问题,而是匹配逻辑被绕过了。
检查 server_name 是否真正构成“精确匹配”
精确匹配要求 Host 头与 server_name 字符完全一致(大小写不敏感,但不含端口、路径或协议)。常见疏漏包括:
- 写成了
server_name api.example.com;,但客户端实际发来的是API.EXAMPLE.COM——虽然 Nginx 内部会转小写比较,但若你同时写了Api.example.com和api.example.com,Nginx 只认第一个出现的 - Host 头带端口,如
api.example.com:8080,而server_name没声明端口,此时不匹配(server_name不解析端口) - 多域名空格分隔写错,比如用了逗号:
server_name example.com, www.example.com;→ 实际只识别example.com,(含逗号),导致整个值无效
确认没有正则或通配符意外覆盖
如果某个 server 块里混用了多种匹配方式,Nginx 仍按优先级处理,但容易误判。特别注意:
- 不要在一个
server块里写多个server_name行,Nginx 只取第一个有效行 - 避免用正则覆盖本该精确匹配的域名,例如:
server_name ~^api\..*\.example\.com$;会匹配api.example.com,但它属于“正则匹配”,优先级最低,只有在精确和通配符都失败时才触发——所以它不会“抢走”精确匹配,但可能掩盖配置错误 - 检查是否有更宽泛的通配符块提前命中,比如同时存在
*.example.com和*.api.example.com,后者更长,会优先匹配v1.api.example.com;但api.example.com仍应由精确块承接
验证请求是否真的到达了预期 server 块
最直接的方式是加日志定位:
- 给每个
server块加唯一标识日志,例如:access_log /var/log/nginx/api.access.log main;和access_log /var/log/nginx/wildcard.access.log main; - 用
curl -H "Host: api.example.com" http://your-ip/手动构造请求,避开 DNS 和浏览器缓存干扰 - 开启
error_log /var/log/nginx/error.log debug;(临时),搜索"no matching server"、"using server"等关键词,看 Nginx 实际选中了哪个块
HTTPS 场景要额外核对 SNI 和证书绑定
HTTP 下靠 Host 头匹配,HTTPS 下还依赖客户端发送的 SNI 值。如果 SNI 缺失或不一致,Nginx 可能回退到默认 server(通常是配置文件里第一个 server 块),造成“看似泛域名生效”的假象:
- 用
openssl s_client -connect your-domain:443 -servername api.example.com测试 SNI 是否正确传递 - 确保每个 HTTPS
server块都有独立ssl_certificate,且server_name与证书 SAN 或 CN 一致 - 避免把
*.example.com和api.example.com放在同一server块里——Nginx 不支持模糊合并,只会取第一个server_name值











