启用 proxy_ssl_server_name on 可解决 nginx 反向代理 https 到 sni 后端时因未透传 sni 导致的 tls 握手失败问题,它使 nginx 在连接后端时发送 host 头对应的域名作为 sni 字段。

当 Nginx 作为反向代理转发 HTTPS 请求到后端服务器(如另一台 HTTPS 服务)时,若后端启用 SNI(Server Name Indication)且要求客户端在 TLS 握手阶段明确声明目标域名,而 Nginx 默认不透传 SNI 名称,就可能导致后端 TLS 握手失败、证书校验不通过或连接被拒绝。启用 proxy_ssl_server_name on 可解决该问题——它让 Nginx 在与后端建立 TLS 连接时,主动发送客户端请求中的 Host 头对应的域名作为 SNI 扩展字段。
为什么需要 proxy_ssl_server_name
Nginx 默认的 upstream TLS 连接行为是:仅根据 proxy_pass https://... 中的地址发起连接,不携带 SNI 信息。这在以下场景会出错:
- 后端是多租户 HTTPS 服务(如基于 SNI 的虚拟主机),依赖 SNI 区分证书和路由
- 后端启用了严格 TLS 配置(如 OpenSSL 1.1.1+ +
SSL_OP_NO_TLSv1_1或强制 SNI 校验) - 后端返回
SSL_ERROR_SSL、ssl_handshake_failed或直接关闭连接,Nginx error log 中出现peer closed connection in SSL handshake
正确配置 proxy_ssl_server_name
该指令必须配合 proxy_pass https://... 使用,且需确保 Nginx 版本 ≥ 1.7.0(推荐 ≥ 1.19.0)。关键配置如下:
FastAPI + Flask 混合部署最佳实践,解决路由定义、API 代理等常见问题,适用于同时运行 FastAPI API 与 Flask 前端的场景。
- 在
location或upstream块中启用:proxy_ssl_server_name on; - 确保
proxy_set_header Host $host;已设置(SNI 值默认取自该变量,而非硬编码) - 若后端需特定域名(如与
Host不同),可用proxy_ssl_name "example.com";显式指定 - 建议同时配置证书验证开关:
proxy_ssl_verify off;(开发/内网)或proxy_ssl_verify on; proxy_ssl_trusted_certificate /path/to/ca.pem;(生产)
常见误区与验证方法
容易忽略但影响生效的细节:
-
proxy_ssl_server_name对 HTTP 后端无效,只作用于https://协议的proxy_pass - 若使用变量拼接
proxy_pass(如proxy_pass https://$backend;),需确认变量值不含端口或路径,否则 SNI 可能提取异常 - 可通过
openssl s_client -connect backend-ip:443 -servername example.com手动模拟带 SNI 的连接,验证后端是否响应正确证书 - Nginx 日志中开启
error_log /var/log/nginx/error.log debug;可看到SSL_do_handshake() failed或SSL_connect:before SSL initialization等线索
完整 minimal 示例
一个典型工作配置片段:
location /api/ {
proxy_pass https://backend-service;
proxy_ssl_server_name on;
proxy_set_header Host $host;
proxy_ssl_verify off; # 内网可关;生产请配 CA 并开 verify
proxy_ssl_protocols TLSv1.2 TLSv1.3;
}
upstream backend-service {
server 10.0.1.5:443;
}










