apache反向代理https握手失败本质是缺失sni或协议头透传不当;须启用sslproxyengine、用sslproxyservername指定带引号的域名、proxypass必须用域名而非ip,并在wss场景下透传upgrade/connection头。

Apache 反向代理导致 HTTPS 握手失败,本质是代理层未正确传递 TLS 协商所需的关键信息。问题不在于证书本身,而在于 Apache 与上游 HTTPS 后端建立连接时,缺失 SNI(Server Name Indication)或未透传必要协议头。解决需分两路:一是确保代理发起的 TLS 连接能被后端正确识别;二是保障 WebSocket 等升级型协议的握手不被破坏。
必须启用 SSL 代理并显式指定 SNI 域名
Apache 默认不会在反向代理连接中发送 SNI 扩展,即使 ProxyPass 写的是域名。后端(如云网关、Istio、Nginx 或自建 HTTPS 服务)依赖 SNI 选择对应证书,SNI 为空则直接拒绝握手。
- 确保已加载
mod_ssl和mod_proxy_http模块:a2enmod ssl proxy_http - 在
ProxyPass所在的<location></location>或<virtualhost></virtualhost>块中添加:SSLProxyEngine on - 强制指定 SNI 值:
SSLProxyVerify noneSSLProxyCheckPeerCN offSSLProxyCheckPeerName off
(仅用于测试或内网可信环境;生产建议校验) - 最关键一步:用
SSLProxyServerName显式设置 SNI 域名,例如:SSLProxyServerName "api.example.com"
注意:必须加英文双引号,不支持变量(如$host)
ProxyPass 必须使用域名而非 IP 地址
如果写成 ProxyPass / https://10.10.20.30:443/,Apache 将无法推导出应发送哪个 SNI,即使启用了 SSLProxyEngine,SNI 字段仍为空,后端 TLS 握手必败。
Apache Superset 是一个广泛采用的开源 BI 平台,用于 SQL 探索、图表构建和仪表板交付。当代理需要查询仓库数据、组装仪表板或使用成熟的分析界面解释指标而不是临时笔记本代码时,此技能非常有用。
- 改为使用可解析的域名:
ProxyPass / https://api.example.com:443/ - 若后端实际走内网 IP(如
192.168.1.100),则必须配合SSLProxyServerName "api.example.com"—— 域名用于 SNI,IP 用于网络寻址,二者不可混淆 - 确保该域名能被 Apache 主机 DNS 解析,或在
/etc/hosts中静态映射
WSS 场景下必须透传 Upgrade 协议头
WSS 握手本质是 HTTP 升级请求,Apache 默认会剥离 Upgrade、Connection 及 Sec-WebSocket-* 头,导致后端收不到有效升级指令,返回 200 而非 101,前端就卡在 readyState=3。
- 在代理配置中加入:
ProxyPreserveHost onRequestHeader set Host "api.example.com"
(确保 Host 与 SNI 一致) - 强制透传关键头:
ProxySet keepalive=onHeader always set Connection "upgrade"Header always set Upgrade "websocket" - 完整 WSS 代理示例:
<location></location><br> ProxyPass https://backend.example.com/ws/<br> ProxyPassReverse https://backend.example.com/ws/<br> SSLProxyEngine on<br> SSLProxyServerName "backend.example.com"<br> ProxyPreserveHost on<br> Header always set Connection "upgrade"<br> Header always set Upgrade "websocket"<br>
验证是否真正生效
配置重载后不能只看 Apache 是否启动成功,必须实测 TLS 和协议层行为。
- 用 OpenSSL 检查 SNI 是否发出:
openssl s_client -connect your-apache-ip:443 -servername api.example.com -showcerts 2>/dev/null | grep "Server name"(应输出匹配的 server_name) - 抓包确认 Client Hello 中含 Server Name extension 字段,且值为你设定的域名
- 查看 Apache error log,确认无
AH02007(SSL handshake failed)或AH01998(failed to enable ssl support)类错误 - 检查后端 access log,确认已有请求到达,而非完全静默










