导读:本期聚焦于俊华创作的《Nginx如何搭配easy-rsa实现客户端证书双向认证?》,敬请观看详情。想让Nginx只允许持有合法证书的用户访问后台服务,单靠密码远远不够。easy-rsa是OpenVPN官方配套的证书管理脚本,用它签发客户端证书非常省事,配合Nginx的ssl_verify_client指令就能实现完整的双向TLS认证。本文从CA证书搭建讲起,逐步演示如何签发服务端与客户端证书,如何在Nginx中配置强制或可选的双向认证,并给出证书吊销、过期续签等运维细节的处理方法,帮你把HTTPS服务的准入门槛提升到证书级别。

日常运维中,仅仅依靠用户名密码来保护Nginx背后的管理后台或内部API,安全性往往不够。一旦密码泄露,服务就完全暴露。双向TLS认证的思路是:服务端除了出示自己的证书外,还要求客户端出示一张由可信CA签发的证书,没有证书或证书不合法的连接直接被拒绝。easy-rsa是OpenVPN社区提供的证书管理脚本,把复杂的openssl命令封装成了简单的脚本调用,用它来搭建私有CA并签发证书非常方便。本文完整演示从CA搭建到Nginx双向认证配置的全过程。

Nginx如何搭配easy-rsa实现客户端证书双向认证?

用easy-rsa搭建私有CA并签发证书

easy-rsa的安装很简单,可以直接从GitHub下载发布包,也可以通过系统包管理器安装。以Linux环境为例,解压后进入目录,初始化PKI环境并构建CA:

# 下载并解压 easy-rsa
wget https://github.com/OpenVPN/easy-rsa/releases/download/v3.1.7/EasyRSA-3.1.7.tgz
tar xzf EasyRSA-3.1.7.tgz
cd EasyRSA-3.1.7

# 初始化PKI目录结构
./easyrsa init-pki

# 构建CA,nopass表示CA私钥不加密,生产环境建议去掉nopass
./easyrsa build-ca nopass

执行build-ca时会提示输入Common Name,这是CA的名字,可以随意填写比如MyCorp CA。完成后在pki目录下会生成ca.crt和private目录下的ca.key,这两份文件就是整个信任体系的根,必须妥善保管,尤其是ca.key,一旦泄露任何人都能伪造证书。

接下来签发服务端证书和客户端证书。服务端证书的Common Name填域名,客户端证书的Common Name填用户标识或设备标识,便于后续识别与吊销:

# 签发服务端证书,nginx-server是自定义名称
./easyrsa gen-req nginx-server nopass
./easyrsa sign-req server nginx-server

# 签发客户端证书,user1是客户端标识
./easyrsa gen-req user1 nopass
./easyrsa sign-req client user1

# 生成 Diffie-Hellman 参数(TLS 1.2及以下需要)
./easyrsa gen-dh

签发完成后,关键文件位置如下:服务端证书在pki/issued/nginx-server.crt,服务端私钥在pki/private/nginx-server.key,客户端证书在pki/issued/user1.crt,客户端私钥在pki/private/user1.key,CA证书在pki/ca.crt。需要把这些文件分发到对应的服务器和客户端机器上。

Nginx双向认证的完整配置

Nginx中控制客户端证书验证的核心指令是ssl_verify_client。设置为on表示强制要求客户端证书,验证失败直接握手失败;设置为optional则不强制,可以通过变量判断证书状态后在应用层做访问控制,适合既要开放公开页面又要保护部分路径的场景。

server {
    listen 443 ssl;
    server_name admin.ippipp.com;

    # 服务端证书
    ssl_certificate     /etc/nginx/ssl/nginx-server.crt;
    ssl_certificate_key /etc/nginx/ssl/nginx-server.key;

    # 客户端证书验证
    ssl_client_certificate /etc/nginx/ssl/ca.crt;
    ssl_verify_client on;
    ssl_verify_depth 2;

    # TLS协议与加密套件
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;
    ssl_prefer_server_ciphers on;

    location / {
        proxy_pass http://127.0.0.1:8080;
        # 把客户端证书信息传递给后端
        proxy_set_header X-Client-DN $ssl_client_s_dn;
        proxy_set_header X-Client-Serial $ssl_client_serial;
    }
}

这里注意几个细节。ssl_client_certificate指向的是CA证书而不是客户端证书,Nginx用它来验证客户端证书的签名链。ssl_verify_depth限制证书链的深度,如果是根CA直接签发客户端证书,设为1或2即可。配置完成后先用nginx -t检查语法再reload:

nginx -t
nginx -s reload

验证效果时,如果没有客户端证书直接用浏览器或curl访问,会收到TLS握手失败的提示。携带客户端证书访问则能正常返回内容:

# 无证书访问,会被拒绝
curl https://admin.ippipp.com/

# 携带客户端证书访问,成功
curl --cert user1.crt --key user1.key https://admin.ippipp.com/

# 也可以把证书和私钥合并成pfx格式导入浏览器
openssl pkcs12 -export -out user1.pfx \
    -inkey pki/private/user1.key \
    -in pki/issued/user1.crt \
    -certfile pki/ca.crt

可选模式与证书吊销的进阶用法

强制模式下,没有证书的请求连HTTP层都进不来,如果希望同一个server块既服务公开页面又保护敏感路径,可以把ssl_verify_client改为optional,然后在location中根据$ssl_client_verify变量判断:

server {
    listen 443 ssl;
    server_name mixed.ippipp.com;

    ssl_certificate     /etc/nginx/ssl/nginx-server.crt;
    ssl_certificate_key /etc/nginx/ssl/nginx-server.key;
    ssl_client_certificate /etc/nginx/ssl/ca.crt;
    ssl_verify_client optional;

    location /admin/ {
        # 只有证书验证通过才放行
        if ($ssl_client_verify != SUCCESS) {
            return 403;
        }
        proxy_pass http://127.0.0.1:8080;
    }

    location / {
        proxy_pass http://127.0.0.1:8080;
    }
}

$ssl_client_verify在验证通过时值为SUCCESS,失败时为FAILED或NONE,除了它还有$ssl_client_s_dn可以拿到客户端证书的主体名称,$ssl_client_fingerprint可以拿到证书指纹,利用这些变量甚至能实现基于特定用户证书的白名单控制。

证书吊销是双向认证运维中不可忽视的一环。员工离职或设备丢失时,必须让对应的客户端证书立即失效。easy-rsa通过吊销列表CRL来管理,Nginx加载CRL文件后会在握手时检查证书状态:

# 吊销 user1 的证书
./easyrsa revoke user1

# 生成或更新CRL文件
./easyrsa gen-crl

生成的CRL文件位于pki/crl.pem,把它复制到服务器上并在Nginx中启用:

ssl_crl /etc/nginx/ssl/crl.pem;

reload之后被吊销的证书就无法再通过验证了。需要注意Nginx加载CRL后,所有客户端证书都会被检查吊销状态,所以每次吊销新证书都要同步更新服务器上的crl.pem。

常见问题与运维建议

实际部署中最常遇到的报错是400 No required SSL certificate was sent,说明客户端没有携带证书,或者携带的证书链不完整。特别是浏览器场景,导入pfx时一定要包含CA证书,否则浏览器只会发送终端证书而中间CA缺失,服务端验证链会失败。curl测试时如果证书是中间CA签发的,需要用--cacert参数指定完整信任链。

另一个常见问题是证书过期。easy-rsa默认签发的证书有效期为825天,到期后客户端会突然无法访问。建议建立证书台账记录每张证书的到期时间,续期流程和签发一样,重新gen-req加sign-req即可,客户端换装新证书。也可以在签发时通过easyrsa的EASYRSA_CERT_EXPIRE变量自定义有效期。

安全方面再强调几点。CA私钥务必离线保管,签发证书的机器和运行Nginx的机器尽量分离;客户端私钥建议生成时设置密码保护,虽然使用时多一步输入,但能防止证书文件被拷贝后直接滥用;对安全要求极高的场景,还可以结合Nginx的error_page机制,把验证失败的请求引导到提示页面而不是直接断开。把这套体系搭建好之后,Nginx后面的服务就多了一道比密码强得多的准入门槛,配合防火墙规则,基本可以做到只有特定的人和设备才能访问内部服务。

Nginx双向认证客户端证书修改时间:2026-09-05 08:25:15

免责声明:已尽一切努力确保本网站所含信息的准确性。网站作品多为原创整理与精心创作,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们进行处理Email:chomcom@qq.com。
引用或转载本作品时,请注明当前出处:https://www.ipipp.com/html/20260905/50787.html,基于非商业用途的前提下,欢迎转载或二创本作品。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。