服务器和代理
SSL_CTX_use_PrivateKey failed:Nginx 私钥加载失败
nginx: [emerg] SSL_CTX_use_PrivateKey("/etc/nginx/ssl/example.com.key") failedNginx 用不了 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. 私钥和证书不匹配
- 确认: 上面两个哈希不一样,或者密钥匹配工具提示证书和 CSR 不是一对。
- 修复: 见 Nginx key values mismatch。
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。