Nginx通过SNI技术实现单IP多HTTPS域名托管,需确保OpenSSL≥1.0.2、各server块独立配置server_name与专属证书路径,禁用证书共用,并用openssl s_client验证SNI生效。

server_name 和 ssl_certificate 必须一一对应
每个 server 块里,server_name 声明的域名必须被该块中的 ssl_certificate 和 ssl_certificate_key 明确覆盖。不能省略、不能复用路径却不显式写出来。
-
server_name example.com www.example.com;→ 对应证书必须包含这两个 SAN(Subject Alternative Name) -
server_name api.other-site.com;→ 必须用另一组证书,哪怕物理路径相同,也要重复写ssl_certificate /etc/letsencrypt/live/api.other-site.com/fullchain.pem; - 泛域名证书
*.example.com不覆盖example.com(除非显式加进 SAN),更不覆盖other-site.com
Let’s Encrypt 多域名证书申请要一次性指定全部域名
用 certbot 批量申请比为每个域名单独申请更省事,也避免 Nginx 加载多个证书文件带来的路径管理混乱。
- 正确:
certbot --nginx -d example.com -d www.example.com -d blog.example.com - 错误:先申请
example.com,再申请blog.example.com,得到两套独立证书目录 —— 容易配错路径,且无法共享 reload 触发 - 证书生成后,所有域名共用同一组
fullchain.pem和privkey.pem,但每个server块仍需各自声明自己的ssl_certificate路径(指向同一文件没问题)
老客户端不支持 SNI,证书会 fallback 到第一个 server 块
Windows XP + IE6、部分 IoT 设备、旧 Android WebView 等不发 SNI 扩展,Nginx 就无法知道用户想访问哪个域名,只能返回 listen 443 ssl 下第一个定义的 server 的证书。
- 现象:访问
www.example.com却收到api.other-site.com的证书,浏览器报NET::ERR_CERT_COMMON_NAME_INVALID - 验证方式:用
openssl s_client -connect example.com:443 -servername www.example.com(带-servername)和不带对比输出的subject=和issuer= - 无解方案:SNI 是 TLS 层协议特性,Nginx 无法绕过。真要兼容,只能分 IP 或换端口(不推荐)
proxy_pass 和证书无关,但容易连带出错
反向代理场景下,ssl_certificate 只管 Nginx 到客户端这段 TLS;后端是否 HTTPS、是否校验证书,由 proxy_ssl_* 系列指令控制,和前端证书配置完全解耦。
- 常见误操作:把
proxy_pass https://backend/和前端证书混为一谈,以为“用了 HTTPS 后端就得配同样证书”——其实不用 - 关键透传头:确保有
proxy_set_header Host $host;和proxy_set_header X-Forwarded-Proto $scheme;,否则后端可能生成 http 链接或拒绝 HTTPS 请求 - 若后端也要求 TLS 验证,需额外配
proxy_ssl_trusted_certificate和proxy_ssl_verify on;
server_name 是否精确匹配、以及测试时忘了用真实 Host 头(比如 curl 不加 -H "Host: xxx" 或没改 /etc/hosts)。


















