Ubuntu 22.04 上 nginx 反代到 https 的后端,upstream 用 IP 加端口写,握手时后端返回默认站点的证书,校验失败后 nginx 报 502,error.log 里是 SSL_do_handshake failed。
一开始怀疑是「upstream 里写的是内网 IP,证书 SAN 里只有域名」,查了一圈,方向不对。
把日志和配置对完,能解释这个现象的基本就这几处。proxy_ssl_server_name 没打开,nginx 按 IP 握手不发 SNI,后端只能给默认虚拟主机。少数情况下是proxy_ssl_verify 打开了却没有配置信任的 CA,自签证书直接校验失败。
少数情况下是后端强制要求 TLS1.2 以上,nginx 默认协议版本被降级。
手工验证后端握手返回哪张证书
openssl s_client -connect 10.0.0.21:443 -servername api.inner -showcerts </dev/null 2>/dev/null | grep 'subject='
接着在 location 里打开 SNI 与校验
printf 'proxy_ssl_server_name on;\nproxy_ssl_name api.inner;\nproxy_ssl_verify on;\nproxy_ssl_trusted_certificate /etc/nginx/ca.crt;\n' > /etc/nginx/conf.d/upssl.conf && nginx -t && nginx -s reload
然后核对后端证书链是否完整
openssl verify -CAfile /etc/nginx/ca.crt <(openssl s_client -connect 10.0.0.21:443 -servername api.inner </dev/null 2>/dev/null)
末了重放请求确认 502 消失
curl -s -o /dev/null -w '%{http_code}\n' https://www.example.com/api/ping
这类问题以前遇到过,但这次的触发条件和上次不一样。
别只看报错消失,验证要多做一步。error.log 不再出现 SSL_do_handshake failed,接口返回 200,openssl 输出的 subject 与后端域名一致。
这里还有个坑。反代 https 后端时 SNI 是最容易漏的一项,尤其 upstream 写 IP 的场景;开了校验就必须配 CA,否则自签环境一律握手失败。这类问题最好一次改到位,反复小改反而容易把原因搅混。
