核心是匹配HTTP请求的Host头,优先级为精确匹配>左通配符>正则,多域名需空格分隔,HTTPS必须用SAN证书覆盖所有域名,并设default_server兜底未匹配请求。

靠 server_name 实现多域名虚拟主机,核心不是“写多个 server 块”,而是搞清“一个请求该进哪个块”——它只比对 HTTP 请求里的 Host 头,不查 DNS,也不看浏览器地址栏输的是什么。
匹配逻辑必须理清:优先级固定,不是按配置顺序
Nginx 不是逐行扫描 server 块,而是按三类规则分组比对,命中即停:
-
精确匹配最优先:比如
server_name example.com www.example.com;,访问www.example.com就走这个块,哪怕后面还有一行server_name *.example.com;也无效 -
左通配符次之:写成
*.example.com可匹配api.example.com、shop.example.com,但不匹配example.com(没子域)或foo.bar.example.com(两层子域) -
正则匹配最慢,但最灵活:用
~^([a-z0-9\-]+)\.example\.com$可捕获子域名,后续用$1拼路径或设变量;注意点号要转义,结尾加$
多个域名共用一个 server 块,空格分隔是关键
想让 example.com 和 www.example.com 都指向同一站点,不用拆两个 server 块:
- ✅ 正确:
server_name example.com www.example.com shop.example.com; - ❌ 错误:
server_name "example.com, www.example.com";(引号+逗号会被当做一个域名字符串) - ❌ 错误:
server_name example.com\nwww.example.com;(换行不识别,必须在同一行用空格连)
这样写之后,$host 变量仍能拿到真实访问的域名,可用于日志区分、条件跳转或代理路径拼接。
HTTPS 下必须配套 SAN 证书,否则只认第一个域名
HTTP 层没问题,但 TLS 握手阶段依赖 SNI,Nginx 只拿 server_name 列表里的第一个域名去查证书 SAN 扩展:
- 如果证书只含
example.com,而你配置了server_name example.com www.example.com;,访问www.example.com会提示证书不匹配 - 正确做法:申请证书时明确包含所有域名,例如 Certbot 命令:
certbot -d example.com -d www.example.com -d shop.example.com - 证书文件本身无顺序,但 Nginx 加载时只校验首个
server_name是否在 SAN 列表中,其余靠 HTTP 层$host区分
没匹配上的请求必须兜底,否则容易误入默认站
如果用户直接用 IP 访问,或 Host 头填了不存在的域名,Nginx 默认交给第一个监听该端口的 server 块处理——这常导致暴露测试页或跳错站:
- HTTP 兜底写法:
server { listen 80 default_server; server_name _; return 444; } - HTTPS 兜底必须配证书(哪怕自签):
server { listen 443 ssl http2 default_server; server_name _; ssl_certificate /path/to/fallback.crt; ssl_certificate_key /path/to/fallback.key; return 444; } -
server_name _;是约定俗成的“不匹配占位符”,不是特殊语法,只是个不会被正常 Host 匹配到的字符串


















