nginx虚拟主机域名匹配不生效,主因是两级筛选逻辑未满足:先按listen端口精准筛选候选server块,再依server_name精确/通配符/正则顺序匹配host头;无default_server时首块隐式兜底,易致https请求错路由。

Nginx 虚拟主机域名匹配不生效、请求被错误路由,往往不是配置写错了,而是没理解它的两级筛选逻辑。排查重点不在“哪行写在前面”,而在于端口是否对得上、server_name 是否按规则命中。
先确认监听端口是否参与候选
请求进来后,Nginx 会先筛掉所有不监听目标端口的 server 块:
- HTTP 请求(Host 头带 :80 或无端口)只看 listen 80 或 listen *:80 的块,listen 443 ssl 完全不参与
- HTTPS 请求(SNI 携带域名)只比对 listen 443 ssl 的块,listen 443(无 ssl)是另一个独立池子
- 绑定了具体 IP 的 listen 192.168.1.10:80,不会响应发往 127.0.0.1:80 的请求
再检查 server_name 匹配顺序是否符合预期
同一端口下的 server 块,Nginx 严格按以下顺序逐级比对 Host 头(大小写不敏感):
-
精确匹配:如
server_name api.example.com;—— 只匹配Host: api.example.com,不匹配www.api.example.com或api.example.com:8080 -
最长前导通配符:如
server_name *.example.com;—— 匹配admin.example.com,但不匹配example.com;若同时存在*.example.com和*.api.example.com,则backend.api.example.com会命中后者 -
后缀通配符(1.11.10+):如
server_name mail.*;—— 匹配mail.org、mail.net,但实际使用少,易误配 -
正则匹配:以
~或~*开头,如server_name ~^v[1-3]\.api\.example\.com$;—— 按配置文件从上到下扫描,第一个成功即停,不比长度
验证兜底行为是否可控
当 Host 头无法匹配任何 server_name 时,Nginx 不会报错,而是自动 fallback:
- 若有
listen 443 ssl default_server;,就用它——这是最安全的做法 - 若没设
default_server,则启用该端口下第一个定义的 server 块(按配置加载顺序),这常导致 HTTPS 请求被错误路由到非预期站点 - 建议单独配一个最小化默认块:
server { listen 443 ssl default_server; return 444; },避免信息泄露或证书错配
检查证书与 server_name 是否真正绑定
SSL 证书本身没有优先级,它只是挂载在某个 server 块里。真正起作用的是 server_name 匹配结果:
- 泛域名证书
*.example.com.crt必须放在server_name *.example.com;的块中才生效 - 精确域名证书
www.example.com.crt必须对应server_name www.example.com; - 客户端 SNI 字段决定 Nginx 选哪个 server 块,之后就直接发送该块配置的证书——如果 SNI 是
admin.example.com,但你只配了www.example.com和*.example.com,那它就会走泛域名块,证书自然也是泛域名证书











