SSD Nodes Learn 🎉 VPS $5.50/月〜
ガイド Matt Connor著者 Matt Connor ・更新日 2026-08-13

VPSにDockerでDiscourseをインストールする方法

公式Dockerランチャーで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 シェルスクリプトと、複数の YAML テンプレートを使用します。Discourse は、自分で作成した Compose ファイルをサポートしていません。また、コンテナを手動で分割して運用する構成も想定していません。Docker Compose で VPS 上のサービスを実行することに慣れている場合は、構成が異なる点に注意してください。ここには 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 を意図的に配置する場合を除きます。
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
  }
]

公式のインストール文書では、必要な最小構成を、swap 付きの 1 GB の RAM と 10 GB のディスクとしています。また、swap 付きの 2 GB の RAM と 20 GB のディスクを推奨しています。最初の行は、コミュニティを運用したい容量ではなく、インストーラーを完了させるための容量として読んでください。ビルド時にメモリ使用量が最大になるため、この差が重要です。

インストール前にドメインをサーバーへ向ける

使用するホスト名の A レコードを作成し、サーバー自体から名前解決を確認します。

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

2 つのコマンドは同じアドレスを出力する必要があります。セットアップウィザードはホスト名に対して接続テストを実行するため、別の場所を指すレコードではテストに失敗します。2 分前に作成したレコードもキャッシュに残っている場合があります。そのため、ウィザードを無理に進めず、古い TTL (time to live) が切れるまで待ちます。

レコードを CDN 経由にするかどうかも、ここで決めます。プロキシ経由のレコードではサーバーのアドレスが隠されます。その場合、コンテナの証明書要求は失敗します。ACME (automatic certificate management environment) チャレンジへの応答を Discourse ではなくプロキシが返すためです。最初のインストールでは、レコードをプロキシ経由にしないでください。

公式インストーラーを実行する

1 つのコマンドで 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 は薄いラッパーです。ホストネットワークを使用し、Docker ソケットをマウントしたコンテナとして discourse/setup-wizard:release を実行します。そのため、ウィザードは設定対象のマシンを調査できます。最初にホスト名と管理者のメールアドレスを確認し、続いて SMTP の設定を確認します。その後、containers/app.yml を書き込み、再ビルドします。

開始前に知っておくべき動作が 2 つあります。マシンのメモリが不足し、swap もない場合、ウィザードは停止して swap の作成を提案します。その後、ラッパーは 2 GB の /swapfile を作成し、/etc/fstab に追加し、/etc/sysctl.d/30-discourse-swap.confvm.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 を利用してください。465 の場合は DISCOURSE_SMTP_FORCE_TLS: true を設定します。サンプル設定でも、この port にはその設定が推奨されています。再構築する前に、ホストから接続できることをテストしてください。

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 challenge への応答にポート 80 が使われるためです。443 のみを許可するファイアウォールでは、ビルドは完了しても証明書は発行されません。再ビルドの直後に ./launcher logs app で結果を確認します。

nginx または Caddy を前段に置くべきですか?

VPS 上で Discourse だけを Web サービスとして運用する場合は、前段に置かないでください。コンテナには調整済みの nginx がすでに組み込まれています。別のプロキシを追加すると、ホップが増え、更新が必要な証明書がもう 1 つ増え、ヘッダーの不具合が新たに発生する可能性があります。

同じ VPS で他のサイトも提供する場合は、前段にプロキシを置きます。テンプレート一覧に templates/web.socketed.template.yml を追加し、expose の 2 行をコメントアウトします。2 つの 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 は絶対 URL を生成するため、このヘッダーがないと 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: 配下を変更するとイメージ自体が変わるため、完全な再構築が必要です。

アップグレードには2つの方法があります。ポイントリリースは、app.yml がビルド中にクローンする docker_manager プラグインによって提供される、/admin/upgrade の Web インターフェースから適用します。ベースイメージやテンプレートの変更は git から取得します。

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

小規模サーバーでは、再構築時に障害が発生しやすくなります。アセットのコンパイルがシステム全体のメモリ使用量のピークになるためです。ビルドが途中で停止し、dmesgruby プロセスを示す Out of memory: Killed process のような行が表示された場合、サイト自体はそれまで正常に動作していても、ビルド中にメモリ不足が発生しています。swap を追加して、再度再構築してください。

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

logs はコンテナの出力を表示し、enter はコンテナ内でシェルを起動し、cleanup は24時間を超えて停止しているコンテナを削除します。cleanup は定期的に実行してください。再構築のたびに古いコンテナが残り、小規模な VPS のディスク容量は気付かないうちに不足するためです。

バックアップと、バックアップに含まれないファイル

Admin の Backups ページからバックアップを取得します。アーカイブはホスト上の /var/discourse/shared/standalone/backups/default/ に保存されます。同じ処理はシェルからも実行できます。

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

discourse restore <filename> で復元します。ただし、discourse enable_restore を実行するまで復元は拒否されます。この保護機構により、誤ったコマンドで稼働中のフォーラムを上書きすることを防ぎます。

自分で補う必要がある点が 2 つあります。アーカイブにはデータベースが含まれます。アップロードファイルは、アップロードを含めるバックアップ設定が有効な場合に限り含まれます。そのため、バックアップを信頼する前にこの設定を確認してください。app.yml は含まれないため、新しい VPS への復元にはホスト名と SMTP ブロックが必要です。つまり、そのファイルもホストから別の場所へコピーしておく必要があります。

また、アーカイブは保護対象のサイトと同じディスク上に保存されます。これはバックアップとはいえません。スケジュールを設定し、別の場所へ転送してください。

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

メモリを消費する活発なフォーラム

ブートストラップは検出したメモリと CPU に基づいて UNICORN_WORKERSdb_shared_buffers を設定し、サンプル設定では共有バッファーを総メモリの 4 分の 1 に制限しています。各 unicorn worker は独立した Ruby プロセスであり、Sidekiq はそれらと並行してバックグラウンドジョブを実行します。そのため、メモリ使用量は登録メンバー数ではなく、同時実行されるリクエスト数に応じて変化します。数百人のメンバーしかいない静かなフォーラムは、大きな負荷にはなりません。

この記事を含め、記事に書かれた数値だけを基準にサーバーのサイズを決めないでください。自分の環境を測定してください。

free -m
docker stats --no-stream

Swap が常時使用され、ページの表示も遅い場合は、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 が表示される場合は、スワップを追加してください。ウィザードが作成する 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 をバックアップするにはどうすればよいですか?

Admin の Backups ページを使用するか、./launcher enter app の後に discourse backup を実行します。アーカイブはホスト上の /var/discourse/shared/standalone/backups/default/ に保存されます。uploads を含める設定が有効であることを確認し、/var/discourse/containers/app.yml もアーカイブと一緒にコピーしてください。両方を別のマシンへ移します。サイトと同じディスク上にあるバックアップは、バックアップが必要になった障害から保護できないためです。