SSD Nodes Learn 🎉 VPS $5.50/月起
指南 Matt Connor作者: Matt Connor

如何在 VPS 上通过 Docker 安装 Discourse 论坛

在 VPS 上部署 Discourse 论坛的完整指南。涵盖官方 Docker 启动器配置、app.yml 参数设置、SMTP 邮件服务对接及 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 的必要条件

有四个要求容易被忽视,且每一个都会在到达登录页面前导致安装失败。

  • 内存。单个容器需要同时运行 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 内存(含 Swap)和 10 GB 磁盘空间,并建议配置 2 GB 内存和 20 GB 磁盘空间。请将第一行数据视为安装程序能够完成运行的门槛,而非运行社区所需的理想配置。两者之间的差异在于,内存峰值出现在构建阶段,而非处理流量时。

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

为即将使用的主机名创建一条 A 记录,随后在服务器上进行确认。

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

这两条命令必须输出相同的 IP 地址。它们必须保持一致,因为安装向导会针对你的主机名进行连接测试,如果记录仍指向其他位置,测试将会失败。两分钟前创建的记录可能仍处于缓存状态,请等待旧的 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 套接字,以便向导能够检查正在配置的机器。它会询问主机名和管理员邮箱地址,随后询问 SMTP 配置。它会写入 containers/app.yml,然后执行重建。

开始前,有两点行为需要了解。如果机器内存不足且未配置交换空间,向导会停止并提示创建:封装程序随后会创建一个 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 端口的认证中继,或使用支持隐式 TLS(传输层安全)的 465 端口。对于 465 端口,请设置 DISCOURSE_SMTP_FORCE_TLS: true,示例配置文件中也建议针对该端口进行此设置。在重建服务之前,请先从主机测试连通性。

nc -vz smtp.example.com 587

正常的测试结果应为以 succeeded! 结尾的单行输出。如果命令执行后挂起并最终超时,说明 VPS 的出站路径上封锁了该端口,任何 Discourse 设置都无法解决此问题。请更换为提供商允许的端口,或要求提供商开放该端口。

站点启动后,请从管理页面的“电子邮件”选项卡发送测试消息,然后查看同一页面上的“已跳过”和“已退回”选项卡。Discourse 会在这些选项卡中记录拒绝发送的邮件以及被中继服务器拒绝的邮件,并注明原因,这比查看日志的效率更高。

TLS:让容器自行获取证书

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

为确保此功能生效,80 端口必须能从公网访问,因为 HTTP 挑战(HTTP challenge)需在此端口响应。如果防火墙仅允许 443 端口,构建过程虽然会完成,但证书将无法签发。重新构建后,请立即使用 ./launcher logs app 检查结果。

是否应该在前端部署 Nginx 或 Caddy?

如果 VPS 上仅运行 Discourse 这一个 Web 服务,则无需部署。容器内已运行优化过的 Nginx,再加一层代理会增加网络跳转、额外的证书续期任务,并可能引入新的 Header 配置错误。

当同一台 VPS 需要托管其他站点时,请在前端部署代理。将 templates/web.socketed.template.yml 添加到模板列表中,注释掉两行 expose,并保持两个 SSL 模板处于注释状态。此时容器将监听 /var/discourse/shared/standalone/nginx.http.sock 的 Unix socket,不再占用任何端口,从而将 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 socket 语法的一部分,缺少该冒号会导致 sudo nginx -t 拒绝加载配置。X-Forwarded-Proto 同样不可或缺。Discourse 会生成绝对链接,若缺少该 Header,它会在 HTTPS 页面中输出 http:// 链接,导致浏览器将其拦截为混合内容。当容器改为使用 socket 通信后,TLS 终止由你负责,请在宿主机上通过 Ubuntu 24.04 上的 Certbot 与 Nginx 配置 申请证书。如果你尚未选定代理软件,Nginx、Caddy 与 Traefik 对比 一文涵盖了你需要权衡的各项因素。

重建、升级及常用命令

cd /var/discourse
./launcher rebuild app

rebuild 会销毁正在运行的容器,根据 app.yml 引导创建一个新容器并启动。整个构建期间站点处于离线状态,因此请将每次配置变更视为几分钟的计划内停机。

仅修改 env: 下的数值无需执行此操作。./launcher destroy app && ./launcher start app 会基于已构建的镜像重新创建容器,仅需几秒钟。任何 templates:hooks: 下的变更都会改变镜像本身,因此需要执行完整重建。

升级有两种方式。小版本更新通过 /admin/upgrade 的 Web 界面应用,该功能由 app.yml 在构建期间克隆的 docker_manager 插件提供。基础镜像或模板的变更则来自 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 的磁盘空间会因此悄然耗尽。

备份,以及备份文件中不包含的内容

在管理后台的“备份”页面执行备份。归档文件会存放在主机的 /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_WORKERSdb_shared_buffers,示例配置将共享缓冲区限制为总内存的四分之一。每个 unicorn 工作进程都是一个完整的 Ruby 进程,Sidekiq 在其旁边运行后台任务,因此内存使用量取决于并发请求数,而非注册会员总数。对于仅有几百名会员的活跃度较低的论坛,负载并不沉重。

不要仅凭文章(包括本文)中的数字来评估服务器规格。请务必自行测量。

free -m
docker stats --no-stream

如果交换分区持续被占用且页面加载缓慢,说明内存不足。如果内存占用平稳但页面加载缓慢,通常是其他原因导致,因此在购买更高配置的套餐前,请先阅读 ./launcher logs app。此外,请务必从外部进行监控,因为论坛若在凌晨 3 点因内存耗尽而崩溃,通常不会有任何提示:在另一台主机上部署 自托管的 Uptime Kuma 状态监控,可以在用户发现问题前向你发出预警。

何时不应选择 Discourse

Discourse 是一个大型应用,安装过程繁重,且每次修改 app.yml 中的设置都需要进行重建。这种开销换来的是完善的审核工具,以及在归档内容庞大时依然有效的搜索功能。对于一个仅有 30 人的交流场所而言,它的系统资源消耗远超实际需求。请先阅读 自托管论坛软件对比,选择 Discourse 是因为你需要它提供的功能,而不是因为它名气大。

FAQ

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

不可以。Discourse 的出厂配置要求必须使用域名,且需要 DISCOURSE_HOSTNAME。Discourse 会基于该主机名生成绝对链接,使用 IP 地址会导致链接失效并无法签发证书。请在开始前创建 A 记录,并使用 dig +short forum.example.com 确认其已解析到你的服务器地址。

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

截至 2026 年 8 月,你可以跳过此步骤。安装向导提供了 Discourse ID 登录方式,且 app.yml 包含一个跳过邮件设置验证的开关。但若要进行初步体验之外的操作,请务必配置 SMTP,因为账户激活和密码重置均需通过邮件发送。请使用 587 或 465 端口的认证中继,因为大多数 VPS 提供商会封禁出站 25 端口。

为什么我的 Discourse 重建在过程中失败了?

通常是因为内存不足。构建过程中的资源编译比站点运行需要更多内存,因此能够正常运行论坛的服务器在重建时仍可能失败。如果 dmesg 显示 Out of memory: Killed process 涉及 ruby 进程,请添加交换空间(向导自带的交换文件为 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?

请使用管理后台的备份页面,或在 ./launcher enter app 之后运行 discourse backup。归档文件会存放在宿主机的 /var/discourse/shared/standalone/backups/default/ 目录下。请确认已开启包含上传文件的备份设置,将 /var/discourse/containers/app.yml 与归档文件一并复制并移动到另一台机器上,因为备份在与站点相同的磁盘上无法应对磁盘故障。