双容器配置求助:LetsEncrypt 已故障数日

我已经到了绝望的边缘,因为试图让 Discourse 机器人或 Claude 来解决这个问题似乎是不可能的。我真的无法清楚地解释这个问题,因为我的技术知识有限,我认为这才是真正困扰我的地方。

我会尝试从我的角度解释一下发生了什么。

当我从单容器迁移到双容器时,samples/ 目录中的文件使用了 web-only,我错误地保留了它,而没有使用 web_only

然后,由于这个原因(我认为是这样),我的图片无法加载,因为某个“部分”预期指向 web_only,但它被设置为了 web-only。我进行了一些更改,图片问题得到了修复。现在的问题在于 Let’s Encrypt 证书。

我让机器人帮我修复,它让我等到第二天,因为问题是证书速率限制。问题应该会自动解决。但没有。然后我又问了它一次,接着问了 Claude,又问了 Claude 一次……过去一周我们一直在经历这种“等到明天 X 点它一定会修好”的循环。它从来没有修好,它们都说“哦,对不起,我不应该假设它会修好,让我们试试这个,因为现在它真的会修好了”。但事实并非如此。

网站本身是正常运行的,但我感觉每次我想重建时,都会出点什么事,老实说,我不想总是依赖这种权宜之计。

Claude 告诉我向 web_only.yml 中的 hooks 添加某些内容,但这里论坛提供的说明中并没有提到类似的东西,所以我期待另一种解决方案,比如……解决实际问题。

请有人能帮我弄清楚问题所在,以及哪里出现了故障吗?我会非常感激,因为到目前为止这真的让人精疲力竭。不是工作本身,而是不明白发生了什么,以及为什么“等到明天”似乎永远无法解决任何问题。

谢谢!


我让 Claude 解释一下问题似乎是什么,也许这会有帮助?这是它说的:

标题: 双容器设置:拆分后 ECC 证书文件夹缺失,每次启动时 --force 循环触发速率限制

设置: 两个容器(data + web_only),从独立模式迁移而来。模板:web, ratelimited, ssl, letsencrypt, cloudflare。主机名 alltiago.com,无别名。

症状: 每次启动 web_only 时都会触发 Let’s Encrypt 速率限制,nginx 无法提供服务,返回连接错误,直到手动从 /etc/nginx/conf.d/outlets/server/20-https.conf 中移除 ECC 行。

我发现的情况:

/shared/letsencrypt/alltiago.com_ecc/ 在我的安装中不存在。/shared/letsencrypt/alltiago.com/(RSA)存在并正常工作,正常续期。

web.letsencrypt.ssl.template.yml 中:

cert_exists() {
  [[ "$(cd ${LETSENCRYPT_DIR}/${DISCOURSE_HOSTNAME}$1 && openssl verify -CAfile <(openssl x509 -in ca.cer) fullchain.cer | grep "OK")" ]]
}

issue_cert "ec-256"
if ! cert_exists "_ecc"; then
  issue_cert "ec-256" "--force"
fi

由于目录缺失,cert_exists "_ecc" 在每次启动时都会失败,因此 --force 会运行并请求一个全新的 ECC 证书,无论磁盘上有什么。这是通过 after_ssl 钩子实现的,该钩子修补了 /etc/runit/1.d/install-ssl,因此它不仅在引导时运行,而且在每次容器启动时都会运行。

结果:429 too many certificates (5) already issued for this exact set of identifiers in the last 168h。然后 --installcert 仍然针对空目录运行,并写入一个不可用的 /shared/ssl/alltiago.com_ecc.cer。nginx 配置了两个证书,无法加载 ECC 证书,因此无法提供服务。

已确认正常工作: ACME HTTP-01 验证成功(通过 staging 测试,ECC 证书针对 letsencrypt_test 正常签发,目录结构创建正确)。RSA 证书今天成功续期。所以这不是 DNS、防火墙或验证的问题。

问题:

  1. 是否有支持的方法可以在不等待速率限制过期的情况下重建 alltiago.com_ecc/
  2. cert_exists 返回 false 是否应该触发 --force 而不是正常的 issue?--force 会绕过“现有有效证书”检查,并在目录缺失时保证速率限制耗尽。
  3. 是否有文档说明如何仅运行 RSA?

为了不让话题跑偏,这里有两个事实说明:重试日期从 8 月 27 日推迟到了 8 月 29 日,因为今天的 RSA 续期消耗了滚动 168 小时窗口中的一个名额。而且没有人报告这个问题的原因是,在正常安装中,两个目录都会在首次启动时创建,并且 --force 分支永远不会运行。

等等。https://alltiago.com/ 似乎运行正常。但我原本想推荐的做法如下

有,但比较棘手。如果你请求一个不同的证书,你的计数就会重新开始。

我可能会建议你在主机名中添加 www,这样你就能同时获得两个域名的证书(不过也许你已经这样做了,那你也可以添加第三个域名,只是为了获取一个新证书)。

Set up Let’s Encrypt with multiple domains / redirects 应该能帮到你。

是的,确实如此,因为有人让我使用一个与 nginx 相关的“临时补丁”。我其实无法准确解释这是什么,因为我自己也不懂。
但问题在于,如果之后我想进行一次正常的重建(rebuild),就会遇到问题(至少根据我现在得到的说法,如果在 8 月 29 日之前操作,届时希望证书能重新签发。说实话,我现在对这一切都不太敢确信。

是的,www 在我去年首次安装 Discourse 时就已经配置好了。

现在,在我尽力让 Claude 帮我理解发生了什么之后,我得到了以下结论。如果你有任何异议,请尽管提出,因为如果有学习机会,我很乐意学习:

  • ECC 似乎是目前的问题所在,但实际上它并非真正必要,因为 RSA 是默认设置,如果我完全弃用 ECC,大家仍然可以无问题地访问我的网站。
  • 如前所述,希望到了 8 月 29 日,随着 168 小时的重置以及 5 个证书限制的重置,这整个问题就会消失:
sudo docker exec web_only grep -i "retry after" /shared/letsencrypt/acme.sh.log | tail -1
  "detail": "too many certificates (5) already issued for this exact set of identifiers in the last 168h0m0s, retry after 2026-08-29 03:43:15 UTC: see https://letsencrypt.org/docs/rate-limits/#new-certificates-per-exact-set-of-identifiers",
  • 如果 8 月 29 日情况仍未恢复正常,Claude 建议弃用 ECC。当我询问会修改哪个文件以及哪个部分时,它是这样说的:

文件: 我们即将创建的那个副本,web.letsencrypt.rsa-only.template.yml(保持你原始的库存文件不变,作为后备)。

其中被移除的内容: 在文件的 /usr/local/bin/letsencrypt 部分中找到的整个代码块:

########################################################
# ECDSA cert
########################################################
issue_cert "ec-256"

if ! cert_exists "_ecc"; then
  # Try to issue the cert again if something goes wrong
  issue_cert "ec-256" "--force"
fi

LE_WORKING_DIR="${LETSENCRYPT_DIR}" ${LETSENCRYPT_DIR}/acme.sh \
  --installcert --ecc \
  -d ${DISCOURSE_HOSTNAME} \
  --fullchainpath /shared/ssl/${DISCOURSE_HOSTNAME}_ecc.cer \
  --keypath /shared/ssl/${DISCOURSE_HOSTNAME}_ecc.key \
  --reloadcmd "sv reload nginx"

这就是整个 ECC 部分,文件中其他内容不变。它上方的 RSA 部分保持原样。

之后还会修改另一个文件: containers/web_only.yml,使其指向这个新的副本,而不是库存模板。我们将作为单独的后续步骤来执行此操作。

嗯。不。我不会去改任何模板。

我觉得最简单的办法就是先等等,然后用默认模板重新构建。除非你以后想一直依赖 AI 的支持,而不是找那些真正懂 Discourse 的人。

我让 Claude 按照你的建议,添加了一个新的证书请求(如果这么叫的话?),现在看起来已经正常工作了。

当我问哪些文件是这次操作留下的残留文件时,得到了以下回复:

以下是实际存在的文件,按今晚(本次会话)产生的文件和之前(本次对话之前)的旧残留文件进行了区分:

今晚(本次会话)产生的:

  • /tmp/acme.sh.txt — 你要求下载的那个脚本副本,既然你的 Mac 上已经有了,现在可以安全删除
  • /tmp/crtsh.json — 来自 crt.sh 502 错误的空文件(150 字节),是垃圾文件,可以安全删除
  • /root/discourse-backup-20260827-1857.tar.gz — 今晚早些时候做的真实备份(SSL/Let’s Encrypt 配置),这个文件其实值得保留,不是垃圾文件

较旧的,来自本次对话之前(8 月 23 日和 8 月 25 日),不是我放进去的:

  • /tmp/app.yml
  • /tmp/check.png, /tmp/check162.png, /tmp/after.png, /tmp/rendered_avatar.png

我不知道这些旧文件是做什么用的,它们早于我们今晚所做的任何操作,很可能是之前某次故障排除会话(你的、机器人的,或之前的 Claude 对话)留下的。你认得这些文件吗?或者需要我帮你弄清楚它们来自哪里,然后再决定是删除还是保留?

/tmp/root 之外没有发现任何可疑内容,更广泛的系统扫描结果是干净的,只有一些正常的日志文件。


我可以把上面提到的这些文件都删掉吗?

那我是不是应该撤销我刚才做的操作?

我完全乐意和真人交流,只是我不想把所有问题都贴在这里,用整个处理过程(终端的输出/日志)刷屏论坛。相反,我宁愿先弄出一个已经“差不多”能用的方案,让对话简短一点。我们都有自己的生活和有限的时间,除非我真的走投无路,否则我不想一上来就跑去论坛求助,你明白吗?

非常感谢你的帮助!
所以,现在,我应该撤销我刚才做的操作吗?与直接等到 29 号相比,你觉得这种做法有什么问题吗?

我的建议仍然是等待,直到你认为自己能够获取新证书,并将所有设备恢复为官方原版系统。