Skip to content

关于 Let's Encrypt 证书签发的杂谈

约 2716 字大约 9 分钟

SSL证书HTTPSApache配置DNS

2026-09-12

统计数据加载中...

前言

申请证书时,Certbot 却一直超时。有时是验证方访问不到站点,有时是服务器自己连不上证书签发接口,这两类问题处理方向不同。

先看失败发生在哪一段连接,再决定修正的配置、改用 DNS-01,还是换一台签发机。证书拿到之后,还要完成安装和续期,不能只停在“签发成功”。

先判断失败方向

签发机 → ACME API:创建订单、领取挑战、提交验证、下载证书
验证方 → 站点或 DNS:确认域名控制权
日志表现优先检查
指向 ACME API 的连接、TLS 或读取超时签发机的 DNS、出站网络、代理和 TLS 环境
拉取 /.well-known/acme-challenge/ 超时或内容错误HTTP 入口、重定向、反代、端口和文件路径
查询 TXT、CAA 出现 SERVFAIL,或 DNSSEC 错误权威 DNS、委派、传播及 DNSSEC 配置
During secondary validation继续看后面的具体错误;不同验证位置的结果可能不一致
插件、参数或权限报错本机 Certbot 版本、安装来源、插件和配置

HTTPSConnectionPool 只是连接异常的包装信息,要看其中的主机名和详细原因。ACME API 在多个阶段都会被调用,不能据此断言“订单还没创建”。

同样,During secondary validation 不代表自身配置一定正确。一个解析器返回正常、Apache 语法通过,也不足以排除 IPv6、DNSSEC、CAA 或多个入口配置不一致。

检查签发机能否连接 ACME API

在运行 Certbot 的机器上执行:

curl -4 -sS --connect-timeout 10 --max-time 25 \
  -o /dev/null \
  -w 'http=%{http_code} connect=%{time_connect}s tls=%{time_appconnect}s total=%{time_total}s\n' \
  https://acme-v02.api.letsencrypt.org/directory

本机配置了 IPv6 时,再将 -4 换成 -6 对照。检查是否经过代理,确认 curl 与 Certbot 的网络环境一致。可以从另一台机器交叉测试,但不要连续创建正式订单来试网络。

TCP 连接成功、后续读取超时,只能缩小排查范围,不能直接证明是运营商限速。还要检查代理、路由、TLS、系统时间和远端状态。

DNS-01 不会绕过 ACME API。 这条出站连接不通,换挑战类型也解决不了。先恢复连接;需要异机签发时,按后文同时安排证书安装和续期。

检查验证入口

HTTP-01 从公网 80 端口访问挑战路径。确认 DNS 的 A、AAAA 都指向可用入口,多台反代或负载均衡节点返回相同挑战内容,路径没有被业务路由、登录或错误重定向接管。

DNS 查询失败则检查权威记录和实际委派,不只查本机缓存。开启代理、拿到合成 IP 的开发机也不适合单独作为 DNS 结论依据。

如果 HTTP 挑战入口难以稳定提供,而 DNS 控制正常,可以使用 DNS-01。它验证 _acme-challenge 下的 TXT 记录,不要求访问网站的 80 端口,也支持通配符证书;但 DNS-01 仍依赖 DNS 查询和 CAA 等签发检查,不能治好所有 DNS 故障。具体要求见 Let’s Encrypt 挑战类型

准备 DNS-01 配置

配置项怎样确定
申请域名列出证书需要覆盖的所有名称,不把证书名称与域名列表混为一谈
DNS 区域和记录名从服务商实际托管区域或权威委派确定,不直接截取域名最后两段
插件或钩子根据 DNS 服务商、Certbot 版本和安装方式选择,确认兼容后再安装
DNS 凭据使用独立、最小权限凭据,尽量限定区域或挑战记录,存放在发布目录之外
挑战记录使用本次验证生成的值,等待权威节点可见,清理时只删除本次创建的值
签发与安装位置确认谁运行 Certbot、谁提供 HTTPS,以及续期后如何部署

DNS 修改权限并不是低风险权限,应尽可能缩小范围;支持时可将挑战子域委派到独立区域。凭据文件限制读取权限,不打印内容或打进发布包。

现成且兼容的插件优先。手动模式配合自动化钩子也可以使用,并非只适用于旧版本;反过来,纯交互式手填 TXT 并不等于已经具备自动续期能力。

钩子应完成什么

认证钩子读取 CERTBOT_DOMAINCERTBOT_VALIDATION,在正确区域写入 TXT,并等待传播;清理钩子删除它自己创建的记录。通配符和普通域名可能同时需要同名 TXT,不能清空整组记录。

上线前在不与签发任务冲突的测试域名上验证“写入 → 查询 → 清理”,失败要返回非零退出码。不要固定认为等待 60 秒一定足够,也不要把 .co.uk 等域名直接拆成最后两段。

下面仅演示已经实现并验证钩子后的调用方式。脚本路径、域名和邮箱都需要替换;插件模式则使用对应插件参数,不混抄两套命令。

DOMAIN='example.com'
EMAIL='admin@example.com'
AUTH_HOOK='/受控路径/dns-auth.sh'
CLEANUP_HOOK='/受控路径/dns-cleanup.sh'

certbot certonly --manual --preferred-challenges dns \
  -d "$DOMAIN" --email "$EMAIL" --agree-tos \
  --manual-auth-hook "$AUTH_HOOK" \
  --manual-cleanup-hook "$CLEANUP_HOOK"

条款与账号信息先确认,参数以当前安装版本为准。不要为了兼容示例,把系统包管理器维护的 Certbot 与另一套 pip 依赖混装。参考 Certbot 手动模式

使用另一台机器签发

DNS-01 不要求签发机就是 Web 服务器。原服务器出站故障时,可以在网络正常、受信任的机器签发,再把证书部署到 HTTPS 入口。

签发机 → ACME API

   └─ DNS 插件或受限远程钩子 → 权威 DNS

签发成功 → 受控传输 → HTTPS 入口安装 → 配置检查与重载

DNS 凭据可以留在原来的受控环境,由签发机调用受限远程钩子。远端只允许处理指定区域的挑战操作;域名、TXT 值和操作类型通过结构化输入传递并验证,不直接拼进任意 shell 命令,也不因此授予完整服务器管理权限。

在签发机保留独立的配置、工作和日志目录。那里不仅有证书,还包含 ACME 账号和续期状态;不是签完后就可以删除的临时文件。

证书和私钥通过验证过主机身份的加密连接传输。安装机使用独立版本目录,不手工把外来文件塞进另一套 Certbot 管理的 live/archive/renewal 结构。

安装并验证证书

先备份当前站点配置,保存仍可用的证书回退点。新证书目录限制访问,私钥仅允许必要服务读取。

下面在证书所在目录执行,以公钥比对证书和私钥是否配对。示例需要 Bash;临时目录中只写入公钥:

(
  set -euo pipefail
  TMP_DIR=$(mktemp -d)
  trap 'rm -rf "$TMP_DIR"' EXIT

  openssl x509 -in fullchain.pem -noout -pubkey > "$TMP_DIR/cert.pub"
  openssl pkey -in privkey.pem -pubout > "$TMP_DIR/key.pub"
  cmp "$TMP_DIR/cert.pub" "$TMP_DIR/key.pub"

  openssl x509 -in fullchain.pem -noout -dates -ext subjectAltName
)

配对正确还不够:检查 SAN 覆盖目标域名、有效时间和证书链。不要只看 subject 或 issuer 是否包含某个品牌名称。

Apache 站点指向已经确认的新文件:

SSLCertificateFile /受控证书目录/fullchain.pem
SSLCertificateKeyFile /受控证书目录/privkey.pem

然后检查配置,成功才重载:

sudo apache2ctl configtest && sudo systemctl reload apache2

配置失败时恢复备份,不反复重启服务碰运气。公网验证不使用 -k

DOMAIN='example.com'
curl -sS -o /dev/null \
  -w 'http=%{http_code} verify=%{ssl_verify_result}\n' "https://$DOMAIN/"

核对 curl 退出码,并从干净、可信的证书存储环境测试域名校验;浏览器无痕模式不会自动清除系统信任的根证书。多入口站点还要逐个核对实际提供的证书,不只看一次域名访问。

续期由谁负责

异机签发不意味着证书必然不能自动续期,关键是在哪台机器续期、续期后如何送到入口。可以选择两种方式:

方式必须补齐
签发机长期负责保留其 Certbot 状态、调度和 DNS 权限;成功续期后安全分发,入口检查并重载
安装机接管恢复网络后,用自己的受控配置完成签发与续期验证,再切换站点证书引用

只在安装机放入两个 PEM 文件,不会让它的 Certbot 自动管理这张证书。反过来,续期配置文件存在,也不等于定时任务或部署钩子正常。

在实际负责续期的机器上检查:

# CERT_NAME 使用列表中的实际证书名称,不一定等于单个域名
certbot certificates
: "${CERT_NAME:?请先设置实际证书名称}"
certbot renew --cert-name "$CERT_NAME" --dry-run

自定义配置目录时,续期任务也要使用同一目录。dry-run 会访问测试 ACME 服务,并可能真实修改挑战 TXT;它不是完全无副作用,也不能证明生产端点一定可达。生产和测试端点分别判断,测试证书不部署到生产。详见 Certbot 续期说明

再检查调度、执行用户、PATH、日志和成功续期后的部署钩子。定时任务不会自动继承交互终端环境;“已签出新证书但重载失败”时,要查看真实退出码和错误,不只搜成功提示。

不要写死“90 天有效、提前 30 天续期”,以证书实际有效期和客户端策略为准,并对外部可见证书设置到期告警。完成接管后,确认续期、安装及公网验证都通过,再撤销临时任务、清理无引用且不再需要回退的文件。旧私钥也不会因为换了证书就自动失效。

完成检查

  • 已按日志区分出站连接与挑战验证问题,没有只靠关键字下结论。
  • 签发成功,域名覆盖、密钥配对和公网证书验证通过。
  • 明确负责续期的机器,调度、挑战权限和部署链路都有验证结果。
  • 失败时有可用配置回退点,临时方案设有截止时间和告警。

遇到暂时故障可以受控重试,但要遵守限流和退避。先确认方向再处理,比反复申请正式证书更有效。

暂无评论

暂无评论,来添加第一条评论吧!