证书客户端显示续期成功,浏览器却仍提示证书快过期。遇到这种情况,先别急着重新申请:新证书可能已经写到磁盘,但 Web 服务仍在内存中使用旧证书;也可能域名前面还有 CDN,浏览器看到的根本不是你刚更新的那一张。
管理证书可以沿三步检查:CA 是否签发了新证书,证书是否安装到服务读取的位置,实际对外的 TLS 端点是否开始使用它。acme.sh 能参与这条流程,但路径、权限和重载命令仍需要由部署者配置。
先确定要在哪一层管理证书
如果网站已经由 Caddy、托管负载均衡或其他组件自动管理证书,先查看现有流程。不要仅因为看到一篇 acme.sh 教程,就再给同一个域名增加另一套续期任务。两套程序争用验证端口、覆盖证书文件,排查会更困难。
acme.sh 是基于 Unix shell 的 ACME 客户端,可用于服务器和一些精简系统。它支持不同 CA 和验证方式,但“使用 shell”不等于不需要维护:依赖工具、计划任务、网络访问以及 DNS 凭据都可能影响续期。项目入口是官方仓库,安装方式和版本应从这里核对。
部署前记录执行用户、安装目录、使用的 CA、域名列表和证书接收服务。尤其不要把 CA 留给读者猜。acme.sh 支持 Let’s Encrypt,但并非所有配置都默认使用它,正式命令最好显式指定所选择的服务端。
下面使用 example.com 和示例目录说明,执行前必须替换为自己控制的域名与真实配置。本文未对任何生产域名发起签发,也没有把示例命令写成已完成的线上测试。
HTTP 验证需要请求真正到达正确目录
已有网站时,webroot 模式通常比临时停掉 Web 服务更容易安排。客户端向某个目录写入挑战文件,CA 通过域名的 HTTP 路径读取它。这里最常见的错误,是把服务器上的目录与代理实际提供的目录混为一谈。
acme.sh --issue \
--server letsencrypt \
-d example.com \
-w /var/www/acme-challenge \
--keylength ec-256
这个命令不会自动让 /var/www/acme-challenge 变成可公开读取的路径。Web 服务还需要把 /.well-known/acme-challenge/ 正确映射过去,避免登录拦截、错误跳转或代理到另一个应用。可以先放一个无敏感信息的测试文件,从外部网络读取,确认返回内容来自这台服务。
HTTP-01 的入口使用 80 端口,不能随意改成一个仅自己可访问的高位端口。涉及通配符证书时,应考虑 DNS-01。各类挑战的适用条件见 Let’s Encrypt 验证方式说明。
检查域名时也要看 A 和 AAAA 记录。IPv4 指向新服务器、IPv6 仍指向旧服务器,会让验证结果看起来时好时坏。CDN、负载均衡和多台源站会增加路径,所有可能接到验证请求的入口都应有一致处理。
DNS 验证适合哪些场景
DNS-01 通过 TXT 记录验证域名控制权,适合通配符证书,也适合服务本身不对公网开放的情况。客户端使用 DNS API 自动写入并清理挑战记录,具体环境变量和权限取决于服务商适配脚本。acme.sh DNS API 文档列出了各家要求。
这里不要照抄另一家 DNS 的变量名,也不要把主账号全局密钥写进公开脚本。选择能够满足验证需要的最小权限,尽可能限制到相关区域;如果服务商不支持进一步限制,就把这项权限作为部署风险明确管理。
等待 TXT 生效时,查询自己的本地缓存可能得到旧答案。应核对权威 DNS 和实际传播情况。反复重新签发不一定能缩短传播时间,却可能带来更多挑战记录和速率限制问题。
手工 DNS 模式可以帮助理解流程,但需要人工改记录的方案,不能被称为无人值守续期。部署验收时应让同一个执行用户、同一套凭据完成完整流程,避免第一次在管理员终端成功,之后计划任务因环境变量缺失而失败。
如果还在选择承载博客的服务器,可以将站点和证书目录一起规划。下面是晚安云的配置入口;选环境时先确认能控制域名解析、Web 入口和必要的文件权限,再按应用负载决定规格。
签发目录与服务目录分开
不要让 Nginx 等服务直接依赖 acme.sh 内部管理目录的文件布局。客户端提供 --install-cert 将结果复制到指定位置,并保存后续安装所需的参数。以下例子对应前面选择的 ECC 证书:
acme.sh --install-cert -d example.com --ecc \
--key-file /etc/example-tls/key.pem \
--fullchain-file /etc/example-tls/fullchain.pem \
--reloadcmd '/usr/local/sbin/reload-example-tls'
目标目录、文件权限和脚本都应事先准备。私钥只给必要进程读取,不要为了绕过权限错误把目录改成所有人可写。执行 acme.sh 的用户需要能够完成安装和重载,但不必因此把整个 DNS 管理和日常业务都放进同一套高权限账号。
重载脚本可以先测试配置,再执行服务支持的 reload。例如 Nginx 环境里可先运行 nginx -t,确认路径和语法可用后再重载。这里需要使用实际二进制路径与服务名,不能假定所有系统都安装在同一个位置。
若配置测试失败,脚本应返回非零退出码并留下可定位的日志。为了“让续期变绿”而吞掉错误,会让新证书停留在磁盘上,对外仍使用旧版本。重载动作的成功标准应包括服务状态和外部证书检查。
从外部确认正在使用哪张证书
对直接提供 TLS 的端点,可以用带 SNI 的连接查看证书信息。以下命令是检查示例,不会申请或修改证书:
openssl s_client -connect example.com:443 \
-servername example.com </dev/null 2>/dev/null |
openssl x509 -noout -subject -issuer -dates -serial
命令得到的是这次连接所见证书。若域名指向 CDN,它通常展示边缘证书;源站证书需要在授权的网络路径下另行检查。只看本地文件的过期时间,不能证明访问者已经得到新证书。
也要区分查看日期与验证完整信任链。上面的输出方便比对主体、签发者、有效期和序列号,但不能代替浏览器或客户端的完整验证。需要验证主机名、链和信任库时,使用相应工具选项,并保留真实错误输出。OpenSSL 的选项含义可查 s_client 文档。
负载均衡后面有多台机器时,要确认没有遗漏旧节点。某一次请求命中新节点,不能证明整个集群已经更新。可以按节点检查,或从入口重复观察并结合部署记录核对。
续期任务必须能留下失败记录
确认实际安装是否创建了计划任务,以及任务以哪个用户运行。交互终端中可用的 PATH、环境变量和权限,不一定出现在 cron 中。日志至少需要显示执行时间、目标域名、失败阶段和部署结果,不能把私钥或 DNS token 打出来。
测试时先使用 CA 的测试环境或独立测试域名。Let’s Encrypt 提供 staging 环境,用来验证客户端和流程,生成的证书不应当作浏览器信任的正式证书。测试通过后,再按正确端点申请正式版本。
不要把某个固定天数写成所有证书的续期规则。证书有效期、客户端策略和 CA 能力可能变化。运维侧更适合监控“距离实际到期还有多少时间”和“最近一次安装是否成功”,并提前预留人工修复窗口。
外部到期监控最好独立于签发机器。这样即使 cron 整体停止、主机时间异常或脚本日志没有发出,你仍有机会从访问端发现风险。
换机器时把恢复步骤一起迁走
迁移服务时,既要迁移当前可用证书,也要重新安排未来续期。只复制两个 PEM 文件,新站点可以暂时正常访问,却可能在下一次到期前没有任何任务负责更新。
记录旧机器和新机器各自承担哪些域名,切换后清理不再需要的计划任务。DNS 凭据尽量按新环境重新分配,避免多台遗忘的服务器长期持有同一个宽权限 token。
验收可以从外部请求开始,倒查到服务读取路径、最近安装记录和续期任务。这样不论故障出现在 CA 验证、文件权限还是服务重载,都能找到下一步该检查的位置,而不必先重复申请一张证书。












