SSD Nodes Learn Hosting plans →
指南 Matt Connor作者: Matt Connor · 更新于 2026-08-22

如何在 VPS 上用 Docker 安装 Discourse

使用 Discourse 官方 Docker launcher 在 VPS 上完成部署:检查内存和 swap、绑定真实域名、配置 SMTP 与 app.yml,执行 rebuild,并处理 TLS 和反向代理。

在 VPS 上安装 Discourse:一个容器,一个配置文件

要在 VPS 上安装 Discourse,请运行项目自带的安装程序,完成简短的向导配置,然后等待构建完成。Discourse 以单个 Docker 容器的形式发布,其中包含 Rails 应用、PostgreSQL、Redis 和 nginx。之后需要修改的所有内容都位于一个文件中,即 /var/discourse/containers/app.yml;每次修改都必须通过重新构建才能应用到站点。

官方安装方式是 discourse_docker:一个 launcher shell 脚本,以及一组 YAML 模板。Discourse 不支持由您自行编写的 Compose 文件,也不建议手动拆分该容器。如果您习惯于 在 VPS 上使用 Docker Compose 运行服务,需要注意两者的结构不同。这里没有 docker compose up -d,./launcher rebuild app 就是部署。

开始前 Discourse 的要求

有 4 项要求容易被忽略,而且每一项都会在到达登录页面之前导致问题。

  • 内存。一个容器同时运行 PostgreSQL、Redis、Sidekiq 和 Ruby Web 服务器。构建步骤会编译资源文件,所需内存高于网站运行时的内存。
  • 真实域名。随附的示例配置明确写道:“Discourse 不支持直接使用 IP 地址。”
  • 出站邮件路径。账户激活、密码重置、管理员邀请和摘要邮件都通过 SMTP(简单邮件传输协议)发送。
  • 主机上的 80 和 443 端口必须空闲,除非您有意将 Discourse 放在现有代理之后。
ChartDiscourse published hardware requirements (official install docs, August 2026)
The data behind this chart
[
  {
    "label": "Documented minimum",
    "ram_gb": 1,
    "storage_gb": 10
  },
  {
    "label": "Documented recommended",
    "ram_gb": 2,
    "storage_gb": 20
  }
]

官方安装文档将最低要求定为 1 GB RAM(配合 swap)和 10 GB 磁盘,并建议使用 2 GB RAM 和 20 GB 磁盘。第一行表示安装程序能够完成安装所需的数值,不是运行社区所需的数值。两者的差距很重要,因为内存峰值出现在构建阶段,而不是流量高峰期。

在安装前将域名指向服务器

为要使用的主机名创建 A 记录,然后直接在服务器上确认解析结果。

dig +short forum.example.com
curl -4 -s https://ifconfig.co

两个命令必须输出相同的地址。它们必须一致,因为安装向导会对主机名执行连接测试,而仍然指向其他位置的记录会导致该测试失败。两分钟前创建的记录可能仍在缓存中,因此应等待旧 TTL(生存时间)过期,不要反复尝试绕过向导。

现在决定是否让 CDN 代理该记录。代理记录会隐藏服务器地址,随后容器的证书申请会失败,因为 ACME(自动证书管理环境)质询由代理响应,而不是由 Discourse 响应。首次安装时,请不要代理该记录。

运行官方安装程序

一条命令会安装 git,使用 Docker 自带的安装脚本安装 Docker,将 discourse_docker 克隆到 /var/discourse,并启动设置向导。

wget -qO- https://raw.githubusercontent.com/discourse/discourse_docker/main/install-discourse | sudo bash

如果服务器上已经安装 Docker,且您希望逐步查看每个操作,请手动执行相同的步骤。

sudo -s
git clone https://github.com/discourse/discourse_docker.git /var/discourse
cd /var/discourse
./discourse-setup

请以 root 身份运行。以普通用户身份启动时,discourse-setup 会立即停止,并显示 This script must be run as root. Please sudo or log in as root first.。如果服务器上未安装 Docker,则会显示 Docker is not installed. Please install Docker first. 后停止,因为手动克隆不会为您安装任何组件。

安装向导会询问什么,以及会写入什么

截至 2026 年 8 月,discourse-setup 只是一个薄封装。它会将 discourse/setup-wizard:release 作为容器运行,使用主机网络并挂载 Docker socket,因此向导可以检查正在配置的计算机。它会询问主机名和管理员电子邮件地址,然后询问 SMTP 配置。它会写入 containers/app.yml,随后重新构建。

开始前需要了解两种行为。如果计算机内存不足且没有 swap,向导会停止并提供创建 swap 的选项:随后该封装会创建一个 2 GB 的 /swapfile,将其添加到 /etc/fstab,在 /etc/sysctl.d/30-discourse-swap.conf 中设置 vm.swappiness = 10,然后重新启动向导。向导完成后会输出 Rebuilding app in 5 seconds (Ctrl+C to cancel)...,并在主机上运行 ./launcher rebuild app。在小型 VPS 上,此构建需要数分钟;首次构建最慢,因为每个资源都会从头编译。

./discourse-setup --help 列出发生问题时有用的标志。--skip-rebuild 会写入配置但不执行构建,--skip-connection-test 会跳过 DNS 和端口检查。仅当您已经知道测试失败的原因时才使用 --skip-connection-test,例如主机位于您管理的网络防火墙之后。

在首次重新构建前阅读 app.yml

向导会写入一个现在由您负责维护的文件。使用 sudo nano /var/discourse/containers/app.yml 打开它。以下部分几乎决定了所有关键行为。

templates:
  - "templates/postgres.template.yml"
  - "templates/redis.template.yml"
  - "templates/web.template.yml"
  - "templates/web.ratelimited.template.yml"
  ## Uncomment these two lines if you wish to add Lets Encrypt (https)
  #- "templates/web.ssl.template.yml"
  #- "templates/web.letsencrypt.ssl.template.yml"

expose:
  - "80:80"   # http
  - "443:443" # https

env:
  DISCOURSE_HOSTNAME: "forum.example.com"
  DISCOURSE_DEVELOPER_EMAILS: "you@example.com"
  DISCOURSE_SMTP_ADDRESS: smtp.example.com
  DISCOURSE_SMTP_PORT: 587
  DISCOURSE_SMTP_USER_NAME: user@example.com
  DISCOURSE_SMTP_PASSWORD: "your-smtp-password"

DISCOURSE_HOSTNAME 是网站响应请求的地址,Discourse 会根据它生成链接。因此,值错误会导致网站首次加载正常,随后却将您重定向到其他位置。DISCOURSE_DEVELOPER_EMAILS 是逗号分隔的列表,其中的地址会在首次注册时自动获得管理员权限。请将您自己的地址添加到此处,并使用该地址注册,因为首个管理员帐户就是通过这种方式创建的。

该文件以明文存储 SMTP 密码,因此请使用 sudo chmod 700 /var/discourse/containers 限制目录的访问权限。该文件也是 YAML 文件,因此空格就是配置内容的一部分:键的缩进不正确会导致构建因解析错误而失败,网站也无法使用。示例文件本身记录了一个容易出错的情况。在未加引号的密码中,# 会开始一段注释。因此,包含该字符的密码必须加引号。

邮件配置是大多数安装在此中断的步骤

截至 2026 年 8 月,向导允许跳过 SMTP,改用 Discourse ID 登录;app.yml 也提供了对应的 DISCOURSE_SKIP_EMAIL_SETUP 开关,其说明是跳过电子邮件设置验证。初步了解软件时可以跳过。但对于社区站点,这不是合适的选择,因为没有出站邮件,用户无法激活账户或重置密码。

实际问题是,大多数 VPS 提供商都会阻止出站端口 25,因此服务器上的普通邮件服务器无法投递邮件。请使用端口 587 上的经过身份验证的中继,或使用端口 465,并启用隐式 TLS(传输层安全)。对于端口 465,请设置 DISCOURSE_SMTP_FORCE_TLS: true;示例配置针对该端口推荐了此设置。在重建之前,先从主机测试连通性。

nc -vz smtp.example.com 587

正常结果是单独一行,并以 succeeded! 结尾。命令挂起后超时,表示从 VPS 发出的路径上端口被阻止,任何 Discourse 设置都无法解决此问题。请改用提供商允许的端口,或要求提供商开放该端口。

站点启动后,请在 Admin 的 Email 页面发送测试消息,然后查看同一页面上的 Skipped 和 Bounced 选项卡。Discourse 会在这些选项卡中记录它拒绝发送的邮件,以及中继拒绝的邮件,并显示具体原因。这比读取日志更快。

TLS:让容器自行获取证书

如果 Discourse 占用 80 和 443 端口,请使用其内置的证书签发功能。取消注释上文所示的两行 SSL 模板配置,然后重新构建。该模板会驱动 acme.sh,将证书存储在共享卷的 /shared/ssl 下,在容器内按计划续期,并将 Discourse 设置为强制使用 HTTPS。

此功能要求 80 端口保持可从互联网访问,因为 HTTP challenge 会通过该端口响应。仅允许 443 的防火墙会导致构建成功完成,但证书始终无法签发。重新构建后,立即使用 ./launcher logs app 检查结果。

应在前端使用 nginx 还是 Caddy?

如果 VPS 上只有 Discourse 这一个 Web 服务,则不需要这样做。容器已经运行经过调优的 nginx,额外增加一层代理会多经过一跳,还会增加一个需要续期的证书以及新的响应头错误来源。

如果同一台 VPS 还提供其他网站,则应在前端使用代理。将 templates/web.socketed.template.yml 添加到模板列表中,注释掉两行 expose,并保持两个 SSL 模板处于注释状态。这样,容器会在 /var/discourse/shared/standalone/nginx.http.sock 的 Unix 套接字上监听,完全不占用端口,从而将 80 和 443 端口留给您自己的代理。

server {
  listen 443 ssl;
  server_name forum.example.com;

  location / {
    proxy_pass http://unix:/var/discourse/shared/standalone/nginx.http.sock:;
    proxy_set_header Host $http_host;
    proxy_http_version 1.1;
    proxy_set_header X-Forwarded-For $remote_addr;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-Real-IP $remote_addr;
  }
}

.sock 后面的冒号是 nginx Unix 套接字语法的一部分,缺少它时 sudo nginx -t 会拒绝加载配置。X-Forwarded-Proto 也不是可选项。Discourse 会生成绝对链接;如果没有该响应头,它会在 HTTPS 页面中生成 http:// 链接,浏览器会将其阻止为混合内容。容器改用套接字后,TLS 由您负责,因此应在主机上使用 在 Ubuntu 24.04 和 nginx 上使用 Certbot 申请证书。如果您还没有确定代理方案,nginx、Caddy 和 Traefik 对比介绍了相关取舍。

重建、升级以及实际使用的命令

cd /var/discourse
./launcher rebuild app

rebuild 会销毁正在运行的容器,从 app.yml 引导创建新容器并启动。整个构建期间网站都会离线,因此每次配置更改都应视为会造成几分钟停机的计划维护。

仅更改 env: 下的值不需要重建。./launcher destroy app && ./launcher start app 会使用已构建的镜像重新创建容器,耗时只有几秒。templates: 或 hooks: 下的任何内容都会改变镜像本身,因此需要完整重建。

升级有两种方式。小版本更新可通过位于 /admin/upgrade 的 Web 界面应用,该界面由 docker_manager 插件提供;构建过程中,app.yml 会克隆此插件。基础镜像或模板的更改来自 git。

cd /var/discourse
git pull
./launcher rebuild app

小型服务器通常会在重建时失败,因为资源编译是整个系统的内存峰值。如果构建中途停止,且 dmesg 显示类似 Out of memory: Killed process 的行并指向一个 ruby 进程,那么即使网站此前运行正常,构建期间仍可能已耗尽内存。添加 swap 后再次运行重建。

./launcher logs app
./launcher enter app
./launcher cleanup

logs 会输出容器日志,enter 会在容器内打开 shell,cleanup 会删除已停止超过 24 小时的容器。请定期运行 cleanup,因为每次重建都会留下一个旧容器,小型 VPS 的磁盘空间会在不知不觉中耗尽。

备份,以及备份不包含的文件

在 Admin 的 Backups 页面创建备份。归档文件会保存到主机上的 /var/discourse/shared/standalone/backups/default/。也可以从 shell 执行相同的任务。

cd /var/discourse
./launcher enter app
discourse backup

discourse restore <filename> 会还原备份,但必须先运行 discourse enable_restore,否则还原会被拒绝。此保护机制可防止误执行命令,覆盖正在运行的论坛。

有两个问题需要您自行处理。归档包含数据库;只有启用了包含上传文件的备份设置时,才会包含已上传的文件。因此,在依赖备份前,请先检查该设置。归档不会包含 app.yml,所以将备份还原到全新的 VPS 后,仍需配置主机名和 SMTP 配置块。这意味着还必须将该文件复制到主机之外。

归档文件也与受保护的网站位于同一块磁盘上,这不算备份。请按计划将其传输到其他位置。

rsync -avz root@forum.example.com:/var/discourse/shared/standalone/backups/default/ ~/discourse-backups/

繁忙论坛需要多少内存

引导脚本会根据检测到的内存和 CPU 设置 UNICORN_WORKERS 和 db_shared_buffers,示例配置将共享缓冲区限制为总内存的四分之一。每个 Unicorn worker 都是一个完整的 Ruby 进程,Sidekiq 也会在旁边运行后台任务,因此内存使用量取决于并发请求数,而不是注册会员数。只有几百名会员的低流量论坛并不算高负载。通常更重要的是同一台服务器上还有哪些服务;如果还运行照片库,请参考PhotoPrism 和 Immich 对比中测得的最低内存需求,以判断 Discourse 重建是否有足够余量完成。

不要根据文章中的数字规划服务器,包括本文中的数字。请测量自己的实际需求。

free -m
docker stats --no-stream

持续使用 swap 且页面加载缓慢,说明内存不足。内存使用稳定但页面加载缓慢,通常表示问题出在其他方面,因此在购买更高规格的方案前,请先阅读 ./launcher logs app。还应从服务器外部添加一项检查,因为论坛在凌晨 3 点耗尽内存时可能会静默失败:在独立主机上运行自托管的 Uptime Kuma 状态监视器,可以在会员发现问题前通知您。

Discourse 不适用的场景

Discourse 是一个大型应用,安装过程复杂。app.yml 中的每项设置发生变化时,都需要重新构建。这个成本换来了完善的内容审核工具,以及在存档规模较大时仍然可用的搜索功能。对于只想找个地方交流的 30 个人来说,它提供的功能和资源都超出了实际需求。请先阅读自托管论坛软件比较,选择 Discourse 应该是因为你需要它提供的功能,而不是因为你只知道这个名称。

FAQ

我可以在没有域名的情况下将 Discourse 安装到 VPS 上吗?

不可以。随附的配置说明,Discourse 无法使用裸 IP 地址运行,并且必须设置 DISCOURSE_HOSTNAME。Discourse 根据该主机名生成绝对链接,因此在此处使用 IP 地址会导致链接失效,并阻止证书签发。开始前先创建 A 记录,然后使用 dig +short forum.example.com 确认该记录解析到服务器地址。

我必须配置 SMTP 才能完成安装吗?

截至 August 2026,可以跳过这一步。安装向导会改为提供 Discourse ID 登录方式,而 app.yml 包含一个可跳过电子邮件设置验证的开关。除非只是初步试用,否则应完成配置,因为账户激活和密码重置都依赖电子邮件。请使用经过身份验证的端口 587 或 465 中继,因为大多数 VPS 提供商都会阻止出站端口 25。

为什么 Discourse 重建会在中途失败?

通常原因是内存不足。构建期间的资源编译比运行中的站点需要更多内存,因此服务器即使能够正常提供论坛服务,也可能无法完成重建。如果 dmesg 显示 Out of memory: Killed process 并指出某个 ruby 进程,请添加 swap(安装向导创建的 swapfile 大小为 2 GB),然后再次运行 ./launcher rebuild app。如果构建因 YAML 错误停止,则说明 app.yml 中存在缩进错误。

Discourse 应该放在我自己的 nginx 或 Caddy 后面吗?

仅当 VPS 还托管其他站点时才需要。在单独托管 Discourse 的服务器上,应让容器继续监听端口 80 和 443,并由容器自行签发证书,这样需要维护的组件更少。若要共享服务器,请添加 templates/web.socketed.template.yml,注释掉 expose 行,并将请求代理到 /var/discourse/shared/standalone/nginx.http.sock 中的 unix socket。请转发 X-Forwarded-Proto,否则 Discourse 会在 HTTPS 页面中生成 http:// 链接。

如何备份自托管的 Discourse?

使用管理后台中的 Backups 页面,或在 ./launcher enter app 之后运行 discourse backup。归档文件会保存到主机上的 /var/discourse/shared/standalone/backups/default/。确认已启用包含上传文件的设置,将 /var/discourse/containers/app.yml 与归档文件一起复制,并将两者移到另一台机器,因为与站点位于同一磁盘上的备份无法应对它原本要防范的故障。