服务器和代理

SSL_CTX_use_PrivateKey failed:Nginx 私钥加载失败

作者: · 最后核实

报错信息nginx: [emerg] SSL_CTX_use_PrivateKey("/etc/nginx/ssl/example.com.key") failed

Nginx 用不了 ssl_certificate_key 指定的私钥时,就会打印这条报错,或者与之相近的 cannot load certificate key "...": PEM_read_bio_PrivateKey() failed。 failed 后面括号里的内容说明原因:私钥和证书不是一对、文件不是 PEM 私钥、私钥加了密码,或者 Nginx 没权限读这个文件。

快速修复

日志括号里的原因决定修法,对照下表就能找到对应的原因。先在 Nginx 之外单独检查私钥和证书:

sudo openssl pkey -in /etc/nginx/ssl/example.com.key -noout && echo "私钥能解析"
sudo openssl x509 -in /etc/nginx/ssl/example.com.crt -noout -pubkey | openssl sha256
sudo openssl pkey -in /etc/nginx/ssl/example.com.key -pubout | openssl sha256

再对照日志里括号中的原因:

日志里的原因 含义 看哪里
key values mismatch 私钥属于另一张证书 key values mismatch
no start line、DECODER routines::unsupported 不是 PEM 私钥 原因 2
bad decrypt、bad password read、提示输入密码 私钥被加密 原因 3
Permission denied、No such file or directory 文件访问问题 原因 4

修好后执行 sudo nginx -t && sudo systemctl reload nginx。

原因

私钥和证书不匹配最常见,其次是格式不对、私钥加密和文件权限。

1. 私钥和证书不匹配

2. 文件不是 PEM 格式的私钥

Nginx 要求 PEM 格式,开头是 -----BEGIN PRIVATE KEY-----、BEGIN RSA PRIVATE KEY 或 BEGIN EC PRIVATE KEY。DER 二进制文件、PKCS#12(.pfx/.p12)、把证书当成私钥、空文件,都会出现 no start line(OpenSSL 1.1.1)或 DECODER routines::unsupported(OpenSSL 3)这类解码错误。

  • 确认: head -1 example.com.key 看不到 BEGIN ... PRIVATE KEY,或者 file example.com.key 显示是二进制数据。
  • 修复: 转换格式:
# DER 转 PEM
openssl pkey -inform DER -in example.com.der -out example.com.key
# PFX 中导出 PEM 私钥
openssl pkcs12 -in site.pfx -nocerts -nodes -out example.com.key

另外检查文件开头有没有被 Windows 记事本加上的 BOM,或者 CRLF 换行(用 dos2unix 处理)。

3. 私钥是加密的

带密码的私钥开头是 BEGIN ENCRYPTED PRIVATE KEY(或含 Proc-Type: 4,ENCRYPTED)。Nginx 会在终端提示输入密码,用 systemd 或面板启动时就报 bad decrypt 或 bad password read。部分 CA 平台生成 CSR 时会让你设私钥密码,下载下来的私钥就是加密的。

  • 修复: 把密码写进只有 root 可读的文件并引用:
ssl_certificate_key /etc/nginx/ssl/example.com.key;
ssl_password_file   /etc/nginx/ssl/example.com.pass;

或者用 openssl pkey -in enc.key -out example.com.key 解密一次,并 chmod 600。

4. 文件权限、路径或 SELinux

  • 确认: 报错里有 BIO_new_file() failed,并带 Permission denied 或 No such file or directory。CentOS、Rocky 等系统上,ls -Z 显示文件标签是 user_home_t(从家目录 mv 过来的文件常见)。
  • 修复: 修正路径,chown root:root、chmod 600;开启 SELinux 的系统执行 sudo restorecon -Rv /etc/nginx/ssl 恢复标签。

5. OpenSSL 版本不支持该私钥类型

很老的 OpenSSL 不认识较新的密钥类型,部分 FIPS 模式的构建会拒绝不合规的密钥。

  • 修复: 使用 RSA 2048 位以上或 ECDSA P-256/P-384 私钥,现有版本都支持。

各环境修法

Nginx 在任何系统上都要求私钥是未加密的 PEM 文件(或配好密码文件)、路径正确、权限收紧。

宝塔面板: 在站点“SSL → 其他证书”里粘贴,不要直接改 /www/server/panel/vhost/cert/ 下的文件权限。粘贴的私钥若带 ENCRYPTED 字样,先在本地解密再粘贴。

Debian / Ubuntu: 私钥一般放在 /etc/ssl/private/ 或 /etc/nginx/ssl/。

CentOS / Rocky / AlmaLinux / Alibaba Cloud Linux: 放在 /etc/pki/tls/private/ 或 /etc/nginx/ssl/,复制后执行 restorecon。

Docker: 以只读方式挂载私钥,注意容器以什么用户启动;官方 Nginx 镜像主进程是 root,rootless 镜像可能需要私钥对其运行用户可读。

Let's Encrypt: 引用 /etc/letsencrypt/live/<名称>/privkey.pem,Certbot 生成的是未加密的 PEM 私钥,权限已经收紧。

不要这样做

放宽私钥权限、明文存密码、把私钥放进网站目录,都会增加私钥泄露的风险。

  • 为了“解决权限问题”把私钥改成 644 或 777。 本机任何用户、被入侵的网站程序都能把私钥拷走。
  • 把私钥密码写在 Nginx 配置里或所有人可读的文件里。 用 ssl_password_file,并且只给 root 读权限。
  • 把证书和私钥放在网站根目录下。 一条写错的 location 规则就可能让所有人下载到私钥。

常见问题

每次重启 Nginx 都提示 Enter PEM pass phrase,怎么去掉?

这个提示说明私钥是加密的,配好密码文件或解密私钥就不会再出现。要么把密码写进一个只有 root 能读的文件,用 ssl_password_file 引用;要么用 openssl pkey -in enc.key -out example.com.key 解密出一份,再 chmod 600 保护。自动重启和面板操作没法手动输密码。

手上只有给 IIS 用的 .pfx 文件,怎么拆成 Nginx 用的?

私钥用 openssl pkcs12 -in site.pfx -nocerts -nodes -out example.com.key 导出,证书链用 -nokeys 导出。阿里云、腾讯云也可以直接重新下载“Nginx”格式。各格式区别见 SSL 格式转换工具。

私钥要让 www 或 nginx 用户可读吗?

不需要。Nginx 主进程以 root 身份运行,在启动时读取证书和私钥,worker 进程不需要访问。私钥保持 root 所有、权限 600 即可。宝塔默认的证书目录权限已经处理好,不要手动改成 755 或 777。

资料来源

  1. nginx ngx_http_ssl_module (ssl_certificate_key, ssl_password_file)
  2. nginx: Configuring HTTPS servers
  3. OpenSSL openssl-pkey
  4. OpenSSL openssl-rsa