Nginx启用mTLS需构建可信闭环验证链:服务端与客户端证书必须同源根CA签发;ssl_client_certificate仅指纯PEM格式根CA证书;ssl_verify_client必须设为on以强制校验;并通过proxy_set_header透传X-Client-Verify、X-Client-DN等变量给后端。

要在 Nginx 中真正启用客户端 SSL 证书双向认证(mTLS),关键不是“加几行配置”,而是构建一个可信、闭环的身份验证链。配置本身不复杂,但任意一环出错都会导致 400 错误或静默拒绝,排查困难。
必须统一且纯净的 CA 证书文件
服务端和所有客户端证书必须由同一个根 CA 签发。Nginx 用 ssl_client_certificate 指向的文件,只能是 PEM 格式的纯 CA 证书(如 cacert.pem),不含私钥、无 BOM、无多余空行或 DOS 换行符(\r\n)。
- 验证格式是否可用:运行
openssl x509 -in /etc/nginx/ssl/ca.crt -text -noout,能正常输出即合格;报unable to load certificate多因编码或换行问题 - 不要拼接 server.crt 或中间证书到该文件里——除非你明确需要多级 CA 链,否则只放根 CA
- 建议客户端和服务端证书的 O(Organization) 和 OU(Organizational Unit) 字段保持一致,避免因字段校验失败而静默拒连
强制校验模式不可妥协
ssl_verify_client on 是生产环境唯一有效的取值。设为 optional 或 optional_no_ca 实质等于关闭双向认证——Nginx 会接收证书但不做签名、有效期、吊销状态等任何检查,$ssl_client_verify 永远返回 SUCCESS。
-
on表示:客户端必须提供证书;该证书必须能被ssl_client_certificate中的 CA 成功验证;任一失败(过期、签名错、CN/O 不匹配、被吊销),Nginx 直接返回400 Bad Request - 配合设置 ssl_verify_depth 2(含中间 CA 时可调高),防止证书链过长绕过校验
- 禁用弱协议:
ssl_protocols TLSv1.2 TLSv1.3;推荐强 cipher:ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256
把客户端身份可靠透传给后端
Nginx 默认只在校验层使用客户端证书,不会自动把任何证书信息转发给后端服务。若后端需做用户识别、日志审计或细粒度权限控制,必须显式透传关键变量:
-
proxy_set_header X-Client-Verify $ssl_client_verify:值为SUCCESS/FAILED/NONE,用于快速判断校验结果 -
proxy_set_header X-Client-DN $ssl_client_s_dn:提取完整证书 Subject,例如CN=api-client-01,OU=backend,O=YourCorp - 如需原始证书 Base64 内容,可加:
proxy_set_header X-Client-Cert $ssl_client_cert(注意长度与后端接收能力)
基础配置示例(精简可用)
以下是一个最小可行的 server 块配置,路径请按实际调整:
server {
listen 443 ssl;
server_name api.example.com;
ssl_certificate /etc/nginx/ssl/server.crt;
ssl_certificate_key /etc/nginx/ssl/server.key;
ssl_client_certificate /etc/nginx/ssl/ca.crt;
ssl_verify_client on;
ssl_verify_depth 2;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
location / {
proxy_pass https://backend;
proxy_set_header X-Client-Verify $ssl_client_verify;
proxy_set_header X-Client-DN $ssl_client_s_dn;
}
}
配置完成后务必重载:nginx -t && nginx -s reload。首次调试可临时设为 ssl_verify_client optional 并检查 $ssl_client_verify 值,确认 CA 文件加载正常后再切回 on。


















