我目前正在尝试将 nginx 设置为需要证书认证的网站的代理。以下 curl 命令运行良好:
curl --cacert ca-cert.pem -v --key client.key --cert client.pem https://example.com:443
但是,以下 nginx 配置似乎被服务器拒绝:
server {
listen 80;
location / {
proxy_pass https://example.com;
proxy_set_header Host example.com;
proxy_ssl_certificate /etc/nginx/client.pem;
proxy_ssl_certificate_key /etc/nginx/client.key;
proxy_ssl_trusted_certificate /etc/nginx/ca-cert.pem;
proxy_ssl_verify off;
}
}
nginx 日志中的完整错误是:
2021/03/08 20:43:06 [error] 29#29: *1 SSL_do_handshake() failed (SSL: error:14094418:SSL routines:ssl3_read_bytes:tlsv1 alert unknown ca:SSL alert number 48) while SSL handshaking to upstream, client: 172.17.0.1, server: , request: "GET / HTTP/1.1", upstream: "https://x.x.x.x:443/", host: "localhost:80"
有人知道发生了什么吗? nginx 配置不是等同于 curl 命令吗?
答案1
...ssl3_read_bytes:tlsv1 警报未知 ca
由于缺少中间证书,上游服务器无法验证发送客户端证书。因此,它会将问题原因作为警报发送回 nginx。修复方法可能是按client.pem
正确的顺序添加必要的中间证书(即首先添加叶证书,然后添加已签名的叶证书等)。
但是为什么它能与 curl 配合使用呢:根据 curl 使用的 TLS 堆栈,也可能取决于 curl 的版本,它会自动将给出的证书与--cert
给出的匹配中间证书相结合--cacert
,并将完整链作为客户端证书的一部分发送到服务器。如果这样做,那么服务器就可以成功验证客户端证书。
答案2
https://example.com
如果 http 服务器为多个(“虚拟”)主机提供服务并且即使在 SSL 握手期间未指定任何主机也会做出答复,则可能会有差异。
现代的卷曲版本默认使用发送服务器名称指示(SNI
), 然而nginx需要明确启用它。
proxy_ssl_server_name on;
添加到 nginx conf后尝试相同操作。
或者查看上游 http 服务器的服务器日志 - 他们会注意到默认主机的连接(而不是的连接example.com
)。
答案3
此错误意味着 nginx 无法验证上游服务器的 TLS服务器使用您在 中提供的 CA 证书proxy_ssl_trusted_certificate
。检查您是否确实提供了签署服务器证书的 CA 证书。
答案4
我遇到了同样的问题。我通过使用链式证书而不是主证书解决了这个问题。您可以在以下网址免费创建链式证书https://tools.keycdn.com/certificate-chain