Nginx 反向代理到 HTTPS 上游怎么配置?
Nginx 反代 HTTPS 上游(端到端加密)配置:proxy_pass https://、上游证书校验 proxy_ssl_verify、SNI 透传、自签证书处理、全链路加密示例与 FAQ。
把 proxy_pass 的目标写成 https:// 即可——Nginx 对外终止客户端 TLS(443 端口配证书),对内再发起一次 TLS 连接上游,实现端到端加密。 上游是自签证书时还需决定是否校验。
基础配置:双端 TLS
server {
listen 443 ssl;
server_name example.com;
# 对外:面向客户端的证书
ssl_certificate /etc/nginx/ssl/example.com.crt;
ssl_certificate_key /etc/nginx/ssl/example.com.key;
location / {
proxy_pass https://internal-app.local:8443; # 注意 https://
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
上游证书的两种处理
上游用正规 CA 证书(内网 PKI 也算):开启校验最安全。
proxy_ssl_verify on;
proxy_ssl_trusted_certificate /etc/nginx/ssl/internal-ca.crt;
proxy_ssl_verify_depth 2;
proxy_ssl_server_name on; # 发送 SNI
proxy_ssl_name internal-app.local; # 校验的证书名
上游是自签证书:内网常见,可以关校验,但要知道这意味着放弃了对上游身份的验证。
proxy_ssl_verify off;
proxy_ssl_server_name on; # 上游按 SNI 选证书时仍然需要
常见坑
- proxy_pass 写 upstream 块名:
proxy_pass https://my_upstream;配合upstream my_upstream { server ...; }——上游组的 TLS 行为同样受proxy_ssl_*控制。 - SNI 缺失:上游一个 IP 托管多个 HTTPS 站点(虚机托管)时,不开
proxy_ssl_server_name on会拿到默认证书,校验必失败。 - 握手版本不匹配:上游只支持 TLS1.3 而 Nginx 端
proxy_ssl_protocols限了旧版本,会握手失败——用proxy_ssl_protocols TLSv1.2 TLSv1.3;对齐。 - 证书里的名字:
proxy_ssl_name必须与上游证书 CN/SAN 匹配,内网常用 IP 访问而证书签的是域名,是经典翻车点。
什么时候值得端到端加密
- 合规要求传输全程加密(金融、医疗内网常见);
- Nginx 与上游之间跨了不可信网段(跨机房、跨云);
- 同机房纯内网、上游证书管理成本高于收益时,回源用 HTTP 也是合理的工程取舍——但要确保那段网络真的可信。
观测云对照
回源 TLS 故障的表现很隐晦:客户端看到 502,error.log 里是握手失败。把 Nginx error.log 采集到观测云,对 SSL_do_handshake() failed、upstream prematurely closed 类关键字设告警,上游证书过期、协议不匹配这类问题能在 502 风暴出现前就暴露;访问日志里的 $upstream_response_time 还能持续追踪回源耗时。
常见问题(FAQ)
Q:proxy_pass 用 https 后需要在上游也配证书吗?
A:需要。上游(应用服务器/内网 LB)必须自己持有 TLS 证书并完成握手——可以是内部 CA 签的,不必是公网 CA。
A:三步:确认 proxy_ssl_trusted_certificate 指向签发上游证书的 CA;确认 proxy_ssl_name 与证书 SAN 匹配;openssl s_client -connect 上游:端口 手动握手看证书链。
Q:对外用 HTTP(80)能反代 HTTPS 上游吗?
A:技术上可以(前半段明文、后半段加密),但前半段流量暴露在外,一般不推荐;要么全 HTTPS,要么明确那段网络可信。