SNI通过TLS握手初期携带域名信息实现单IP多HTTPS站点,Nginx 1.11.0+默认支持,需各server块独立配置证书,无SNI请求时使用首个或default_server块证书,并可用openssl s_client验证。

在单台服务器、单个公网IP地址上部署多个HTTPS站点时,传统SSL握手无法区分目标域名,导致Nginx只能为该IP返回一个默认证书——这就是SNI(Server Name Indication)要解决的核心问题。SNI通过在TLS握手初期携带请求的域名信息,让服务器能按需选择对应证书,从而实现“一IP多站多证”。
确认环境支持SNI
SNI是TLS协议扩展,依赖客户端和服务器两端共同支持:
- 服务端:Nginx 1.11.0+ 默认启用SNI(旧版本需确认编译时启用了OpenSSL且版本≥0.9.8j);可通过 nginx -V 2>&1 | grep -i openssl 检查OpenSSL版本
- 客户端:现代浏览器(Chrome/Firefox/Safari/Edge)、curl 7.18.1+、Android 4.0+ 均支持;IE在Windows XP上不支持,但Win7+ IE7及以上均支持
配置多域名独立SSL证书
每个 server 块必须绑定明确的 server_name,并各自指定证书路径。Nginx会根据SNI字段自动匹配:
server {
listen 443 ssl http2;
server_name site-a.com;
ssl_certificate /etc/nginx/ssl/site-a.com/fullchain.pem;
ssl_certificate_key /etc/nginx/ssl/site-a.com/privkey.pem;
# 其他配置...
}
<p>server {
listen 443 ssl http2;
server_name site-b.net;
ssl_certificate /etc/nginx/ssl/site-b.net/fullchain.pem;
ssl_certificate_key /etc/nginx/ssl/site-b.net/privkey.pem;</p><h1>其他配置...</h1><p>}注意:不能共用同一组 ssl_certificate 指令到多个 server 块中,否则Nginx启动时不会报错,但实际只会加载第一个块的证书作为fallback。
处理无SNI请求(如老旧客户端)
当客户端不发送SNI字段(例如某些嵌入式设备或极老系统),Nginx会使用监听端口上**第一个定义的server块**的证书响应。若需统一兜底,可显式定义一个默认server:
server {
listen 443 ssl http2 default_server;
server_name _;
ssl_certificate /etc/nginx/ssl/default/fullchain.pem;
ssl_certificate_key /etc/nginx/ssl/default/privkey.pem;
return 444; # 或返回友好提示页
}这样既避免证书错配警告,也便于识别异常流量。
验证SNI是否生效
使用 openssl s_client 手动模拟不同域名的TLS握手:
# 请求 site-a.com 的证书 openssl s_client -connect your-server-ip:443 -servername site-a.com -showcerts 2>/dev/null | openssl x509 -noout -subject <h1>请求 site-b.net 的证书</h1><p>openssl s_client -connect your-server-ip:443 -servername site-b.net -showcerts 2>/dev/null | openssl x509 -noout -subject
输出的 subject=CN=... 应分别与对应域名一致。也可用在线工具如 SSL Checker 输入各域名验证证书绑定情况。

















