如何在 VPS 上安裝 Discourse Docker
使用官方 Docker launcher 在 VPS 部署 Discourse,確認 RAM 與 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(simple mail transfer protocol)寄出。
- 主機上的 80 和 443 埠必須可用,除非你刻意將 Discourse 放在現有代理伺服器後方。
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.。
設定精靈會詢問的內容,以及寫入的檔案
截至 August 2026,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,表示空白字元就是設定內容的一部分:索引錯誤的鍵會使建置因剖析錯誤而失敗,導致網站無法使用。範例檔案本身記載了一個常見陷阱。在未加引號的密碼中,# 會開始註解。因此,只要密碼包含該字元,就必須加上引號。
Email 是最常導致安裝卡住的步驟
截至 August 2026,精靈允許略過 SMTP,改用 Discourse ID 登入;app.yml 也提供相符的 DISCOURSE_SKIP_EMAIL_SETUP 選項,說明為略過電子郵件設定驗證。初步了解軟體時可以略過。但若要建立社群,這不是好的選擇,因為沒有對外寄信功能,使用者就無法啟用帳戶或重設密碼。
實務上的問題是,多數 VPS 供應商會封鎖對外連線的 25 埠,因此在該主機上直接執行郵件伺服器無法投遞郵件。請使用具備驗證功能的 relay,透過 587 埠傳送,或透過使用 implicit TLS(transport layer security)的 465 埠傳送。使用 465 埠時,請設定 DISCOURSE_SMTP_FORCE_TLS: true;範例設定也建議在該埠使用此設定。重新建置前,先從主機測試是否可連線。
nc -vz smtp.example.com 587正常結果是單行輸出,並以 succeeded! 結尾。若命令卡住後逾時,表示從 VPS 對外的路徑上有連接埠遭到封鎖,任何 Discourse 設定都無法解決。請改用供應商允許的連接埠,或要求供應商開放該連接埠。
網站啟動後,請從 Admin 中的 Email 頁面傳送測試訊息,再查看同一頁面的 Skipped 與 Bounced 索引標籤。Discourse 會在這些索引標籤中記錄它拒絕傳送的郵件,以及 relay 拒絕的郵件;其中也會列出原因,因此比讀取日誌更快。
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 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 會寫入絕對 URL,因此缺少該標頭時,會在 HTTPS 頁面中產生 http:// URL,瀏覽器會將其封鎖為混合內容。容器改用 socket 後,TLS 就由您負責,因此請在主機上使用 Ubuntu 24.04 與 nginx 上的 Certbot 申請憑證。如果您尚未決定代理,nginx、Caddy 與 Traefik 比較 說明了各方案的取捨。
重建、升級與實際會使用的指令
cd /var/discourse
./launcher rebuild apprebuild 會銷毀執行中的容器,從 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 cleanuplogs 會輸出容器的內容,enter 會在容器內開啟 shell,而 cleanup 會移除已停止超過 24 小時的容器。請不時執行 cleanup,因為每次重建都會留下舊容器,小型 VPS 的磁碟空間可能在未察覺的情況下耗盡。
備份,以及備份未包含的檔案
在 Admin 的 Backups 頁面建立備份。封存檔會寫入主機上的 /var/discourse/shared/standalone/backups/default/。也可以從 shell 執行相同的工作。
cd /var/discourse
./launcher enter app
discourse backupdiscourse restore <filename> 可還原備份,但必須先執行 discourse enable_restore,系統才會允許還原。這項防護可避免誤下指令覆寫正在運作的論壇。
有兩項缺口需要自行補上。封存檔包含資料庫;只有在啟用包含上傳檔案的備份設定時,才會包含上傳檔案。因此,確認該設定後再信任備份。封存檔永遠不包含 app.yml,所以還原到全新的 VPS 時,仍需要主機名稱與 SMTP 區塊。這表示也必須將該檔案複製到主機外保存。
此外,封存檔與受保護的網站位於同一個磁碟上,這不算備份。請依排程將它傳送到其他位置。
rsync -avz root@forum.example.com:/var/discourse/shared/standalone/backups/default/ ~/discourse-backups/論壇流量繁忙時需要多少 RAM
Bootstrap 會根據偵測到的記憶體與 CPU 設定 UNICORN_WORKERS 和 db_shared_buffers,而範例設定會將 shared buffers 上限設為總記憶體的四分之一。每個 unicorn worker 都是完整的 Ruby 程序,Sidekiq 也會在旁執行背景工作,因此記憶體用量取決於並行請求數,而不是註冊會員數。只有幾百名會員的論壇通常不算繁重的工作負載。通常更重要的是同一台主機上還執行哪些服務;如果是相片媒體庫,PhotoPrism 與 Immich 的比較中測得的 RAM 最低需求,可協助你判斷 Discourse 重建是否仍有足夠餘裕完成。
不要根據文章中的數字來配置伺服器,包括本文。請測量自己的環境。
free -m
docker stats --no-streamSwap 持續使用且頁面載入緩慢,表示 RAM 不足。記憶體使用量穩定但頁面載入緩慢,通常代表其他問題,因此請先閱讀 ./launcher logs app,再考慮購買更大的方案。也應從主機外部加入監控,因為論壇在 3am 耗盡記憶體時可能會無聲失效:在另一台主機上執行自架的 Uptime Kuma 狀態監控,就能比會員更早發現問題。
Discourse 不適合的情況
Discourse 是大型應用程式,安裝程序複雜,而且 app.yml 中的每項設定變更都需要重新建置。這項成本換來的是完整的管理工具,以及在封存內容龐大時仍能正常運作的搜尋功能。若只有 30 人想找個地方交流,Discourse 的功能與系統需求都超出實際需要。請先閱讀自架論壇軟體比較,再根據你需要 Discourse 所提供的功能來選擇,而不是因為你早已知道這個名稱。
FAQ
我可以在沒有網域名稱的 VPS 上安裝 Discourse 嗎?
不可以。隨附的設定明確指出,Discourse 無法使用純 IP 位址運作,而且必須設定 DISCOURSE_HOSTNAME。Discourse 會根據該主機名稱建立絕對連結,因此填入 IP 位址會導致連結失效,也會阻止憑證簽發。開始前先建立 A 記錄,再使用 dig +short forum.example.com 確認該記錄解析到伺服器位址。
我必須設定 SMTP 才能完成安裝嗎?
截至 August 2026,可以略過此步驟。設定精靈會改提供 Discourse ID 登入方式,而 app.yml 含有可略過電子郵件設定驗證的開關。不過,除了初步試用之外,仍應完成設定,因為帳號啟用與密碼重設都會透過電子郵件寄送。請使用 port 587 或 465 上經過驗證的 relay,因為大多數 VPS 供應商會封鎖對外 port 25。
為什麼 Discourse 重建會中途失敗?
通常是記憶體不足。建置期間的資產編譯比執行中的網站需要更多記憶體,因此即使伺服器能正常提供論壇服務,仍可能無法完成重建。如果 dmesg 顯示 Out of memory: Killed process 並指出 ruby 程序,請增加 swap(設定精靈建立的 swapfile 為 2 GB),然後再次執行 ./launcher rebuild app。如果建置因 YAML 錯誤停止,則表示 app.yml 可能有縮排錯誤。
Discourse 應該放在我自己的 nginx 或 Caddy 後方嗎?
只有在 VPS 同時提供其他網站時才需要。若伺服器只執行 Discourse,讓容器保留 port 80 和 443 並自行簽發憑證即可,這樣需要管理的元件較少。若要共用伺服器,請加入 templates/web.socketed.template.yml,註解掉 expose 行,並將代理請求轉送至 /var/discourse/shared/standalone/nginx.http.sock 的 unix socket。請傳遞 X-Forwarded-Proto,否則 Discourse 會在 HTTPS 頁面產生 http:// 連結。
如何備份自架的 Discourse?
使用 Admin 中的 Backups 頁面,或在執行 ./launcher enter app 後執行 discourse backup。封存檔會放在主機的 /var/discourse/shared/standalone/backups/default/。確認已啟用包含上傳檔案的設定,將 /var/discourse/containers/app.yml 與封存檔一併複製,並將兩者移至另一台機器,因為備份若與網站位於同一張磁碟上,無法在其所要防範的故障發生時保留下來。