维护页面的变通方法——这能做到吗?

是的,我会分阶段进行:

  1. 获取一台性能稍强的服务器
  2. 完成两个容器的安装配置

如果此时你已满意,可以到此为止,或者:

  1. 按照 @Lilly 上面提供的优秀指南来实现维护页面。:+1:

哈哈,很高兴你问了这个问题,因为我之前没花时间解释这部分(我应该解释的——这里有很多内容需要说明,而且 Cloudflare 很复杂!)

当设置了 Workers 路由页面时,论坛上的每一个图片加载和页面浏览都会通过该 Worker 进行路由。

Cloudflare 免费 CDN 计划包含 Worker 路由每天 100,000 次请求的限制

因此,如果你的论坛流量相对较大,为了防止在一天内达到免费版的上限,最好不要一直开启它。这里指的是 Worker 路由,而不是维护页面——你可以一直保留维护页面,除非你开启了 Worker 路由,否则它不会被触发。这仅仅是指 上面步骤 2 中你分配路由的部分(设置和删除都很简单)。除非你使用的是 Cloudflare 付费计划,否则良好的做法是仅在进行自己的维护时才开启它。

  1. 前往你域名的 Cloudflare Workers 路由页面,点击路由右侧的按钮。

  1. 在编辑屏幕底部,点击 remove(移除)按钮,将 Worker 页面从路由中分离。

  1. 别担心,Worker 代码本身不会被删除,只是路由规则被移除。下次你进行重建/更新时,可以像 上面的步骤 2 那样再次添加它。

如果你使用的是 Cloudflare 付费计划,那就不用担心了。不过,那样的话你可以直接使用 Cloudflare 的错误页面,而不是使用 Workers 页面……(我是不是说过 Cloudflare 挺复杂的?LOL)

:warning: 下方为高级管理员配置

如果想在免费版上完全自动化更新,则应使用 Cloudflare API 令牌、你的区域 ID (zone-id) 以及 curl 命令来获取 Worker 的 route id(路由 ID)。然后编辑 /root/update-web.sh 脚本,添加一些有趣的内容,以自动开启和关闭 Worker 路由:

#!/bin/bash
cd /var/discourse

CF_TOKEN="your_actual_token_here" #<---Cloudflare API 令牌
ZONE_ID="xxxx" #<---来自你的 Cloudflare 个人资料页面
ROUTE_ID="xxxx"
WORKER_NAME="my-site-maintenance-page"

echo "➡️ 正在拉取最新的 Discourse Docker 脚本..."
git pull

echo "➡️ 在后台引导新的 Web 容器..."
./launcher bootstrap web_only

if [ $? -eq 0 ]; then
    echo "✅ 引导成功!"
    
    # 开启 Cloudflare 维护 Worker
    echo "🚧 正在启用维护页面..."
    curl -s -X PUT "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/workers/routes/$ROUTE_ID" \
         -H "Authorization: Bearer $CF_TOKEN" \
         -H "Content-Type: application/json" \
         --data '{"pattern":"*your-site.com/*","script":"'$WORKER_NAME'"}' > /dev/null

    # 交换容器(30秒的停机窗口)
    echo "🔄 正在交换容器..."
    ./launcher destroy web_only && ./launcher start web_only
    
    # 关闭 Cloudflare 维护 Worker
    echo "🌍 正在禁用维护页面..."
    curl -s -X PUT "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/workers/routes/$ROUTE_ID" \
         -H "Authorization: Bearer $CF_TOKEN" \
         -H "Content-Type: application/json" \
         --data '{"pattern":"*your-site.com/*","script":null}' > /dev/null

    echo "🚀 完成!网站已更新,且无可见停机时间。"
else
    echo "❌ 引导失败!中止交换以保持当前网站在线。"
fi 

我使用的是旧版本的脚本,因为我不想自动化所有事情,而且我喜欢亲自参与更新/重建过程。我只需要在更新前添加 Workers 路由,然后在更新后移除它。这只需要几秒钟。

我的一般步骤如下:

  1. 在 Cloudflare 上添加 Workers 路由
  2. SSH 连接到 Hetzner
  3. 执行任何系统更新(例如:sudo apt update && sudo apt upgrade -y,如有必要则重启服务器)
  4. 如果需要重启,则再次 SSH 连接
  5. 运行 ./update-web.sh
  6. 在 Cloudflare 上移除 Workers 路由

我对编程和开发领域几乎一无所知,除了很久以前我用 Visual Basic 做过一个“Hello World”的小程序。但我还是能搞定一些事情,因为我更熟悉如何管理我的 WordPress 和 Mastodon/Pixelfed 服务器,以及我的 Discourse 论坛。此外,现在还有所谓的 AI(这对新手来说并没有广告宣传的那么轻松)。

我不确定在 Discourse 中是否真的可行,因为它是基于 Docker 的。但在普通的 Nginx-Varnish-WordPress 环境中,我构建了一个系统:当 Plesk 服务器检测到 5xx 错误时,会显示一个错误页面。实际上,我有三套配置:如果 Varnish 宕机,前端的 Nginx 会显示生成的快照内容;如果与 WordPress 相关的后端宕机,Varnish 会开始使用快照来提供未缓存的内容;第三种情况是,如果前端 Nginx 无响应,则显示错误页面。

Varnish 相关的配置在 Discourse 中不可行,但我看不出有什么理由不能在 Docker 环境中构建类似的“蛛网”系统,使得任何 5xx 错误都能显示一个错误页面。

不过,这可能是一个非常容易出错的系统。而且,如果有超过少数几个用户,我完全不知道会发生什么。

当然,还有一个最明显的答案:在 Discourse 之前使用 Nginx。在我转向双容器架构之前,我就是这么做的。

我终于腾出时间重新安装了 Discourse。在评估了自己目前的情况以及维护两个容器所需的精力后,我认为现阶段还是先只用一个容器。如果未来确实需要两个容器,我会重新审视这里所讨论的所有内容。除了安装插件(这似乎不像管理组件那样频繁)之外,在用户在线人数较少的时段让社区停机 20 分钟,并提前通过横幅通知大家社区将在特定日期和时间停机,目前看来是相当合理的。

让我们看看情况如何吧。

它需要的维护量和单个容器一样多 :flushed_face:

少一些心痛 :slight_smile:

你能具体说明一下那个过程是怎样的吗?

不确定你是在回复我还是在回复 @Jagster?你是什么意思?

因为在新容器启动(bootstrap)的过程中,您的网站可以保持在线,这大大减轻了压力——如果构建失败,您无需惊慌,可以花费所需的时间来修复问题,而无需让网站离线。

好的,所以你是建议两者都采用,因此才说“减少麻烦”。
那么,作为一个在这方面没有经验的人,我认为拥有 2 个容器并不意味着运行两个 Discourse 实例,对吧?

我正在阅读这两个主题:

以及

我想看看这大概需要多少工作量,以及我需要投入多少精力,以免最终搞出一个我无法管理的局面,反而让整个过程比只使用一个容器时可能出现的其他问题更麻烦。

只是想表扬一下关于双容器部署的分享。我之前用的是单容器,通常需要 3-5 分钟(在一台拥有 64GB 内存的独立服务器上)。

能否用清晰、简单的例子说明一下,在双容器安装中,什么时候应该同时更新两个容器?也就是说,哪些 Discourse 升级需要重启这两个容器,而哪些只需要重启新创建的 web_container?

首先,你需要按照非常简单的说明来启动双容器配置。之后,你通常只需要运行以下命令:

./launcher bootstrap web_only && ./launcher destroy web_only && ./launcher start web_only ) 2>&1 | tee ~/$(date +%Y-%m-%d_%H-%M-%S)-upgrade.log'

tee 部分仅用于日志记录,因为对我来说,浏览日志文件比查看我正在使用的 tmux 输出流更简单。

但基本上,这与使用 app.yml 并重新构建的效果完全相同,只是对用户的干扰要小得多。当然,还有一个数据容器,但它很少需要维护——如果你打算对容器进行更复杂的操作,你大概也清楚该如何处理以及何时处理。

如果双容器配置升级失败,你的论坛仍然会保持运行状态,而单容器配置则可能会崩溃。

因此,只有初始启动稍微复杂一些,但说明相当清晰。我会说,如果使用 Amazon SES,配置 mail-reveiver 才是更具挑战性的任务。

例如,这种评论是我不能简单忽视的,因为更新/升级似乎不再像点击按钮那么简单,而是需要更多的关注和留意。对于有经验的人来说,这可能看起来很容易、很明显,但对于没有经验的人来说,可能并非如此:

你觉得这个主题中的说明在2026年仍然准确吗?毕竟那是2015年的内容。

我不介意试一试,因为我今天刚重新安装了Discourse。如果出了什么问题,我可以直接回退到单个容器。我只是想确保在操作进行到一半时,不会做出在2026年已经不再适用的操作……

对我来说,节省的那几分钟实际上超过了 20 分钟。如果说每月升级一次的话,每月一次倒是没错,但我至少每周升级两次。而且,如果某个插件失败且必须尝试几次(毕竟我们是在生产实例上工作 :wink:),那么这么长的停机时间简直让人痛苦。

根本没有什么每次新版本发布时都要遵循的公告中的详细说明。Mcdanlj 也许需要,但他不是普通的系统管理员,他的工作层级要高得多。

我有点困惑……

你之前说:

但你在上面那条回复中又说:

这听起来好像工作量更大了?

光这一点,就让人觉得维护两个容器确实比维护一个更复杂,而不是难度相同?当然,停机时间什么的我都理解,但就容器本身的维护而言,似乎比使用单个容器进行简单升级更复杂,也更容易出错。还是说我漏掉了什么?

没错:

容器 1 = 网站 & nginx
容器 2 = 数据库和 redis

(我想我理解得没错)

容器 1 里的内容经常变动

容器 2 里的内容很少变动。

而且你可以更新容器 1 而无需更新容器 2。

更棒的是,你可以为容器 1 准备一个替代版本,然后在几秒钟内完成切换(这个准备过程被称为“引导”/“bootstrapping”)

你忽略了一点:使用单容器时,运行 ./launcher rebuild app 会同时停止 web 和 data 服务,然后对两者都进行升级。但 data 端极少需要升级,而在任务完成后,只有在没有问题的情况下,所有服务才会重新启动。

而对于双容器方案,你只需要重建 “web” 容器,不动 data 容器。如果一切顺利,它会销毁旧容器并启动新容器。如果出了问题,你旧的、可正常运行的 “web” 容器仍然在使用中。

所以,两者唯一的实际区别在于如何处理软件以及数据库的其他几项内容。

当然,单容器方案也是一种选择。但主要问题是,当创建双容器时,唯一的实质区别在于升级时使用的命令——而针对这一点,可以用 alias 来解决 :wink:

那是早期手写公告的时代,公告里会提到现在是时候更新数据库了。新的自动化网站更花哨,但不再有像以前那样由人写的备注,指出什么才是真正最重要的事情。

我想现在你得留意关于数据库即将更新的帖子吧?我似乎好几个个月都没注意到这些帖子。

不过,这种情况几年才发生一次,而且当你明确重建数据库时它会重新构建,CDCK 似乎也在一段时间内保留了对旧版本 pgsql 的兼容性。所以它实际上从来没有真正困扰过我。至少到目前为止是这样。

我个人真的很喜欢双容器(或更多!)的配置用于我自己,但我还是会加上限定条件,因为这对每个人来说并不是最容易的。我很难判断对于谁来说,双容器部署会感觉“当然,这很简单”,而对于谁来说会是“唉,我只想点一下按钮”。