apache反向代理https握手失败主因是sni缺失或协议头透传不当;须启用sslproxyengine、用sslproxyservername指定带引号的域名、proxypass必须用域名而非ip,并在wss场景下透传upgrade/connection头。
apache 中 sni 扩展丢失导致握手失败,核心表现是后端 https 服务拒绝连接(如返回 handshake failure、no shared cipher 或直接断连),而日志里看不到有效 sni 域名。问题不在客户端请求,而在 apache 作为反向代理发起上游连接时未发送 sni —— 这属于代理层配置缺失,不是证书或域名解析问题。
确认是否真由 SNI 缺失引发
先排除其他常见原因,再聚焦 SNI:
- 用
openssl s_client -connect api.example.com:443 -servername api.example.com -tlsextdebug 2>&1 | grep "server name"直连后端,看 ClientHello 是否含server name字样;若无,说明后端本身依赖 SNI 且严格校验 - 检查 Apache 错误日志中是否有
SSLProxyEngine not enabled、SSLProxyServerName not set类提示 - 抓包验证:在 Apache 服务器上对出向连接(如
tcp port 443 and host upstream-ip)抓包,过滤 ClientHello,看 Extensions 段是否为空或不含 server_name
检查 Apache 代理配置关键项
SNI 不是自动推导的,必须显式启用并指定:
Apache Superset 是一个广泛采用的开源 BI 平台,用于 SQL 探索、图表构建和仪表板交付。当代理需要查询仓库数据、组装仪表板或使用成熟的分析界面解释指标而不是临时笔记本代码时,此技能非常有用。
- 确保已加载模块:
a2enmod ssl proxy_http,且配置中启用SSLProxyEngine on -
SSLProxyServerName必须存在且带英文双引号,例如SSLProxyServerName "api.example.com";不支持变量(如$host)或 IP -
ProxyPass目标地址必须用域名(如https://api.example.com:443/),不能写成https://10.10.20.30:443/;域名用于 SNI,IP 仅用于寻址 - 该域名需能被 Apache 主机 DNS 解析;内网环境建议在
/etc/hosts中静态映射
验证 SNI 是否真正生效
配置生效后,通过两种方式交叉验证:
- 重启 Apache 后,执行
curl -v https://your-apache-domain/,观察后端响应;若仍失败,检查 Apache error_log 中紧邻SSL_do_handshake() failed的上下文,是否出现peer did not return a certificate或unable to get local issuer certificate—— 这些常是 SNI 缺失后证书选择错误的连锁反应 - 用
openssl s_client -connect your-apache-ip:443 -servername api.example.com模拟客户端访问 Apache,再结合后端抓包,确认 Apache 发给后端的 ClientHello 是否携带了正确的 SNI 值
特殊场景:WSS 或严格 TLS 校验环境
WebSocket over SSL(WSS)和国密 TLCP 等协议对 SNI 更敏感:
- WSS 要求透传
Upgrade和Connection头,否则后端无法识别升级意图;需配ProxyPreserveHost on和RequestHeader set Host "api.example.com" - TLCP 服务(如 GmSSL)默认不发 SNI 扩展,需修改源码或使用支持 SNI 的客户端版本;Apache 代理时同样依赖
SSLProxyServerName强制注入 - 若后端启用了
ssl_verify_client require或证书绑定 SNI,SNI 域名必须与证书中subjectAltName完全一致,大小写和通配符均需匹配










