ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Caddy 中间证书过期导致 HTTPS 证书报错:openssl 定位 + Caddyfile 修复指南

Caddy 中间证书过期导致 HTTPS 证书报错:openssl 定位 + Caddyfile 修复指南 Caddy 中间证书过期导致 HTTPS 证书报错openssl 定位 Caddyfile 修复指南【免费下载链接】caddyFast and extensible multi-platform HTTP/1-2-3 web server with automatic HTTPS项目地址: https://gitcode.com/GitHub_Trending/ca/caddy用户集中反馈你的站点弹出“您的连接不是私密连接”可 openssl 一看叶子证书剩余有效期还有 60 多天——这多半就是 Caddy 中间证书过期在作怪。本文按“定位 → 修复 → 自动兜底”的顺序带你把这类 Caddy 证书链异常一次修干净并让它不再复发。原理速览中间证书过期为什么拖垮整条信任链先说白话浏览器和操作系统里只预装了各 CA 的根证书相当于“总公章”而你的域名证书并不是根证书直接签发的中间隔了一层中间证书CA 专门用来签发域名证书的“二级公章”。Caddy 在 TLS 握手时会把叶子证书 中间证书一起发给客户端浏览器拿这两者往上拼出一条链验证到预装的根证书为止任何一环失效整条链就作废。CA 为什么非要定期换中间证书因为中间证书是真正高频签发的那一环轮换它可以把私钥泄露的影响面锁死在几年的时间窗口内。Lets Encrypt 就经历过 E1 → E2 这样的 Lets Encrypt 中间证书轮换E1 到期后的那一波故障里不少服务器叶子证书明明有效页面却一片红——和中间证书过期引发的 HTTPS 信任链排查是同一个病灶叶子没事链断了。上图为 Caddy 中间证书过期场景下的信任链C → B → A 任一环节失效浏览器即判定连接不安全。 快速定位三个地方看找出链断在哪一环openssl 一条命令验证服务端证书链在能直连该站点的机器上执行把域名换成你的openssl s_client -connect example.com:443 -showcerts /dev/null正常时输出里逐张列出证书结尾是Verify return code: 0 (ok)链上每张证书的有效期都盖过今天。异常时结尾出现Verify return code: 21 (certificate expired)或20 (unable to get local issuer certificate)并且你能在打印的证书列表里看到某一环的notAfter已经过期——通常断的那一环就是中间证书而不是叶子。Caddy 日志和管理接口里找证书线索翻一下 Caddy 的错误日志关注 x509 和过期字样grep -Ei x509|expired|failed to verify certificate /var/log/caddy/*.log正常时日志里只有签发、续期这类良性记录。异常时会看到类似tls: failed to verify certificate: x509: certificate signed by unknown authority的条目直接指向链验证失败。另外可以问管理接口 Caddy 现在到底加载了哪些证书curl -s http://localhost:2019/config/json/tls你会看到当前生效的证书加载器和自动化策略确认这个域名是“自动签发”还是“手动加载”这决定后面走哪条修复路径。浏览器证书路径视图打开站点 → 点地址栏的锁形图标 → “连接是安全的” → “证书有效” → 切到证书路径页签。正常时路径上三层证书状态全绿从服务器证书一路指到受信任的根。异常时中间那一层会直接标红“此证书已过期”或打叉——这和 openssl 的结论应当一致不一致时优先信 openssl。 修复路径按证书来源分两种修法Caddy 证书链异常的修复本质让握手时出示的中间证书重新处于有效期内。场景 ALets Encrypt 等 CA 自动签发auto-HTTPS如果 2019 接口的 tls 配置显示该域名走automate自动签发基本不用你碰证书文件。Caddy 的证书生命周期管理见 modules/caddytls/certmanagers.go默认在剩余有效期跌到总时长的 1/3 时触发重签发——对 Lets Encrypt 的 90 天证书就是到期前约 30 天。重签发时 ACME 流程会从 CA 目录拉取当时最新签发的中间证书并写入存储旧的失效链自然被替换。所以你的操作只有两件事确认 Caddy 进程正常、出网没被防火墙拦 443/80然后执行一次重载让新证书进入连接池caddy reload --config Caddyfile如果等不到续期窗口、需要立刻恢复重启 Caddy 让它尽快检测到证书问题并走签发流程比手动改文件干净得多。验证再跑一遍openssl s_client -connect example.com:443 -showcerts /dev/null确认Verify return code: 0 (ok)且链上中间证书是 CA 当前在用的那张。场景 B自签或第三方证书用 tls 指令手动加载这类证书 Caddy 不会帮你续链坏了只能换文件。步骤向 CA 或证书供应商要一张最新的中间证书CA 官网的证书/下载页里有当前有效的 intermediate把叶子和中间证书拼成完整链fullchain即“全链”PEM叶子在前、中间在后cat example.leaf.crt example.intermediate.crt example.fullchain.pem在 Caddyfile 的站点块里用tls指令指向新链文件example.com { tls /etc/caddy/certs/example.fullchain.pem /etc/caddy/certs/example.key }热加载不用停服务caddy reload --config Caddyfile验证同样用openssl s_client复查重点看输出里第二张证书中间证书的签发者是否已换成 CA 新签发的那张、有效期是否已更新。 让 Caddy 自动兜底把人工介入压到最低如果证书链是你自己拼、自己换的说明这个域名还没交给自动签发。对公网域名最省心的做法是让 Caddy 的 auto-HTTPS 接管它会按 modules/caddytls/automation.go 里的策略自动申请、续期、拉新链CA 轮换中间证书时你也只是“下次续期自动换上新链”零操作。再配一个稳定的存储位置防止重启、迁移时证书和 ACME 账户信息丢失{ storage file_system /etc/caddy auto_https on } example.com { root * /var/www/html file_server }auto_https on在 Caddy 里本来就是默认行为这里写出来是强调“别关”storage指定证书与账户的落盘目录默认也是文件系统存储见 modules/filestorage/。只要这两样在CA 换中间证书对你就只是日志里多一行“新证书已签发”。防复发一条 grep 加一条告警规则就够了日志侧把证书关键字巡检扔进定时任务有命中当天就会有人知道0 8 * * * grep -Ei x509|expired /var/log/caddy/*.log | mail -s Caddy cert alert opsexample.com监控侧如果你已经接了 Prometheus加一条“30 天内到期”的告警即可指标名按你实际采集到的为准- alert: CaddyCertExpiringSoon expr: caddy_tls_certificate_expiry_timestamp_seconds - time() 86400 * 30 for: 5m labels: severity: warning两条都不用多覆盖“链断了”和“快断了”两种情况。日常巡检清单用openssl s_client看链而不只看叶子Verify return code必须是 0且中间证书的notAfter也在未来CA 官宣中间证书轮换尤其 Lets Encrypt时把 Caddy 自动签发的域名挨个过一遍 openssl备份 storage 目录/etc/caddy并确认它可写迁移或换机后重启验证证书能正常加载日志里x509、expired关键字进每日巡检别等用户投诉才翻日志升级 Caddy 版本后跑一次caddy validate --config Caddyfile确认 tls 相关指令没有解析变化Caddy 把“自动 HTTPS”做成了默认行为就是让你不必手工维护证书——把 storage 管稳、巡检节奏保持住证书链问题就只是 5 分钟的小活而不是又一次线上事故。【免费下载链接】caddyFast and extensible multi-platform HTTP/1-2-3 web server with automatic HTTPS项目地址: https://gitcode.com/GitHub_Trending/ca/caddy创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进