启用Nginx客户端证书认证需同时配置ssl_verify_client on、ssl_client_certificate、ssl_certificate及ssl_certificate_key四指令,并设准ssl_verify_depth;CA证书须含CA:TRUE,校验后透传$ssl_client_verify等变量至后端。

在企业内部系统中启用客户端证书认证(mTLS),核心不是堆砌指令,而是理清信任链与校验逻辑。Nginx 的 ssl_verify_client 是开关,真正起作用的是它和 ssl_client_certificate、ssl_verify_depth 的配合——三者缺一不可。
明确验证目标:你到底想信谁?
客户端证书必须由你明确信任的 CA 签发。这个 CA 可以是:
- 自建根 CA(适合内网统一管控)
- 私有中间 CA(例如用 OpenSSL 或 HashiCorp Vault 管理)
- 第三方商业 CA 的子级(需确保其证书链完整)
关键点:把该 CA 的公钥证书(PEM 格式,不含私钥)存为文件,比如 /etc/nginx/ssl/internal-ca.pem。用 openssl x509 -in internal-ca.pem -text -noout | grep "CA:" 确认输出含 CA:TRUE,否则 Nginx 拒绝信任。
基础配置必须成套写全
ssl_verify_client on 单独存在毫无意义。以下四行必须同时出现在同一个 server 块中:
-
listen 443 ssl;—— 启用 HTTPS 监听 -
ssl_certificate /path/to/server.crt;和ssl_certificate_key /path/to/server.key;—— 服务端自己的证书与私钥 -
ssl_client_certificate /etc/nginx/ssl/internal-ca.pem;—— 你信任的 CA 公钥 -
ssl_verify_client on;—— 强制校验客户端证书
若客户端证书由中间 CA 签发(如 root → intermediate → client),记得设 ssl_verify_depth 2,否则默认只查一级,校验会失败。
让后端真正用上证书信息
验证通过后,Nginx 会生成几个变量,可透传给上游服务做身份识别或权限判断:
-
$ssl_client_verify:值为SUCCESS、FAILED:reason或NONE -
$ssl_client_s_dn:证书主题,例如CN=dev-01,OU=API,O=MyCorp,适合提取用户名 -
$ssl_client_cert:Base64 编码的完整证书内容,可用于后端二次验签
在 location 块中加上这几行即可转发:
proxy_set_header X-Client-Verify $ssl_client_verify; proxy_set_header X-Client-DN $ssl_client_s_dn; proxy_set_header X-Client-Cert $ssl_client_cert;
调试不能只看返回码
客户端连不上时,400 错误可能意味着没发证书,403 更可能是证书不被信任或已过期。真实原因得靠日志定位:
- 临时开启 debug 日志:
error_log /var/log/nginx/debug.log debug; - 关注关键词:
SSL_do_handshake() failed、certificate verify failed、unable to get local issuer certificate - 本地快速验证命令:
openssl verify -CAfile /etc/nginx/ssl/internal-ca.pem client.crt,结果应为OK
不复杂但容易忽略











