如何在 VPS 上使用 Docker 安裝 Discourse
完整教學教您在 VPS 上部署 Discourse。涵蓋官方 Docker 安裝流程、app.yml 設定、SMTP 配置、記憶體需求與重建步驟,解決安裝過程中的常見錯誤。
在 VPS 上安裝 Discourse:單一容器與單一設定檔
若要在 VPS 上安裝 Discourse,請執行該專案提供的安裝程式,回答精靈中的幾個問題,並等待建置完成。Discourse 以單一 Docker 容器形式發布,其中包含 Rails 應用程式、PostgreSQL、Redis 與 nginx。您後續的所有變更皆集中於單一檔案 /var/discourse/containers/app.yml 中,且每次變更都必須透過重建(rebuild)才能套用到網站。
官方安裝方式為 discourse_docker:包含一個 launcher Shell 指令碼與一組 YAML 範本。Discourse 不支援您自行編寫的 Compose 檔案,且該容器不應手動拆解。若您習慣 使用 Docker Compose 在 VPS 上執行服務,請留意此處架構不同。這裡沒有 docker compose up -d,且 ./launcher rebuild app 即為部署方式。
開始安裝 Discourse 前的必要條件
有四項需求經常導致安裝失敗,且在您進入登入頁面之前就會遇到問題。
- 記憶體。單一容器需同時執行 PostgreSQL、Redis、Sidekiq 與 Ruby 網頁伺服器。建置階段會編譯資源,所需的記憶體高於網站實際執行時的需求。
- 真實網域名稱。官方提供的範例設定檔已明確指出:「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 (time to live) 過期,不要強行跳過精靈的檢查。
現在決定該記錄是否要透過 CDN 代理。代理後的記錄會隱藏您的伺服器位址,這會導致容器的憑證請求失敗,因為 ACME (automatic certificate management environment) 驗證是由代理伺服器回應,而非由 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 僅是一個輕量級的封裝程式。它會以 host network 模式執行 discourse/setup-wizard:release 容器,並掛載 Docker socket,以便精靈能檢測正在設定的機器。它會詢問主機名稱與管理員電子郵件地址,接著詢問您的 SMTP 區塊。完成後,它會寫入 containers/app.yml 並重新建置。
在開始之前,有兩種行為值得注意。若機器記憶體不足且未設定 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 埠的驗證轉送(authenticated relay),或使用具備隱式 TLS(傳輸層安全性)的 465 埠。若使用 465 埠,請設定 DISCOURSE_SMTP_FORCE_TLS: true,範例設定檔亦建議針對該埠使用此參數。在重建服務前,請先從主機端測試連線能力。
nc -vz smtp.example.com 587正常的測試結果應為單行輸出並以 succeeded! 結尾。若指令執行後卡住並顯示逾時,代表該埠在您的 VPS 對外路徑上遭到封鎖,任何 Discourse 設定皆無法解決此問題。請改用供應商允許的埠號,或要求供應商開啟該埠。
網站啟動後,請從管理介面的 Email 頁面發送測試郵件,接著查看同一頁面中的 Skipped 與 Bounced 分頁。這些分頁會記錄 Discourse 拒絕發送的郵件以及轉送伺服器退回的郵件,並會註明原因,這比查看日誌更為快速。
TLS:讓容器自行取得憑證
若 Discourse 需佔用 80 與 443 埠,請使用其內建的憑證簽發功能。取消註解上述兩行 SSL 範本設定,接著重新建置。該範本會驅動 acme.sh,將憑證儲存於 /shared/ssl 下的共享儲存區,在容器內按排程自動續期,並將 Discourse 設定為強制使用 HTTPS。
此功能運作時,網際網路必須能連線至 80 埠,因為 HTTP 驗證挑戰(HTTP challenge)需在此埠回應。若防火牆僅開放 443 埠,建置程序雖會完成,但憑證將無法簽發。重新建置後,請立即使用 ./launcher logs app 檢查結果。
應該在前端部署 Nginx 還是 Caddy?
若 VPS 上僅運行 Discourse 單一網頁服務,則無需額外部署。容器內已預載調校過的 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 會產生絕對連結,若缺少該標頭,系統會在 HTTPS 頁面上輸出 http:// 連結,導致瀏覽器因混合內容(mixed content)問題而封鎖資源。當容器改用 socket 模式後,TLS 憑證管理將由您負責,請參考 Certbot on Ubuntu 24.04 and nginx 在主機端申請憑證。若您尚未決定使用哪款代理軟體,the nginx, Caddy and Traefik comparison 說明了各方案的權衡考量。
重建、升級與實際使用的指令
cd /var/discourse
./launcher rebuild apprebuild 會銷毀正在執行的容器,從 app.yml 重新啟動一個新容器。在整個建置過程中網站會處於離線狀態,因此請將每次設定變更視為數分鐘的排程停機時間。
僅變更 env: 下的值不需要這樣做。./launcher destroy app && ./launcher start app 會從您已建置的映像檔重新建立容器,這只需幾秒鐘。任何 templates: 或 hooks: 下的變更都會改變映像檔本身,因此需要完整重建。
升級有兩種方式。小版本更新可透過 /admin/upgrade 的網頁介面套用,該介面由 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 cleanuplogs 會輸出容器的日誌,enter 可進入容器內部執行 shell,而 cleanup 會移除已停止超過 24 小時的容器。請不時執行 cleanup,因為每次重建都會留下一個舊容器,小型 VPS 的磁碟空間可能會在不知不覺中耗盡。
備份與備份檔未包含的檔案
請從管理介面的 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/繁忙論壇的記憶體成本
啟動程序會根據偵測到的記憶體與 CPU 設定 UNICORN_WORKERS 與 db_shared_buffers,範例設定檔則將 shared buffers 限制為總記憶體的四分之一。每個 unicorn worker 都是一個完整的 Ruby 程序,而 Sidekiq 則在旁執行背景任務,因此記憶體用量取決於並發請求數,而非註冊會員數。對於僅有數百名會員的安靜論壇而言,負載並不沉重。
請勿僅憑文章中的數字(包含本文)來評估伺服器規格,應自行測量。
free -m
docker stats --no-stream若 Swap 持續被使用且頁面載入緩慢,代表記憶體不足。若記憶體用量穩定但頁面載入緩慢,通常是其他原因所致,請在升級方案前先閱讀 ./launcher logs app。此外,請務必從外部進行監控,因為論壇若在凌晨 3 點因記憶體耗盡而崩潰,通常不會發出通知:在獨立主機上部署 自架 Uptime Kuma 狀態監控,能在會員發現問題前先行通知您。
何時不該選擇 Discourse
Discourse 是一個大型應用程式,安裝過程繁重,且每次修改位於 app.yml 的設定時都需要進行重建。這些成本換來的是完善的審核工具,以及在存檔龐大時仍能正常運作的搜尋功能。若僅是三十人需要一個交流空間,這套系統對該對話需求而言過於龐大。請先閱讀 自架論壇軟體比較,並確保選擇 Discourse 是因為你需要其功能,而非僅因它是你已知的名稱。
FAQ
我可以在沒有網域名稱的情況下將 Discourse 安裝在 VPS 上嗎?
不行。預設的設定檔指出 Discourse 無法僅使用裸 IP 位址運作,且必須具備 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 程序,請增加 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?
請使用管理介面中的備份頁面,或在 ./launcher enter app 之後執行 discourse backup。封存檔會儲存在主機的 /var/discourse/shared/standalone/backups/default/ 目錄。請確認已開啟包含上傳檔案的設定,將 /var/discourse/containers/app.yml 與封存檔一併複製並移至另一台機器;若備份檔與網站位於同一顆磁碟,將無法在硬碟故障時發揮備份作用。