IT 相关 · 2025 年 3 月 27 日

解决 Nginx 反向代理到 HTTPS 协议地址无法正常访问的问题

在宝塔面板进行反向代理时遇到一个蹊跷的现象:

  • 后端地址使用 http 协议时访问站点正常,但由于要代理的站点有部分地址会根据访问协议自动跳转到 https 访问,导致循环跳转而不能正常访问;
  • 后端地址必须使用 https 协议才能正常访问,但更换后直接显示 502 Bad Gateway;
  • 后端地址换成 WAF 地址,再由 WAF 反代到目标地址能够正常访问。

由此得出结论,肯定是有某种神秘力量在干预反向代理正常工作。在进行排查时发现,被代理的站点服务器不能通过 IP 直接访问 (部分 IDC 防止直接通过 IP 访问被滥用而拦截) 。在反代时已经添加了 Host 头部信息,而且尝试通过 WAF 反代是能正常访问的,在问题解决前一直认为通过 IP 访问拦截应该不是反代显示 502 的原因。

想到通过 HTTPS 协议访问时,通常情况下服务器需要通过 SNI(全称 Server Name Indication,中文意思是服务器名称指示) 进行识别,否则服务器则会通过默认的 SSL 证书进行 TLS 握手访问默认站点,该默认站点正是通过 IP 访问的站点。

在宝塔面板设置反代时后端地址使用 HTTPS 协议,查看 Nginx 反代部分的配置代码发现并没有发送 SNI 相关的代码,在默认情况下后端服务器会先进行 TLS 握手,然后才获取到请求的 HOST 头。这种情况下,后端服务器会使用默认的 SSL 证书进行 TLS 握手,而不会根据请求的域名选择对应的 SSL 证书。

由于 IDC 已禁用了 IP 访问,在 TLS 握手阶段由于没有包含 SNI 信息,被 IDC 视为通过 IP 访问,还没有到后端服务器尝试通过默认 SSL 证书握手阶段就被阻断,导致反代后访问显示 502 Bad Gateway 的情况。

为了解决该问题,需要在设置反代时正确发送 SNI 到后端,添加如下代码即可:

proxy_ssl_server_name on;
proxy_ssl_name www.jiangdefu.com;