标准开源 Nginx 不支持上游 mTLS,即无法向后端出示客户端证书;仅能校验后端证书(proxy_ssl_verify on),需依赖 Nginx Plus、Envoy 或 HAProxy 实现完整双向认证。

标准开源 Nginx 本身不支持向上游后端发起带客户端证书的 TLS 连接(即上游 mTLS),因此无法原生实现“负载均衡 + 双向 SSL 到后端集群”。所谓“支持双向 SSL 认证的反向代理”,实际只能完成其中一半:Nginx 可以验证后端证书(单向校验),但不能向后端出示自己的客户端证书——除非使用商业版 Nginx Plus,或改用其他代理组件。
先明确:什么是真正的上游双向 SSL?
真正意义上的上游 mTLS 要求:
- Nginx 作为 TLS 客户端,向后端 HTTPS 服务发起连接时,必须携带有效客户端证书(proxy_ssl_certificate + proxy_ssl_certificate_key)
- 后端服务必须配置为 强制要求并校验该客户端证书
- Nginx 同时需校验后端返回的服务器证书是否可信(靠 proxy_ssl_trusted_certificate + proxy_ssl_verify on)
但截至 Nginx 1.25(当前最新稳定版),proxy_ssl_certificate 系列指令仅在 Nginx Plus 中完整支持上游 mTLS。开源版虽有这些指令,但实测中多数版本(尤其 1.20 之前)会忽略 client certificate 发送,导致后端收不到证书而拒绝连接。
开源 Nginx 实际能做的安全加固方案
如果你坚持使用开源 Nginx,可构建接近双向认证强度的链路,重点放在可信身份传递 + 后端证书强校验:
-
启用并严格校验后端证书:设置
proxy_ssl_verify on、proxy_ssl_trusted_certificate /etc/nginx/ssl/upstream-ca.pem(仅含根/中间 CA,PEM 格式,无空行) -
显式指定 SNI 和主机名:加
proxy_ssl_name "backend-api.internal"和proxy_ssl_server_name on,避免 IP 直连导致 SAN 不匹配 -
限定 TLS 版本与深度:用
proxy_ssl_protocols TLSv1.2 TLSv1.3、proxy_ssl_verify_depth 3 -
后端降级为 HTTP 内网通信:关闭后端 TLS,改用内网 IP 白名单 +
proxy_set_header X-Client-Cert $ssl_client_cert透传原始客户端证书 Base64,由后端自行解析校验
可行替代架构(推荐生产环境采用)
若后端强依赖客户端证书认证,建议绕过 Nginx 上游限制:
- 用 Envoy 或 HAProxy 替代 Nginx 做 TLS 终止层:二者原生支持上游 mTLS,可配置证书轮换、SNI 路由、健康检查,并与 Nginx 协同(Nginx 做最外层 HTTPS 终止,Envoy 做上游 mTLS 代理)
-
OpenResty + Lua SSL 扩展:通过
lua_ssl_trusted_certificate和 OpenSSL API 在 rewrite 阶段构造带证书的 upstream 请求,但开发维护成本高,不适合中小团队 - 后端前置轻量网关:如用 Spring Cloud Gateway 或 Traefik,它们对上游 mTLS 支持成熟,Nginx 仅负责 DNS 负载和基础转发
配置示例(开源 Nginx 可用的安全增强版)
以下是在 upstream 或 location 中生效的最小可靠配置:
upstream secure_backend {
server backend1.example.com:8443;
server backend2.example.com:8443;
}
<p>server {
listen 443 ssl;
server_name api.example.com;</p><pre class="brush:php;toolbar:false;">ssl_certificate /etc/nginx/ssl/server.crt;
ssl_certificate_key /etc/nginx/ssl/server.key;
location / {
proxy_pass https://secure_backend;
# 强制校验后端证书
proxy_ssl_verify on;
proxy_ssl_trusted_certificate /etc/nginx/ssl/backend-ca.pem;
proxy_ssl_verify_depth 3;
# 确保 SNI 正确发送
proxy_ssl_name "backend-api.internal";
proxy_ssl_server_name on;
# TLS 协议约束
proxy_ssl_protocols TLSv1.2 TLSv1.3;
# 透传下游客户端身份(供后端二次校验)
proxy_set_header X-SSL-Client-Verify $ssl_client_verify;
proxy_set_header X-SSL-Client-DN $ssl_client_s_dn;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}}
注意:/etc/nginx/ssl/backend-ca.pem 必须是后端服务所用 CA 的根+中间证书拼合 PEM 文件,可用 openssl crl2pkcs7 -nocrl -certfile backend-ca.pem | openssl pkcs7 -print_certs -noout 验证是否合法。


















