Nginx 通过 SNI 字段匹配独立 server 块实现多域名 HTTPS,每个域名需专属 server 块、精确 server_name 和对应证书路径;无 SNI 请求由 default_server 或首个块处理;可用 openssl s_client 验证证书是否按域名正确返回。

要让 Nginx 在单个 IP 上为不同域名自动加载对应 HTTPS 证书,核心不是“动态选择”,而是靠 TLS 握手初期的 SNI 字段触发 server 块匹配——每个域名必须有独立、完整、精准配置的 server 块。
每个域名配一个独立的 server 块
不能把多个域名塞进同一个块里“共用”一套证书(除非是 SAN 或泛域名证书)。正确做法是:
- 每个主域名(如 site-a.com)单独写一个
server块 - 每块都监听
443 ssl http2,且必须带ssl参数,否则不加载证书 -
server_name要精确列出该证书覆盖的所有域名,例如:server_name site-a.com www.site-a.com; -
ssl_certificate和ssl_certificate_key必须指向该域名专属的 PEM 文件,路径不能复用、不能写错
证书路径与域名必须一一对应
Nginx 启动时不校验证书文件是否存在或是否匹配域名,但运行时会严格按路径加载:
- 若某块证书路径错误、权限不足或文件缺失,该域名的 HTTPS 请求会失败(常见表现:连接重置、证书不匹配警告)
- 推荐用 certbot 分别申请:比如
certbot --nginx -d site-a.com和certbot --nginx -d site-b.net - 证书目录建议按域名隔离,例如:
/etc/nginx/ssl/site-a.com/和/etc/nginx/ssl/site-b.net/ - 泛域名证书(如
*.example.com)只能覆盖同主域下的子域,无法用于other.net
处理无 SNI 的老旧请求
部分旧客户端(如 Android 4.4 以下、某些嵌入式设备)不发送 SNI 字段,Nginx 会回落到第一个定义的 server 块,或显式标记的 default_server:
- 把最常用站点的块放在配置文件最前面,降低误配概率
- 也可显式声明兜底块:
listen 443 ssl http2 default_server; - 兜底块的
server_name _;是惯用写法,表示不匹配任何具体域名 - 建议返回
return 444;(关闭连接)或跳转提示页,避免提供无效证书引发浏览器警告
验证 SNI 是否真正生效
别只信浏览器,用 OpenSSL 直接测试 TLS 层行为:
-
openssl s_client -connect your.ip:443 -servername site-a.com -showcerts 2>/dev/null | openssl x509 -noout -subject→ 应显示CN = site-a.com - 换域名再试:
-servername site-b.net→ 应返回另一张证书的 subject - 这个测试绕过缓存、CDN 和浏览器中间层,结果最真实

















