VPSにDiscourseをDockerでインストールする方法
公式のDocker launcherでDiscourseをVPSへ導入します。必要なRAMとswap、実在ドメイン、SMTP、app.ymlの設定、rebuild、TLSとリバースプロキシの注意点を解説します。
VPS に Discourse をインストールする: 1 つのコンテナ、1 つの設定ファイル
VPS に Discourse をインストールするには、プロジェクト独自のインストーラーを実行し、短いウィザードに回答して、ビルドが完了するまで待ちます。Discourse は、Rails アプリケーション、PostgreSQL、Redis、nginx を収めた単一の Docker コンテナとしてリリースされます。後から変更する設定はすべて 1 つのファイル /var/discourse/containers/app.yml にあり、変更内容は毎回リビルドによってサイトに反映されます。
公式のインストール方式は discourse_docker です。これは launcher の shell スクリプトと YAML テンプレート一式で構成されています。Discourse は、自分で作成した Compose ファイルをサポートしていません。また、コンテナを手作業で分割して運用することも想定されていません。VPS 上で Docker Compose を使ってサービスを実行することに慣れている場合は、構成が異なることを理解してください。ここには docker compose up -d はなく、./launcher rebuild app がデプロイそのものです。
Discourse の開始前に必要なもの
開始前に確認すべき要件は 4 つあります。どれもログイン画面に到達する前に問題になります。
- メモリ。1 つのコンテナで 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
}
]公式のインストール文書では、必要最低限の要件として、swap を有効にした 1 GB の RAM と 10 GB のディスク容量を挙げています。また、2 GB の RAM と 20 GB のディスク容量を推奨しています。最初の行は、インストーラーを完了させるための値であり、コミュニティを運用するための値ではないと考えてください。この差が重要なのは、メモリ使用量のピークがネットワークトラフィックではなくビルド時に発生するためです。
インストール前にドメインをサーバーへ向けます
使用するホスト名に A レコードを作成し、サーバー自体からそのレコードを確認します。
dig +short forum.example.com
curl -4 -s https://ifconfig.co両方のコマンドで同じアドレスが表示される必要があります。セットアップウィザードはホスト名に対して接続テストを実行するため、異なるアドレスが表示されるとテストに失敗します。2 分前に作成したレコードもキャッシュに残っている場合があります。ウィザードを無理に進めず、以前の TTL (time to live) が切れるまで待ってください。
レコードを CDN のプロキシ経由にするかどうかも、この時点で決めます。プロキシ経由のレコードではサーバーのアドレスが隠されます。そのため、コンテナの証明書要求は失敗します。ACME (automatic certificate management environment) チャレンジに Discourse ではなくプロキシが応答するためです。最初のインストールでは、レコードをプロキシ経由にしないでください。
公式インストーラーを実行する
1 つのコマンドで git をインストールし、Docker 公式のインストールスクリプトを使って Docker をインストールし、discourse_docker を /var/discourse に clone して、セットアップウィザードを起動します。
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-setuproot として実行します。一般ユーザーで起動すると、discourse-setup は直ちに This script must be run as root. Please sudo or log in as root first. で停止します。Docker がインストールされていない場合は、手動での clone では何もインストールされないため、Docker is not installed. Please install Docker first. で停止します。
セットアップウィザードの確認事項と書き込まれる内容
2026年8月時点で、discourse-setup は薄いラッパーです。ホストネットワークを使用し、Docker ソケットをマウントしたコンテナとして discourse/setup-wizard:release を実行します。これにより、ウィザードは設定対象のマシンを検査できます。最初にホスト名と管理者のメールアドレスを尋ね、続いて SMTP の設定ブロックを尋ねます。その後、containers/app.yml を書き込み、再ビルドします。
開始前に知っておくべき動作が 2 つあります。メモリが不足し、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 プロバイダーが送信 port 25 をブロックしていることです。そのため、サーバー上で通常のメールサーバーを動かしても配信できません。port 587 の認証付きリレーを使用するか、implicit TLS(transport layer security)を使用する port 465 のリレーを使用してください。port 465 では、サンプル設定がこの port に推奨している DISCOURSE_SMTP_FORCE_TLS: true を設定します。再ビルドする前に、ホストから到達性を確認してください。
nc -vz smtp.example.com 587正常な結果は、succeeded! で終わる 1 行です。コマンドが停止した後にタイムアウトする場合、VPS から外部への経路上で port がブロックされています。Discourse の設定では解決できません。プロバイダーが許可している port に変更するか、プロバイダーにブロック解除を依頼してください。
サイトが起動したら、Admin の Email ページからテストメッセージを送信し、同じページの Skipped タブと Bounced タブを確認します。これらのタブには、Discourse が送信を拒否したメールと、リレーが拒否したメールが記録されます。拒否理由も表示されるため、ログを読むより迅速に確認できます。
TLS: コンテナに証明書を取得させる
Discourse がポート 80 と 443 を使用する場合は、組み込みの証明書発行機能を使用します。上記の SSL テンプレート行 2 行のコメントを解除してから、再ビルドします。このテンプレートは acme.sh を制御し、証明書を /shared/ssl 配下の共有ボリュームに保存し、コンテナ内でスケジュールに従って更新し、Discourse で HTTPS を強制する設定を行います。
この機能を使用するには、ポート 80 にインターネットから到達できる必要があります。HTTP チャレンジへの応答に使用するためです。443 だけを許可するファイアウォールでは、ビルドは完了しても証明書は発行されません。再ビルド直後に ./launcher logs app で結果を確認します。
nginx または Caddy を前段に置くべきか
VPS 上で Discourse だけを Web サービスとして運用している場合は、前段に置かないでください。コンテナには調整済みの nginx がすでに含まれているため、プロキシを追加すると経由が1つ増え、更新が必要な証明書がもう1つ増え、ヘッダー関連の不具合の原因も増えます。
同じ VPS で他のサイトも提供する場合は、前段に置きます。テンプレート一覧に templates/web.socketed.template.yml を追加し、expose の2行をコメントアウトします。SSL 用の2つのテンプレートもコメントアウトしたままにします。これでコンテナは /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 は絶対 URL を記述するため、このヘッダーがないと HTTPS ページ上に http:// リンクを出力し、ブラウザーが混在コンテンツとしてブロックします。コンテナをソケット接続にした場合、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:配下を変更するとイメージ自体が変わるため、完全な再構築が必要です。
アップグレードには2つの方法があります。ポイントリリースは、app.ymlがビルド中にクローンするdocker_managerプラグインによって提供され、/admin/upgradeの Web インターフェースから適用できます。ベースイメージやテンプレートの変更は git から取得します。
cd /var/discourse
git pull
./launcher rebuild app再構築時に小規模サーバーで障害が発生しやすいのは、アセットのコンパイルがシステム全体で最もメモリを消費する処理だからです。途中で停止したビルドで、dmesgにrubyプロセスを示すOut of memory: Killed processのような行が表示された場合、ビルド中にメモリが不足しています。事前にはサイトが正常に動作していても、この問題は発生します。swap を追加して、再構築をもう一度実行してください。
./launcher logs app
./launcher enter app
./launcher cleanuplogsはコンテナの出力を表示し、enterはコンテナ内のシェルを開きます。cleanupは24時間以上停止しているコンテナを削除します。再構築のたびに古いコンテナが残り、小規模な VPS のディスク容量は気付かないうちに不足するため、定期的にcleanupを実行してください。
バックアップと、バックアップに含まれないファイル
Admin の Backups ページからバックアップを取得します。アーカイブはホスト上の /var/discourse/shared/standalone/backups/default/ に保存されます。同じ処理はシェルからも実行できます。
cd /var/discourse
./launcher enter app
discourse backupdiscourse restore <filename> で元に戻せます。ただし、discourse enable_restore を実行するまでリストアは拒否されます。この保護機能は、誤ったコマンドによって稼働中のフォーラムが上書きされるのを防ぐためのものです。
自分で補う必要がある点が2つあります。アーカイブにはデータベースが含まれます。アップロードファイルは、アップロードを含めるバックアップ設定が有効な場合にだけ含まれます。そのため、バックアップを信頼する前に、この設定を確認してください。app.yml は含まれないため、新しい VPS へのリストアではホスト名と SMTP 設定が必要です。このファイルもホストから別の場所へコピーしてください。
また、アーカイブは保護対象のサイトと同じディスク上に保存されます。これはバックアップとはいえません。スケジュールを設定し、アーカイブを別の場所へ転送してください。
rsync -avz root@forum.example.com:/var/discourse/shared/standalone/backups/default/ ~/discourse-backups/メモリ使用量に影響する活発なフォーラム
bootstrap は検出したメモリと CPU に基づいて UNICORN_WORKERS と db_shared_buffers を設定します。サンプル設定では、共有バッファの上限を総メモリの 4 分の 1 にしています。各 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 が既知の名前だからではなく、必要な機能を備えているから選択してください。
FAQ
ドメイン名なしで VPS に Discourse をインストールできますか?
いいえ。提供される設定では、Discourse は IP アドレスだけでは動作せず、DISCOURSE_HOSTNAME が必要とされています。Discourse はそのホスト名から絶対リンクを生成するため、そこに IP アドレスを指定するとリンクが壊れ、証明書も発行できません。開始前に A レコードを作成し、dig +short forum.example.com でサーバーのアドレスに解決されることを確認してください。
インストールを完了するには SMTP の設定が必要ですか?
2026 年 8 月時点では省略できます。セットアップウィザードでは代わりに Discourse ID でのログインを選択でき、app.yml にはメール設定の検証を省略するスイッチがあります。ただし、最初に試す段階を過ぎたら設定してください。アカウントの有効化とパスワードのリセットは、どちらもメールで行われるためです。ほとんどの VPS プロバイダーは送信ポート 25 をブロックするため、ポート 587 または 465 の認証付きリレーを使用してください。
Discourse の再ビルドが途中で失敗したのはなぜですか?
通常の原因はメモリ不足です。ビルド中のアセットコンパイルには、稼働中のサイトより多くのメモリが必要です。そのため、フォーラムの配信には問題がないサーバーでも、再ビルドには失敗することがあります。dmesg に ruby プロセスを示す Out of memory: Killed process が表示された場合は、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 ソケットへプロキシします。X-Forwarded-Proto を転送してください。転送しないと、Discourse は HTTPS ページ上で http:// リンクを生成します。
自己ホスト型 Discourse をバックアップするにはどうすればよいですか?
Admin の Backups ページを使用するか、./launcher enter app の後に discourse backup を実行してください。アーカイブはホスト上の /var/discourse/shared/standalone/backups/default/ に保存されます。uploads を含める設定が有効であることを確認し、/var/discourse/containers/app.yml もアーカイブと一緒にコピーしてください。両方を別のマシンへ移動します。サイトと同じディスク上にあるバックアップは、そのバックアップが必要になる障害では失われるためです。