我运行了一个 Discourse 论坛,里面包含了大量的内容和图片,已经好几年了。Maker Forums 拥有超过 100GB 的图片以及超过 400,000 个帖子,其中相当一部分是从 Google+ 导入的,其余的则是在网站上创建的。这篇文章描述了我最终配置 Maker Forums 以及后来其他几个 Discourse 实例时所涉及的一些要素。这是我当初起步时希望知道的事情,我也用这些经验帮助其他人避免在自己部署 Discourse 实例时犯同样的错误。
面向更广泛的受众。
警告: 如果你不熟悉 Linux 系统管理员的工作,这份指南可能不适合你。我甚至可能没有意识到这份指南中预设了多少关于 Linux 的知识。如果读起来让你豁然开朗,那你可能就是目标受众。如果读起来让你感到困惑,那你可能不是目标受众。如果这看起来像是一项繁重的工作,请考虑付费请 CDCK 或 @pfaffman 为你运行 Discourse;他们非常专业。或者先从 免费的 discourse.group 站点 开始,然后随着规模增长再付费升级。
这还不够:我的 Linux 专业知识比 Discourse 专业知识更丰富。我的观点不承担任何保证责任。如果尝试遵循我的建议导致你的任何东西损坏(你的 Discourse 论坛、你的主机系统,或者你的心),损坏的碎片归你所有,而且全是锋利的边缘。我没有任何计划为本文中的内容提供任何形式的支持。
我计划(但不承诺)根据我参与维护的 Discourse 实例的实践情况,随时更新这份文档。这份文档以建议的形式撰写,但主要旨在作为对我自己以及任何继承了我负责的 Discourse 部署的管理员的建议。除此之外,你应该将其视为你自行研究的一个起点,以确定你想要如何部署 Discourse。
系统设置
使用基于 CentOS 或 Ubuntu LTS 的操作系统。任何支持 Docker 的系统可能都能工作,但我使用的是这两个。
Docker
我是 Fedora 用户。我曾担任 Red Hat 的首位 Fedora 项目主管,我更倾向于在 Podman 上运行 Discourse,因为我认为其安全模型优于 Docker。然而,Discourse 部署仅支持 Docker,如果你尝试在其他平台上运行,你将是一位相当先锋的探索者。(也许将来,如果 docker-compose 得到支持,可以通过 podman-compose 在 Podman 上运行。)
现在 Docker 支持 cgroups v2,你可以在基于 CentOS 的系统上安装官方 Docker 构建版:
dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
dnf install --allowerasing docker-ce docker-ce-cli
(包含 --allowerasing 是因为可能与已安装的 podman、runc 和 buildah 存在冲突;需要删除它们才能安装 docker。)
systemctl enable --now docker
我已在 AlmaLinux 9 上测试过此操作。
安全
这一部分与 Discourse 本身没有直接关系,但这是我常规安全实践的一部分。不要允许仅凭密码通过 shell 访问网络上的任何系统,包括运行 Discourse 的虚拟机。 设置基于 SSH 密钥(使用密码短语加密)的访问,并配置虚拟机上的 ssh 服务器,禁止密码访问。
laptop$ ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/.../.ssh/id_rsa):
Enter passphrase (empty for no passphrase): SOME LONG PHRASE
Enter same passphrase again: SOME LONG PHRASE
Your identification has been saved in .ssh/id_rsa
Your public key has been saved in .ssh/id_rsa.pub
Linux 发行版通常设置为在内存中记住密码短语,因此每次启动只需输入一次。Windows 没有这么方便;你可以考虑使用 Pageant 配合 PuTTY 来实现同样的功能。
首先,验证无需密码的传入 SSH 连接是否正常工作。只有在完成此操作后,在服务器上修改 /etc/ssh/sshd_config 文件,找到 PasswordAuthentication 行。将其设置为 no 以禁用传入的密码访问。
PasswordAuthentication no
防火墙
你需要保持 80 和 443 端口通常开放,以便 letsencrypt 生成和更新你的 SSL 证书,即使你的 Discourse 尚未对公众开放。
如果你使用 firewalld,以下命令可以实现此目的:
firewall-cmd --add-service http --add-service https --zone public
firewall-cmd --runtime-to-permanent
独立的设备和文件系统
将 /var/discourse/shared 设置为一个独立的设备,拥有自己的文件系统,空间为 20GB 加上至少两倍于你所需图片存储的空间;如果你将使用 prometheus,请增加更多空间。如果该设备以后易于扩展(例如 LVM 或任何云块存储,如 AWS 弹性块存储),你可以监控并根据需要增长它;否则,请在开始时预留充足的空间。如果你使用的是网络存储块设备,不要在其上创建分区表。不使用分区表将使扩展更容易;你无需修改分区表。在许多情况下,你可以在没有任何系统停机时间的情况下进行扩展。
在 Maker Forums 上,这是一个连接到运行 Maker Forums 的虚拟机的网络存储块设备。在另一个 Discourse 论坛上,它是 Digital Ocean 块存储卷。在 Amazon 上,这将是 AWS 弹性块存储。在我运行于 Fedora 上 libvirt 下的 KVM 虚拟机的测试系统上,它是 Fedora 主机上的 LVM 卷,作为虚拟磁盘导出给 AlmaLinux 虚拟机。在每种情况下,我都可以创建一个新的虚拟机,将关键文件复制过去,停止旧虚拟机,将 /var/discourse/shared 卷附加到新虚拟机,并在几分钟内恢复运行。这使得虚拟机上的操作系统升级风险相对较低。
确保你的虚拟机根文件系统至少有 25GB 空间,不包括 /var/discourse/shared 的任何空间。这将用于所有 docker 容器,如果任何时候可用空间少于 5GB,discourse launcher 将会失败。你还需要为系统更新预留充足的空间。如果磁盘空间不足,很难恢复。
在站点配置中,请设置 force_https,但注意警告。在将 Discourse 站点公开之前,先在测试环境中设置它。请注意,即使使用 force_https,你也需要开放 80 端口,以便重定向到 443 端口的 SSL 并更新你的 letsencrypt SSL 证书。(但是,如果你使用 cloudflare,请使用其功能;据报道它与 Discourse 中的 force_https 不兼容。)
内核配置
Redis(Discourse 构建的关键组件之一)强烈建议在使用基于磁盘的持久化时禁用透明大页面(Discourse 正是这样做的),我也允许内存超额分配。
echo 'sys.kernel.mm.transparent_hugepage.enabled=never' > /etc/sysctl.d/10-huge-pages.conf
echo 'vm.overcommit_memory=1' > /etc/sysctl.d/90-vm_overcommit_memory.conf
sysctl --system
Discourse 安装
虽然默认安装是单个容器,但这使得每次升级(建议每月进行)如果从命令行执行,通常需要 10-15 分钟的停机时间,这对于某些更新(包括更新 Discourse 构建基础工具的更新、安全或新功能更新,或者当 UI 实时更新因任何原因失败时)是必要的。你可以通过双容器安装在实际操作中减少停机时间。
双容器安装
从两个容器开始配置。
./discourse-setup --two-container --skip-rebuild
${EDITOR:-nano} containers/data.yml
./launcher rebuild data
# 我倾向于使用 app.yml,但你也可以坚持使用 web_only.yml,阅读相关文本
mv containers/web_only.yml containers/app.yml
${EDITOR:-nano} containers/app.yml
./launcher rebuild app
这使得每几个月必要的系统停机时间非常短,几乎察觉不到;如果用户在停机期间不点击或滚动浏览内容,许多用户根本不会注意到。这使得应用大多数安全更新变得更加容易;这只是一个短暂的停顿,而不是大约 15 分钟的重建所有东西。以下过程适用于大多数更新,通常会产生大约 30-90 秒的停机时间,主要取决于主机系统的性能和安装的插件集。
cd /var/discourse
git pull
./launcher bootstrap app
./launcher destroy app && ./launcher start app
./launcher cleanup
不要在 bootstrap 和 destroy/start 调用之间延迟。不经常(在实践中可能一年一两次),在 bootstrap 阶段末尾执行的数据库迁移会导致应用程序用户出现或多或少严重的错误,这是由于旧代码访问了更新的数据库。
这确实意味着当你更新 Discourse 时,你还必须检查是否也需要更新数据容器,但这很少需要(通常预期每年一两次)。根据你的数据容器和应用程序容器的内容以及系统速度,这通常会导致 5 到 20 分钟的停机时间。
cd /var/discourse
git pull
./launcher stop app
./launcher rebuild data
./launcher rebuild app
关于何时更新数据容器的更多信息,请参阅:
(在我自己的部署中,我个人选择将 web_only 容器称为 app,既因为它更容易输入,也因为这使得大多数说明更容易遵循。这是非标准的,但我一直欣赏其易用性。然而,这是额外的工作,它对我有效是因为我知道发生了什么。如果这听起来不好,请在多容器部署中坚持使用默认的 web_only。)
请注意,在未来的某个时候,Docker 可能会强制你迁移到新的配置以连接你的容器:
如果你有 4GB 或更多内存,或多个 CPU,请阅读以下建议:
更新计划
关注 release-notes 标签(点击 release-notes 并点击右上角的铃铛;我使用“关注首帖”)和/或将 https://meta.discourse.org/tag/release-notes.rss 添加到你的 RSS 源,以了解何时发布新版本。在更新之前阅读发布说明。如果有数据库更改,发布说明会提及。它们还会指出包含安全更新的版本。即使你跳过实际更新到某些版本,也要阅读所有发布说明;如果你不阅读更新数据库的版本的发布说明,你可能会错过未阅读的发布说明中的数据库更新说明。
邮件
邮件仍然是保持人们联系的关键方式之一。设置传出和传入邮件,让邮件为你工作。如果有问题,请参阅:
保持联系
Maker Forums 曾见过一些长期离开后返回的偶尔访客。默认情况下,Discourse 在一年后停止发送摘要电子邮件。如果你想鼓励偶尔访客在看到新有趣内容时回来,请考虑将 suppress_digest_email_after_days 设置为比默认 365 天更长的时间。我为 Maker Forums 将其设置得长得多,以支持偶尔访客保持最新。阅读摘要电子邮件是“潜水”浏览论坛的有效方式,你永远不知道什么时候有什么东西会激发某人参与贡献的兴趣。
类似地,默认情况下,不活跃的特权用户(信任级别 0 且无帖子)在 730 天未登录后最终会被删除。将“清理不活跃用户天数”设置为 0 以禁用删除用户,如果你希望他们能够无限期地潜水阅读摘要电子邮件。
考虑添加 yearly review 插件,它每年会生成一个帖子,如 2020: The Year in Review 并最终将其电子邮件发送给你的不活跃用户,这可能会鼓励他们重新参与。
邮件接收容器
设置第三个容器作为邮件接收器。它确保处理退信,使你的退信处理独立于传出邮件提供商,并为你提供通过电子邮件回复的选项。
确保你设置了 SPF 以信任你的电子邮件发件人;至少,如果你通过同一个 MX 发送和接收,策略如 v=spf1 +mx -all,但更具体的可能作为垃圾邮件保护更受信任。也考虑 DKIM。
如果你使用相同的主机名接收电子邮件,你真的应该在容器外部终止 SSL,就像“离线页面”一样(见下文),并且需要将你的 certbot 证书映射到容器中,并在运行 certbot 后重启容器。
在容器外部终止用户 SSL 连接
有两种选择在容器外部终止 SSL,任何一种都比在容器内部终止带来显著优势。在成功完成 discourse-setup 并引导你的论坛后,设置其中一种。
外部 nginx
在主机系统上运行 nginx,而不仅仅是在容器中,既用于托管维护页面,也用于支持 IPv6 地址日志记录(如果主机支持 IPv6)。(否则,所有 IPv6 连接都将记录为来自与你的本地 docker 虚拟网络接口相关的内部 RFC1918 地址。)此配置将在大多数维护操作期间显示临时维护页面,最终将重定向回用户查看的页面。
请注意,该页面上的说明(目前)建议安装名为 letsencrypt 的包,但现在通常称为 certbot。如果你按照该页面上的说明使用 --certonly,你将不需要 certbot 的 nginx 插件,但安装 nginx 插件是另一种机制。在 CentOS 衍生版上:
dnf config-manager --set-enabled crb
dnf install epel-release
dnf install certbot python3-certbot-nginx
systemctl enable --now certbot-renew.timer
确保 certbot 重启 nginx 和邮件接收容器,以免浏览器或电子邮件因继续使用旧的、过期的证书而阻止与你的站点的流量。
# systemctl edit certbot-renew
对于没有邮件接收器的系统,我添加了两行:
[Service]
ExecStartPost=/bin/systemctl reload nginx
在我使用单独邮件接收容器且共享系统证书的系统上:
[Service]
ExecStartPost=/bin/systemctl reload nginx
ExecStartPost=/bin/sh -c 'cd /var/discourse && ./launcher restart mail-receiver'
如果你使用 SELinux,Ubuntu 容器未设置为将 nginx.http.sock 文件标记为 httpd_sys_content_t 以便外部 nginx 能够访问它。你有两个选择。
第一种是以宽容模式运行 nginx,移除其 SELinux 保护:semanage permissive -a httpd_t
然而,这移除了可能最相关服务的 SELinux 保护!为了保持 SELinux 启用,你需要允许 nginx 访问错误页面,并从通过 unix 域套接字代理切换到端口(这慢几微秒,但你的用户应该察觉不到)。
首先,运行这些命令以允许 nginx 访问错误页面:
semanage fcontext -a -t httpd_sys_content_t /var/www
restorecon -R -v /var/www
然后在你的 app.yaml 中,注释掉或删除 - "templates/web.socketed.template.yml",将端口 80 暴露为本地机器上的不同端口,并重建容器。
expose:
- "8008:80" # http
不要在这里使用 https —— 你已经在外部 nginx 中终止了 SSL,X-Forwarded-Proto 头告诉 Discourse 请求是通过 https 进来的。确保端口 8008(或你选择的任何其他端口)没有通过防火墙设置公开暴露。
然后运行此命令以允许 nginx 通过网络连接到容器:
setsebool -P httpd_can_network_connect 1
然后修改你的外部 nginx 配置,从通过 nginx.http.sock 代理切换到 http://127.0.0.1:8008(或你选择的端口),并清除默认的 Connection: close 头,这样外部 nginx 就不必为每个请求建立新的 IP 连接。
...
location / {
proxy_pass http://127.0.0.1:8008;
proxy_set_header Host $http_host;
proxy_http_version 1.1;
# Disable default "Connection: close"
proxy_set_header "Connection" "";
...
删除 web.socketed.template.yml 也删除了 real_ip 调用,所以把它加回来。确保你使用的 IP 地址范围有意义;Docker 的默认是使用 172.16* RFC1918 地址空间,这些地址在公共互联网上策略上不路由。在你的 app.yml 文件中添加类似以下内容,在 run 部分中,选择一个或多个 RFC1918 地址空间或适合你部署的其他内容:
run:
- file:
path: /etc/nginx/conf.d/outlets/server/real-ip-recursive.conf
chmod: 644
contents: |
real_ip_recursive on;
- file:
path: /etc/nginx/conf.d/outlets/server/real-ip-header.conf
chmod: 644
contents: |
real_ip_header X-Forwarded-For;
- file:
path: /etc/nginx/conf.d/outlets/server/set-real-ip-from.conf
chmod: 644
contents: |
set_real_ip_from 192.168.0.0/16;
set_real_ip_from 172.16.0.0/12;
set_real_ip_from 10.0.0.0/8;
这对于速率限制正常工作以及归因用户的注册和最后使用 IP 地址是必需的。
更多信息:
外部服务
我还没有在 Discourse 前面配置 Fastly 或 Cloudflare,但其他人已经配置了,与在主机上运行的外部 nginx 不同,它们允许你在主机系统完全关闭时(例如在主机上进行系统更新时重启)提供维护页面。如果这对你有价值,以下是操作方法:
不要急于使用 S3 上传
在启用 enable_s3_uploads 或在设置后迁移到它之前,非常确定你总是想使用 S3(或等效服务)上传图片。请注意,使用 S3 (s3_endpoint) 及其关联的 CDN (s3_cdn_url) 用于图片也会导致通过该 CDN 提供 javascript。从 S3 迁移回本地存储不受支持,目前也没有具体的实施计划。这是一扇“单向门”,甚至无法通过完整备份和恢复来撤销。如果你确实使用 S3 或类似服务,不要使用 Digital Ocean Spaces 代替 S3。meta 上有参考指出它不可靠。
我早期将我的站点迁移到通过 Digital Ocean Spaces 及其关联的 CDN 提供图片,我不得不编写数百行自定义代码以迁移回本地存储,在此过程中对我的 Discourse 实例造成了轻微损坏,因为“单向门”未被充分理解。
更多信息:
你不需要启用 S3 上传来为 Discourse 使用 CDN。考虑在管理自己图片的 Discourse 前面使用独立的 CDN(例如 Cloudflare、CloudFront、Fastly、GCS CDN)。据我二手了解,关于不建议使用 Cloudflare 的警告是由于“Rocket Loader”修改 JavaScript;并且目前,只要你不使用“Rocket Loader”,它就能正常工作。
Discourse 设置以进行 moderation
在任何 moderation 活跃的站点上,强烈考虑 enable_whispers 配置,它允许 moderation 员和管理员在行内讨论主题。此外,类别 moderation 员在最近的 Discourse 版本中被赋予了更多能力。如果你有不同主题的专家拥有自己的类别,或者你有功能上独立的类别(例如用于支持),值得了解 enable_category_group_moderation。
地理位置在尝试确定账户是否合法时可能很有帮助。
Discourse Templates 功能对 moderation 员真的很有帮助。它让你协作处理常见回复。我们在 Maker Forums 有几十个。它比它取代的先前“Canned Responses”插件拥有更多功能。
User Notes 功能将帮助 moderation 员共享关于用户的笔记。你可以将这些用于:
- “留意这个用户,他们可能是恶意的,因为……”
- “虽然这种行为看起来可疑,但我已通过……验证这是一个合法用户。”
- “我已经在这个用户那里进行对话以解决疑虑,其他 moderation 员不需要凑热闹。”
信息可访问性
Discourse Solved 插件不仅标记已解决的问题,以便站点访问者更容易识别,而且我理解它可能还会优先处理 google 搜索结果。
公共信息比私人信息更容易访问。在 Maker Forums 上,我们的 FAQ 强烈 discourage 个人消息,并提醒每个人个人消息并非真正私密。但是,默认情况下,用户可能会看到消息:
你已回复 user 3 次,你知道你可以发送个人消息给他们吗?
如果你真的想鼓励用户去个人消息,我建议你转到 Admin → Customize → Text 并更改 get_a_room 模板以修复逗号拼接。
如果像 Maker Forums 一样,你想保持对话公开以惠及所有人,Admin → Settings → Other → get_a_room_threshold 可以设置得更高,比如 1000000。
类似地,如果你有一个提供支持的论坛,max_replies_in_first_day 默认值 10 可能会在用户用完回复预算时,将寻求帮助的对话中的新用户推入个人消息。考虑增加此设置以避免将对话推入个人消息。
连接用户,建立社区
一些插件可以帮助用户相互连接。
如果你的论坛没有太多同时在线用户,考虑使用 Who’s Online 插件,让人们更有连接感。你可能想限制显示给登录用户,可能仅限于至少达到信任级别 1 的用户。你可以通过将 whose_online_minimum_display 设置得很高并将 whos_online_hide_below_minimum_display 设置为 true,仅用它来为头像添加存在标识 (whos_online_avatar_indicator)。这对于支持论坛以支持和鼓励快速问答并帮助用户解决问题可能很有用。
然而,存在感是一把双刃剑。如果用户在线时间与大多数论坛用户不同,他们可能会感到孤独,或者论坛对他们来说可能像“鬼城”。
如果你有很多国家的用户,并希望他们有关于彼此更可能可用的提示,考虑使用 National Flags 插件,并鼓励用户在他们的个人资料中设置国旗。
翻译是一个棘手的问题。当人们不说同一种语言时,帮助沟通会很方便,但目前(截至本文撰写时)没有提供免费服务层级的翻译服务。如果你选择付费翻译服务,你可以使用 Discourse Translator 插件启用翻译。
备份
对于系统文件,考虑至少备份:
/var/discourse/containers(用于 discourse 配置详情)/var/www(用于错误页面)/etc/ssl(用于 letsencrypt 配置,以避免在恢复备份时引导 certbot;否则你必须在引导时注释掉 nginx 配置中的 SSL 部分;这仅在你保持备份近期时有效,因为证书有效期短)/etc/systemd/system/backup-uploads.service(用于将图片备份到 S3)/usr/local/bin/mc(minio-client 作为图片备份工具,如果你选择使用)/root/.mc(minio-client 图片备份配置)/root/.ssh(传入 SSH 会话身份验证)
其中一些文件你可以通过将它们检入 Git 并推送到异地来备份。如果你检入 Git 的文件包含秘密(如数据库密码),绝对不要将它们推送到公共存储库。或者,你可以脚本化将它们复制出系统并检入到你控制的监督系统上的 Git。脚本化足够频繁以保持 /etc/ssl 的备份新鲜。
目标是在灾难情况下拥有备份,并在出错时拥有更改记录。
对于大多数这些文件,更好的替代方案是将规范副本保存在其他地方,并使用 Ansible 等工具维护系统上的配置,这使得备份后更新同样容易。但如果你要这样做,你可能不需要我告诉你就明白了!
Discourse 配置以进行备份
-
使用
include_thumbnails_in_backups备份缩略图。没有缩略图的恢复需要很长时间来重新生成它们。如果你的站点没有太多图形,缩略图占用的空间可以忽略不计。如果你的站点图形丰富,重新生成缩略图可能需要几天。在重新生成缩略图时,电子邮件通知将被禁用。无论如何,从备份中省略缩略图没有意义。 -
如果你有很多图片,不要在备份中包含图片。这将使备份变得缓慢且笨重。单独备份它们。如果你在数据库备份后备份图片,你的备份将保持一致。
-
安排以某种方式将备份发送到异地。
此页面显示如何设置数据库备份到 S3 或类似 S3 的服务:
使用 restic 备份
配置 discourse 备份到文件系统,然后使用 restic 从文件系统备份到远程备份目标。这是一个示例配方。
# dnf install restic
# mkdir /var/restic
# mkdir /opt/backup
# cd /opt/backup
# cat > backup <<EOF
#!/usr/bin/bash
set -e
. /opt/backup/backup-config
restic --cache-dir=/var/restic \
backup \
/etc \
/root \
/var/discourse \
/opt/backup \
--exclude /var/discourse/shared/data/postgres_data
restic --cache-dir=/var/restic forget \
--prune --keep-hourly 24 --keep-daily 7 --keep-monthly 3
EOF
# chmod +x backup
这些细节会根据 restic 目标的不同而有所差异。并非所有目标都使用 AWS 环境变量,因此请阅读 restic 文档。
# cat > backup-config <<EOF
### 这些细节取决于你配置的 restic 目标,因此请修改它们
export AWS_ACCESS_KEY_ID=yours-here
export AWS_SECRET_ACCESS_KEY=same
export RESTIC_PASSWORD_FILE=/root/restic-password
export RESTIC_REPOSITORY=see-the-restic-documentation
EOF
# {$EDITOR:-nano} /root/restic-password
你需要保存一份 /root/restic-password 中内容的副本,否则你将无法读取备份!请使用你的密码保险箱。
最后,创建一些服务,初始化 restic 存储库,并设置计时器以启动备份。
# cat > /etc/systemd/system/backup.service <<EOF
[Unit]
Description=Back up to remote target
Wants=network-online.target
After=network-online.target
[Service]
Type=oneshot
StandardOutput=file:/var/log/backup.out
StandardError=file:/var/log/backup.err
WorkingDirectory=/var/discourse
ExecStart=/opt/backup/backup
[Install]
WantedBy=multi-user.target
EOF
# cat > /etc/systemd/system/backup.timer <<EOF
[Unit]
Description=Regular system backups
[Timer]
Persistent=true
OnCalendar=00/4:30:00
Unit=backup.service
[Install]
WantedBy=timers.target
EOF
# systemctl daemon-reload
# . /opt/backup/backup-config
# restic init
# /opt/backup/backup
# systemctl enable backup.timer
完成此过程后,你应该能够看到已创建初始备份。
# restic snapshots
我成功地使用这种方式制作的 restic 备份,通过 restic restore 命令将 Discourse 服务器从一个系统迁移到另一个系统。
流式 minio 图像备份
作为 Restic 的替代方案,虽然数据库备份可以存储到 S3,但没有独立于从 S3 提供图像的 S3 图像备份。另一种方法是使用 minio-client 将图像复制到任何类似 S3 的存储。这可以是许多类似 S3 的目标,包括 S3 和 minio,但 不包括 DigitalOcean Spaces,因为它构建在 Ceph 文件系统之上,而 Ceph 文件系统以与 S3 不同的方式实现 ListObjectsV2 API。
在 S3 中,创建一个阻止公共访问的存储桶(权限 → 阻止公共访问 是在 AWS 中正确设置的最简单方法)。
以某种方式安装 minio-client (mc)。这是一种方法。
curl https://dl.min.io/client/mc/release/linux-amd64/mc > /usr/local/bin/mc && chmod +x /usr/local/bin/mc
使用类似以下的命令配置名为 backup 的别名来设置 minio-client:
# mc alias set backup https://s3.amazonaws.com ACCESSKEY SECRETKEY --api S3v4
# mc mirror /var/discourse/shared/standalone/uploads backup/UPLOADS-BACKUP-BUCKET
然后创建服务 /etc/systemd/system/backup-uploads.service 如下
[Unit]
Description=Neartime remote backup sync of discourse uploads
After=network.target
StartLimitIntervalSec=0
[Service]
Type=simple
Restart=always
RestartSec=600
User=root
ExecStart=/usr/local/bin/mc mirror --overwrite -a --watch /var/discourse/shared/app/uploads backup/UPLOADS-BACKUP-BUCKET
[Install]
WantedBy=multi-user.target
注意,这里的 UPLOADS-BACKUP-BUCKET 应该是一个与配置 discourse 上传数据库备份的 s3_backup_bucket 不同的存储桶。另外,请注意,如果你使用标准的多容器部署,路径将是 /var/discourse/shared/web_only/uploads。
# systemctl enable backup-uploads
# systemctl start backup-uploads
# journalctl -fu backup-uploads
上传测试图像,并确保你看到成功备份原始和优化图像的行。在 journalctl 中按 Control-C 将退出跟随模式。
恢复
截至本文撰写时,我从未需要测试此计划。此摘要可能会遗漏某些内容。
- 通常恢复所有备份文件
- 启动 nginx(现在将显示你的维护页面)
- 使用 /var/discourse/containers 中恢复的文件进行正常的 Discourse 部署
- 如果你没有从备份中恢复,请在 /usr/local/bin/mc 中安装 minio-client
- 如果你没有备份
/root/mc,设置备份别名# mc alias set backup https://s3.amazonaws.com ACCESSKEY SECRETKEY --api S3v4 # mc cp backup/UPLOADS-BACKUP-BUCKET /var/discourse/shared/app/uploads- 恢复最新的数据库备份;我建议你 Restore a backup from the command line
- 仅在确认站点运行正常后,按照上述文档重新配置上传到 S3 的备份。
流式 postgresql 备份
未来,我可能会创建、测试并提供一种配置,以启用使用 连续 WAL 归档 通过 postgresql 中的 archive-command 使用 minio-client 流式传输近乎实时的 Postgres 备份,类似于流式上传备份。
性能监控
至少有两种性能监控方法。
Prometheus 容器
设置 prometheus,如果你在同一系统上运行,将 prometheus 日志放在 /var/discourse/shared/prometheus。Prometheus 文件可能会变得很大,你不希望它们填满根文件系统;如果你迁移到更新的主机系统(无论是升级到更大的 VM 还是安装新操作系统的 VM),你可能还希望带上它们。
如果你在 discourse 系统(或公共互联网上的任何地方)部署 prometheus,请在其前面配置安全。以这种方式安装,一种选择是类似以下的 nginx 配置:
location /prometheus/ {
auth_basic "Prometheus";
auth_basic_user_file /etc/nginx/prometheus-htpasswd;
proxy_pass http://localhost:9090/;
}
Sysstat
如果 Prometheus 太复杂,请考虑使用 sysstat 代替。
dnf install sysstat(或在 debian 及其衍生版本上apt install sysstat)systemctl enable --now sysstatsystemctl enable --now sysstat-collect.timersystemctl enable --now sysstat-summary.timersystemctl edit sysstat-collect.timer并将OnCalendar=*:00/10更改为OnCalendar=*:00/2- 如果 /etc/default/sysstat 存在,将
false更改为true
此后,sar 命令可以告诉你是否偶尔资源不足。
其他资源
这里有一个补充(且更紧凑)的讨论,关于在内部使用 Discourse 作为内部通信的主要形式。