启用 apache sni 前须确认:一、apache ≥2.2.12 且编译支持 openssl;二、mod_ssl 已启用;三、每个 virtualhost 独立配置证书与私钥,禁用全局 ssl 配置。

Apache 启用 SNI 前必须确认的三件事
Apache 默认不自动启用 SNI,即使你配了多个 SSLCertificateFile,老版本或未开启 TLS 的配置下,只会返回第一个站点的证书——浏览器会报 ERR_SSL_VERSION_OR_CIPHER_MISMATCH 或直接显示错误证书。
- 确认 Apache 版本 ≥ 2.2.12(推荐 ≥ 2.4.8),且编译时启用了 OpenSSL 支持(
httpd -V | grep -i ssl查看) - 确保
mod_ssl已加载:a2enmod ssl(Debian/Ubuntu)或检查LoadModule ssl_module modules/mod_ssl.so在配置中启用 - 必须使用
NameVirtualHost *:443(Apache 2.2)或直接在<virtualhost></virtualhost>中定义(2.4+ 不再需要显式NameVirtualHost)
每个 <virtualhost></virtualhost> 必须独立配证书路径
SNI 依赖客户端在 TLS 握手阶段发送请求的域名(SNI 扩展),Apache 据此选择对应虚拟主机的证书。如果两个 <virtualhost></virtualhost> 共用同一组 SSLCertificateFile 和 SSLCertificateKeyFile,SNI 就失效了——所有域名都拿到同一张证书。
- 每个站点必须有自己专属的证书文件:比如
SSLCertificateFile /etc/ssl/certs/site-a.example.com.crt - 私钥不能共用,哪怕域名同属一个组织,也要配对应的
SSLCertificateKeyFile - 若使用 Let’s Encrypt,建议用
certbot --apache -d site-a.example.com -d www.site-a.example.com单独运行多次,避免跨域混用fullchain.pem - 不要在全局
ssl.conf里写证书路径,所有 SSL 配置必须放在具体<virtualhost></virtualhost>块内
SSLStrictSNIVHostCheck 设为 off 是多数情况下的安全妥协
这个指令控制 Apache 是否拒绝不带 SNI 的旧客户端(如 IE6 on XP、Android 2.x、curl on 会让这些客户端无法访问任何 HTTPS 站点;设为 off 则 fallback 到第一个定义的 <virtualhost></virtualhost> 的证书——可能不匹配,但至少能连上。
- 生产环境建议设为
SSLStrictSNIVHostCheck off(Apache 2.2.12+ 默认就是 off) - 如果明确不需要兼容老旧设备,可设为
on,但需确认监控里没有大量 TLS handshake failure 日志 - 该指令必须放在
<virtualhost></virtualhost>外部(如ssl.conf全局段),不能写在某个虚拟主机内部
验证 SNI 是否生效的两个命令
光看浏览器没用——浏览器缓存证书、自动重定向、HSTS 都会干扰判断。得用底层工具直连验证。
- 用
openssl s_client -connect example.com:443 -servername site-a.example.com,检查返回的subject=是否匹配预期域名 - 用
curl -I --resolve site-b.example.com:443:your-server-ip https://site-b.example.com,确认响应头中的证书信息和 HTTP Host 一致 - 常见坑:
-servername参数拼错、DNS 解析没指向你的服务器 IP、防火墙拦截 443 端口导致超时而非证书错误










