🔒 第04章 · 证书查看与排错
openssl 查看/排查常见报错
04 | 证书查看与排错(openssl)¶
证书出问题时(浏览器报警、续期失败、访问报错),第一反应不是懵,而是用 openssl 把证书"读"出来、把链"对"起来、把报错"定位"出来。这一章把 openssl 排查的整套手法讲透,命令和报错都围绕本机真实证书
bangdream.xyz展开。
openssl 是什么¶
openssl 是 TLS 的事实标准工具箱:生成密钥、签发证书、查看证书、模拟握手、校验签名。它本身不帮你签证书,但能让你看清、诊断、验证手里证书的每一个细节。
# 本机版本(openssl 3.0.13)
openssl version
每张证书的几个"身份证字段"¶
回顾第一章:证书由 subject(我是谁)、issuer(谁签的我)、subjectAltName(我能覆盖哪些域名)、有效期、公钥、签名组成。openssl 把它们一一照出来。
查看本地证书文件¶
/etc/letsencrypt/live/<域>/ 下有四类文件,对应不同用途:
| 文件 | 内容 | 用途 | 查看命令 |
|---|---|---|---|
fullchain.pem |
叶证书 + 中间证书(整条链) | Nginx 用这个 | 用 x509 或 crl2pkcs7 |
cert.pem |
只有叶证书 | 排错时看本站信息 | 用 x509 |
chain.pem |
只有中间证书 | 看是哪个中间 CA 签的 | 用 x509 |
privkey.pem |
私钥 | 绝不能外泄 | 看私钥信息用 pkey |
# 看叶证书的关键字段(本机实测输出)
openssl x509 -in /etc/letsencrypt/live/bangdream.xyz/cert.pem -noout \
-subject -issuer -dates -ext subjectAltName
# 等价地看整条链(文件里多个证书,用 crl2pkcs7 + pkcs7 逐个打印)
openssl crl2pkcs7 -nocrl -certfile /etc/letsencrypt/live/bangdream.xyz/fullchain.pem \
| openssl pkcs7 -print_certs -noout
第一条的输出里你能看到
subject=CN = bangdream.xyz、issuer=O = Let's Encrypt, CN = YE1、两行 Dates 等——这正是证书的"身份字段"。记住issuer是 Let's Encrypt 就说明不是自签名。
查看证书是否到期¶
# -checkend 数字(秒)会在"剩余不足 N 秒时要到期"时报错并返回非零
openssl x509 -in /etc/letsencrypt/live/bangdream.xyz/cert.pem \
-noout -checkend 86400 -date && echo "证书还够 1 天" || echo "证书将到期/已到期"
| 参数 | 作用 | 返回值 |
|---|---|---|
-dates |
打印有效期起止 | 文本 |
-checkend <秒> |
判断剩余是否大于 N 秒 | 满足则 0,不满足非 0 |
校验证书与私钥是否匹配¶
最经典的问题:配置里 ssl_certificate 和 ssl_certificate_key 不是一对(常见于换证书时只换了一半)。校验方法是对比两者的公钥指纹。
# 提取证书里的公钥指纹
printf "" | openssl x509 -in /etc/letsencrypt/live/bangdream.xyz/cert.pem \
-noout -pubkey | openssl sha256
# 提取私钥对应的公钥指纹
openssl pkey -in /etc/letsencrypt/live/bangdream.xyz/privkey.pem \
-pubout -outform DER | openssl sha256
两张指纹一致 → 证书和私钥是匹配的一对;不一致 → 直接把私钥换错/证书发错。这是排查
Cannot find specified certificate key的首选命令。易错点:
privkey.pem是私钥,pkey命令读的是私钥;cert.pem里的-pubkey输出是 DER 编码的公钥。二者要转成同一种摘要方式再比。永远不要把privkey.pem贴进帖子或传给他人。
查看证书链是否完整(缺中间证书?)¶
用 crl2pkcs7 把 fullchain 的每一级都打印出来,看它是否"能追到根"。
openssl crl2pkcs7 -nocrl -certfile /etc/letsencrypt/live/bangdream.xyz/fullchain.pem \
| openssl pkcs7 -print_certs -noout
本机输出能看到"雷神"四级:叶(bangdream.xyz)→ 中间(YE1)→ 根(ISRG Root)。如果只打印出 1 行(只有叶子)说明链里缺中间证书,这正是导致浏览器 unable to get local issuer certificate 的根因。
模拟一次真实握手(ssl_client)¶
要验证远程证书而不是本地文件,用 openssl s_client 主动向服务器发起握手,抓回证书。
# 连本机站点并打印证书
echo | openssl s_client -connect bangdream.xyz:443 -servername bangdream.xyz 2>/dev/null \
| openssl x509 -noout -subject -issuer -dates -ext subjectAltName
# 只看验证结果(0 表示信任链验证通过)
echo | openssl s_client -connect bangdream.xyz:443 -servername bangdream.xyz 2>&1 \
| grep "Verify return code"
-servername是 SNI。访问多域名服务器时必须带上,否则默认取的是服务器"第一个"证书,会让你误判。
常见报错排查表¶
| 浏览器/openssl 报错 | 含义 | 排查动作 |
|---|---|---|
unable to get local issuer certificate |
链不完整,缺中间证书 | 换用 fullchain.pem,看 crl2pkcs7 是否打印多级 |
certificate expired / not yet valid |
过期/未生效 | -checkend,看 -dates,必要时 certbot renew |
| 浏览器红锁 + 域名不匹配 | SAN 不含该域名 | -ext subjectAltName,确认 SAN 里有没有这个域名 |
Cannot find specified certificate key |
证书/私钥不配对 | 比对两者公钥指纹(见上) |
no peer certificate available |
443 没启用 SSL / 端口错 | ss -ltnp | grep 443,看 nginx 是否 listen 443 ssl |
permission denied (publickey) 类 |
证书文件权限错误 | ls -la live/<域>/,确认可被 nginx 用户读取 |
| 浏览器 TLS 报"使用的加密协议" | 协议太旧被拒 | 看 nginx ssl_protocols 是否只开了 TLS1.2/1.3 |
权限问题:为什么 nginx 读不到证书¶
/etc/letsencrypt/live/<域>/ 目录默认是 root 且 drwx------(0700)。Nginx worker 常以 www-data/nginx 用户运行,需要能最终读取到证书文件。
ls -la /etc/letsencrypt/live/bangdream.xyz/
# drwx------ root root -> 这个目录默认只有 root 能进
易错点:如果 nginx 报权限相关错误,常见原因是
live/目录权限过严。通常 certbot 会正确设置,但手动改动过目录结构、或迁移证书后,需要检查nginx -t是否报权限,必要时chmod/ 调整目录可读,或用sudo -u www-data测试读取。
场景:三步定位"为什么访问 https 报错"¶
以本机站点为例,一次完整的排查流程:
# 1. Nginx 配置没错
nginx -t
# 2. 证书还没到期、链完整
openssl x509 -in /etc/letsencrypt/live/bangdream.xyz/cert.pem -noout -dates
openssl crl2pkcs7 -nocrl -certfile /etc/letsencrypt/live/bangdream.xyz/fullchain.pem \
| openssl pkcs7 -print_certs -noout
# 3. 握手能通、验证通过
echo | openssl s_client -connect bangdream.xyz:443 -servername bangdream.xyz 2>&1 \
| grep "Verify return code"
如果 1-3 全过,基本可以断定证书本身没问题,问题在业务层(如 X-Forwarded-Proto、后端、DNS)。
延伸:用 openssl 生成自签名测试证书¶
开发环境临时用,别用在生产:
openssl req -x509 -newkey rsa:2048 -nodes \
-keyout /tmp/dev.key -out /tmp/dev.crt -days 30 \
-subj "/CN=dev.example.com"
安全提醒:自签名证书"谁的根都不是",浏览器必然报警。生产环境一律用 Let's Encrypt(certbot),别把自签名证书挂上去。
下一章:05-security-headers → OCSP / HSTS / 安全响应头,给已经跑通的 HTTPS 加最后一层加固。