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

我的更新过程中出现了一个错误

api_key = "a quick brown fox"
fetch("https://api.example.com/data", headers: { 'Authorization' => api_key })

请帮我修复它。

嘿!

我不是在回答你的问题,只是出于好奇。你为什么觉得需要维护页面?设置起来似乎挺麻烦,而且收益甚微。

我的实例每个月停机更新大概5分钟,基本上就这样了。

每当我进行重大更改,例如安装插件时,有时需要花费20分钟。

考虑到这些操作并非每周甚至每月都要进行,这倒不是什么大问题。但对于新访客来说,看到那个显示“某些功能无法正常工作”的丑陋页面,并不会留下良好的第一印象。即使是那些不知道网站会停机的老访客,也可能因此陷入“恐慌模式”,以为整个社区被关闭了或发生了其他严重事故,其中一些人甚至会立刻发邮件问我到底发生了什么。

我认为,无论是新访客还是老访客,告知他们当前正在发生的事情,都是一个贴心的细节。

如果Claude提出的这种方案只需花费几分钟,且之后无需再频繁调整,我相信这绝对是一笔值得投入的时间。

如果你迁移到双容器安装,只需几秒钟。

如果你真的愿意,甚至可以在夜间安排切换,趁你和/或你的主要用户群睡觉时进行。

你不需要维护页面。

我使用 dual container build 并置于 Cloudflare CDN 之后。双容器模式将停机时间降至最低,我的两个主要生产论坛在重建期间最多只有 30 秒的离线时间。我喜欢使用维护页面,因为默认的网络服务器宕机页面既难看,又无法提示用户离线时间有多长。

例如,对于 your-domain.com 这个站点,我只需设置一个 Cloudflare Workers 路由,指向 *yourdomain.com/*(包含星号)。

步骤 1:创建 Worker 页面

你可以在 Cloudflare 的 workers & pages 设置页面中设置维护页面——点击 create application 按钮:

然后使用 hello world 模板:

然后给它起个名字并点击 deploy

然后进入该维护页面的概览页面,点击 edit code

并将以下代码粘贴到 worker.js 代码窗口中(替换你的域名以及你想要的消息,编辑文本、文字颜色、背景等):

export default {
  async fetch(request, env, ctx) {
    try {
      // Fetch the original request from your server
      const response = await fetch(request);

      // If YOUR SITE is swapping containers, it throws a 502, 521, or 530
      if (response.status === 502 || response.status === 521 || response.status === 530) {
        return returnCustomErrorPage();
      }

      // If everything is fine, return the normal forum traffic
      return response;
    } catch (e) {
      // If the server is completely unreachable
      return returnCustomErrorPage();
    }
  }
};

function returnCustomErrorPage() {
  const html = `
    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>System Refresh - YOUR-SITE.com</title>
      <style>
        body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; text-align: center; padding: 50px; color: #333; background-color: #f9f9f9; }
        h1 { font-size: 2.5em; margin-bottom: 0.5em; color: #9400D3; }
        p { font-size: 1.2em; line-height: 1.5; }
        .container { max-width: 600px; margin: 0 auto; background: white; padding: 40px; border-radius: 8px; box-shadow: 0 4px 6px rgba(0,0,0,0.1); }
      </style>
    </head>
    <body>
      <div class="container">
        <h1>Just a quick update window</h1>
        <p><strong>YOUR-SITE</strong> is undergoing a brief 30-second system refresh.</p>
        <p>Grab a quick sip of your drink—this page will automatically refresh as soon as we are back online.</p>
      </div>
      <script>
        // Automatically check if the site is back up every 10 seconds
        setInterval(function() {
          window.location.reload();
        }, 10000);
      </script>
    </body>
    </html>
  `;

  return new Response(html, {
    status: 503, // 503 is best for SEO so Google doesn't penalize you for downtime
    headers: {
      "Content-Type": "text/html;charset=UTF-8",
      "Retry-After": "30"
    }
  });
}

它看起来应该像这样。点击 deploy 以保存:

步骤 2:添加路由

现在进入 Cloudflare worker route 页面,点击 add route 按钮以调出新的路由模态框,填入域名路由并选择你刚刚创建的 worker 页面,然后点击保存:

步骤 3:运行更新或重建

现在,当你通过 ssh 进入服务器并运行系统更新或进行重建时,在真正发生停机时显示的将不再是网站宕机或错误页面,而是这个页面(我的设置是 30 秒,因为这是我的站点的最大停机时间)

我倾向于在维护时添加和删除我的 workers 路由页面,但有些人喜欢一直保留它(我保留页面的实际代码,只是添加和删除路由)。

我想这就完了。

可选:使用脚本运行更新并设置计划

我还使用服务器上的 unix shell 脚本来运行双容器特定的更新,我是这样创建的:

cat << 'EOF' > /root/update-web.sh
#!/bin/bash
cd /var/discourse
echo "➡️ Pulling latest Discourse docker scripts..."
git pull

echo "➡️ Bootstrapping new web container in the background (takes ~8 mins)..."
./launcher bootstrap web_only

if [ $? -eq 0 ]; then
    echo "✅ Bootstrap successful! Swapping containers..."
    ./launcher destroy web_only && ./launcher start web_only
    echo "🚀 Done! Site updated with almost zero downtime."
else
    echo "❌ Bootstrap failed! Aborting swap to keep current site online."
fi
EOF

chmod +x /root/update-web.sh

然后在服务器的 root 提示符下使用命令 ./update-web.sh 运行它。


:warning: 编辑:除非你有付费的 cloudflare 账户,否则不要执行以下步骤。

你可以将其自动化到特定时间,例如你本地时间的周日凌晨 1 点。对我来说,1:00am local8:00 AM UTC,(你可以通过在 ssh 登录时输入 date 来查看服务器的 UTC 日期)。

所以:

运行此命令以打开服务器的任务调度器:

crontab -e

(如果它要求你选择编辑器,请选择你喜欢的编辑器,选择 1 即 nano 可能最容易)

我滚动到注释的底部并粘贴以下内容:

0 8 * * 0 /root/update-web.sh >> /var/log/discourse-update.log 2>&1

(这意味着在分钟 0、小时 8(UTC)、每个周日早上运行 /root/update-web.sh 文件)

然后保存并退出(如果你使用的是 nano):

  1. Ctrl + O 保存。
  2. Enter 确认。
  3. Ctrl + X 退出。

然后我可以在周日早上醒来时运行 cat /var/log/discourse-update.log 来检查它是否正常运行。如果你确实使用 cron 任务调度器,那么你将需要保留 workers 页面路由。

我想这就是全部了。 如果你有问题请告诉我 lol。 这比我看起来要简单得多 lol。 :grin:

哇!我非常感谢你提供的详细步骤!:raising_hands:

我已经把你的回复保存到我的笔记里了,这样当我不久后再次安装 Discourse 时,就可以回来参考。我一定会告诉你进展如何,即使安装过程需要花一些时间。目前我正在完成一些编码工作,之后才会重新专注于 Discourse。

我也同意“web serve is down”页面很难看,而且对于没有经验的用户来说,这条信息意义不大。拥有一个带有自定义消息的简单维护页面总是更好的选择,即使这需要一些设置工作。

再次非常感谢你抽出时间分享这些。希望其他人也能从中受益 :slight_smile:

问题就在这里。

这并非一个简单的改动,还涉及需要担忧和维护的额外基础设施,恕我直言,为了几秒钟的停机时间,这完全 值得。

我明白你的意思,但那只是其中一种情况。如果真的出现严重故障,我需要花更多时间(不止几秒钟)来修复怎么办?

另外,你是怎么做到只有几秒钟的停机时间的?我安装插件后,看到的停机时间大约是20分钟。

因为在双容器设置(我们在帖子中都链接了,且是不可或缺的依赖项)中,你使用 ./launcher bootstrap web_only 引导新构建(在此期间你的网站仍保持 100% 正常运行),然后你只需销毁并立即启动刚刚构建好的新容器(这只需几秒钟)。

哦,好的,那还是针对双容器部署方案的。我原以为你是在说完全搭建双容器部署方案不值得费这个劲。你的意思是,不值得做的只是那个维护页面所增加的额外工作,对吧?

个人而言,是的。

如果你希望为在30到60秒内通过全新导航出现的网页访问者提供双重保障,那么使用维护页面是合理的。

你需要权衡这样做的好处与维护相关基础设施所需的时间。

现在我明白了。谢谢。

那么我现在想问:使用 2 个容器时,那大约 20 分钟的时间依然存在,唯一的区别是我可以在非实时运行的那个容器上执行操作,等准备就绪后再进行切换。是这样吗?

是的,构建容器仍然需要一些时间。顺便提一下,你需要确保你的服务器配置足够强大,以便在正常为社区提供服务的同时,能够并行进行该构建过程(最关键的是确保有足够的内存——因此务必确保你有足够的交换空间)。构建过程还会占用至少一个 CPU 核心,因此建议你的服务器拥有多 1 或 2 个核心。

现在一切都讲得通了。谢谢。

我最初使用的是这个,但似乎已经不再可用了:

所以我现在需要改用这个:

价格跳涨有点多……:/ 而且看起来服务器性能似乎更差……?

对于这种配置,我建议至少使用 4GB 内存和 3 个核心(“vcpu”)……

作为参考,因为有人在另一个话题中问过,(编辑:错误)答案是:Any cheaper alternatives to Hetzner? - #2 by Canapin

这是唯一符合要求的……价格差异真大……

image

我想我现在得先用单个容器搭建,等时机成熟(:money_bag:)再升级。

谢谢你的信息,Robert!

我持不同意见,我认为设置维护页面是值得的。根据我的经验,当用户看到 Discourse 错误页面时,他们做的第一件事通常是刷新页面,随后会看到简短的维护页面,并在容器切换完成后自动重新加载网站。设置起来并不复杂,而且只需配置一次。在采用双容器配置进行重建时,引导阶段会在后台进行,用户仍可使用网站;导致短暂停机的是容器切换过程(这与标准的单容器配置不同)。

服务器成本和选择是完全不同的问题,应该放在另一个独立的话题中讨论。

我想我现在处于中间立场。我理解你的意思,也理解 @merefield 的观点。拥有这个功能确实是个不错的点缀,而且如果只需设置一次,我想也不算什么大碍吧?

同时,如果最坏情况下确实需要长达 60 秒,并非每个人都会在 0 秒整访问网站并被迫等待 60 秒。有些人可能会看到丑陋的页面 5 秒,有些 20 秒,有些 60 秒。甚至有些人根本不会看到它(我想是这样?),例如,如果他们只是在阅读回复或撰写回复,这个切换可能在他们点击“发送”之前,或者在他们停止阅读主题并点击“回复”(或访问其他页面)之前就已经完成了。

我对 nginx 路由方案的顾虑,更多是与单容器设置中 20 分钟的问题有关。既然可以选择使用 2 个容器,并将时间从 20 分钟缩短到最多 60 秒,我在想这是否真的还重要?尤其是,如果我能够在顶部添加一个公告,说明服务将在低流量时段短暂中断几秒钟,这应该就不会成为大问题了吧?

我得坐下来好好想想。不过,如果我能找到划算的服务器优惠,双容器设置肯定是我打算实施的方案。

你能否用我能理解的简单方式解释一下?我对 Workers 还不太熟悉……

如果一直保留没有问题,为什么还要添加和删除 Workers 路由页面呢?所以,如果我添加了维护页面,我是否真的只需设置一次,之后就可以一直通过终端 SSH 连接到服务器,像操作单个容器那样在那里完成所有操作,而无需再访问 Cloudflare?

@merefield 提到维护页面、Workers 等也需要维护,所以我想知道这真的是“设置后就不用管了”的东西,还是说偶尔需要做一些操作?