単一のサーバー上で、Discourse の「マルチサイト」機能を使用せずに、複数のスタンドアロン Discourse インストールをホストできます(別コンテナ / 別ポート / 別 app.yml)。
マルチサイトよりも手動での設定が必要ですが、インスタンスを分離でき、後で個別のサイトを独自のサーバーに移行しやすくなります。
実用的なパターンは以下の通りです:
• 外部 Postgres(単一インスタンス)
• 外部 Redis(単一インスタンス)
• 複数の Discourse Web コンテナ
• 1 つの Sidekiq ノード
• ヘルスチェック付きリバースプロキシ
これにより、マルチサイトを完全に回避しつつ、トラフィックの少ない設定でのコスト削減が可能になります。
DISCOURSE マルチコンテナ実行マニュアル
外部 Postgres + Redis + HAProxy + app1 / app2
- ホストパッケージ
| ステップ | コマンド |
|---|---|
| システムの更新 | apt-get update |
| 基本ツールのインストール | apt-get install -y ca-certificates curl gnupg lsb-release |
| HAProxy + certbot + socat のインストール | apt-get install -y haproxy certbot socat |
- DOCKER ネットワーク(必須)
コンテナ間で名前解決を行うために、ユーザー定義の Docker ネットワークが必要です。
| ステップ | コマンド |
|---|---|
| ネットワークの作成 | docker network create discourse-net |
| 確認 | docker network ls | grep discourse-net |
これにより、以下が正しく機能します:
• DISCOURSE_DB_HOST=pg
• DISCOURSE_REDIS_HOST=redis
- 秘密鍵
| 目的 | コマンド |
|---|---|
| Postgres 超級ユーザー | export PG_SUPERPASS='REPLACE_ME_super_strong' |
| Discourse DB パスワード | export DISCOURSE_DBPASS='REPLACE_ME_discordb_strong' |
| Redis パスワード | export REDIS_PASS='REPLACE_ME_redis_strong' |
| Secret key base | export SECRET_KEY_BASE="$(openssl rand -hex 64)" |
- POSTGRES コンテナ
| ステップ | コマンド |
|---|---|
| ディレクトリの作成 | mkdir -p /var/discourse/external/postgres |
| コンテナの実行 | docker run -d --name pg --restart=always --network=discourse-net -e POSTGRES_PASSWORD="$PG_SUPERPASS" -v /var/discourse/external/postgres:/var/lib/postgresql/data postgres:15 |
| 確認 | docker ps | grep pg |
- データベースの作成
| ステップ | コマンド |
|---|---|
| ロールの作成 | docker exec -it pg psql -U postgres -c "CREATE ROLE discourse LOGIN PASSWORD '$DISCOURSE_DBPASS';" |
| DB の作成 | docker exec -it pg psql -U postgres -c "CREATE DATABASE discourse OWNER discourse ENCODING 'UTF8' TEMPLATE template0;" |
| テキスト検索の設定 | docker exec -it pg psql -U postgres -d discourse -c "ALTER DATABASE discourse SET default_text_search_config = 'pg_catalog.english';" |
| ログインテスト | docker exec -it pg psql -U discourse -d discourse -c "select 1;" |
- PGVECTOR 拡張機能
最新の Discourse バージョンに必要です。
| ステップ | コマンド |
|---|---|
| インストール | docker exec -it pg bash -lc 'apt-get update && apt-get install -y postgresql-15-pgvector && rm -rf /var/lib/apt/lists/*' |
| 拡張機能の作成 | docker exec -it pg psql -U postgres -d discourse -c "CREATE EXTENSION IF NOT EXISTS vector;" |
| 確認 | docker exec -it pg psql -U postgres -d discourse -c "SELECT extname FROM pg_extension WHERE extname='vector';" |
- REDIS コンテナ
| ステップ | コマンド |
|---|---|
| ディレクトリの作成 | mkdir -p /var/discourse/external/redis |
Redis 設定テンプレート:
requirepass REPLACE_ME_REDIS
appendonly yes
save 900 1
save 300 10
save 60 10000
| ステップ | コマンド |
|---|---|
| 設定の書き込み | tee /var/discourse/external/redis/redis.conf >/dev/null <<EOF |
| パスワードの挿入 | sed -i "s/REPLACE_ME_REDIS/$REDIS_PASS/" /var/discourse/external/redis/redis.conf |
| Redis の実行 | docker run -d --name redis --restart=always --network=discourse-net -v /var/discourse/external/redis:/data -v /var/discourse/external/redis/redis.conf:/usr/local/etc/redis/redis.conf redis:7-alpine redis-server /usr/local/etc/redis/redis.conf |
| 認証テスト | docker exec -it redis redis-cli -a "$REDIS_PASS" ping |
- DISCOURSE ディレクトリ構成
| ステップ | コマンド |
|---|---|
| ベースディレクトリの作成 | mkdir -p /var/discourse |
| 移動 | cd /var/discourse |
| リポジトリのクローン | git clone https://github.com/discourse/discourse_docker.git |
| コンテナディレクトリ | mkdir -p /var/discourse/containers |
| 共有ログ | mkdir -p /var/discourse/shared/web-only/log/var-log |
| コンテナのリンク | ln -sfn /var/discourse/containers /var/discourse/discourse_docker/containers |
| ランチャーのリンク | ln -sfn /var/discourse/discourse_docker/launcher /var/discourse/launcher |
- アプリケーションコンテナ
app1.yml
• web + sidekiq
• ポート 8001
docker_args: "--network=discourse-net"
expose:
- "8001:80"
app2.yml
• web のみ
• ポート 8002
• sidekiq 無効
docker_args: "--network=discourse-net"
expose:
- "8002:80"
run:
- exec: bash -lc 'mkdir -p /etc/service/sidekiq && touch /etc/service/sidekiq/down'
- ブートストラップ
| ステップ | コマンド |
|---|---|
| 移動 | cd /var/discourse/discourse_docker |
| app1 のブートストラップ | ./launcher bootstrap app1 |
| app1 の起動 | ./launcher start app1 |
| app2 のブートストラップ | ./launcher bootstrap app2 |
| app2 の起動 | ./launcher start app2 |
- ヘルスチェック
| ステップ | コマンド |
|---|---|
| app1 | curl -sSf http://127.0.0.1:8001/srv/status |
| app2 | curl -sSf http://127.0.0.1:8002/srv/status |
| sidekiq app1 | docker exec -it app1 pgrep -fa sidekiq |
| sidekiq app2 | `docker exec -it app2 pgrep -fa sidekiq |
- TLS 証明書
| ステップ | コマンド |
|---|---|
| プロキシの停止 | systemctl stop haproxy |
| 証明書の発行 | certbot certonly --standalone -d example.com --agree-tos -m you@example.com --non-interactive |
| プロキシの起動 | systemctl start haproxy |
- HAPROXY ロジック
frontend fe_discourse
bind :80
bind :443 ssl crt /etc/letsencrypt/live/example.com/haproxy.pem
http-request set-header X-Forwarded-Proto https if { ssl_fc }
http-request set-header X-Forwarded-Proto http if !{ ssl_fc }
redirect scheme https code 301 if !{ ssl_fc }
use_backend be_discourse if { nbsrv(be_discourse) gt 0 }
default_backend be_maint
backend be_discourse
balance roundrobin
option httpchk GET /srv/status
server app1 127.0.0.1:8001 check
server app2 127.0.0.1:8002 check
backend be_maint
http-request return status 503 content-type text/html string "<h1>Maintenance</h1>"
- ダウンタイムゼロの再構築
| ステップ | コマンド |
|---|---|
| app1 の無効化 | echo "disable server be_discourse/app1" | socat stdio /run/haproxy/admin.sock |
| app1 の再構築 | ./launcher rebuild app1 |
| app1 の有効化 | echo "enable server be_discourse/app1" | socat stdio /run/haproxy/admin.sock |
| ステップ | コマンド |
|---|---|
| app2 の無効化 | echo "disable server be_discourse/app2" | socat stdio /run/haproxy/admin.sock |
| app2 の再構築 | ./launcher rebuild app2 |
| app2 の有効化 | echo "enable server be_discourse/app2" | socat stdio /run/haproxy/admin.sock |
終了
Docker ネットワークが必要
外部 Postgres および Redis
pgvector のインストール済み
Sidekiq は app1 のみに分離
HAProxy のヘルスチェック有効
メンテナンスフォールバック有効
ローリング再構築対応
後で 1 つのサイトを独自のサーバーに移行する
マルチサイトの代わりに完全にスタンドアロンの Discourse インストールを実行する利点の 1 つは、移行が簡単でリスクが低いことです。
各 Discourse インスタンスは既に以下を持っています:
• 独自のコンテナ
• 独自のアップロード
• 独自のデータベース
• 独自の Redis 使用
• 独自の app.yml
マルチサイトの分離は不要です。
高レベルの移行ステップ
- 新しい VPS のプロビジョニング
新しいサーバーで Docker と Discourse を通常通りインストールします。
マルチサイトは設定しないでください。
- 完全バックアップの作成
ソースサイトから:
管理者 → バックアップ → バックアップの作成
バックアップファイルをダウンロードします。
これには以下が含まれます:
• データベース
• アップロード
• ユーザー
• 設定
• テーマ
- 新しいサーバーでの復元
新しいサーバーで:
• 初期設定を完了
• 管理者としてログイン
• バックアップをアップロード
• 復元
Discourse はスキーマの互換性を自動的に処理します。
- DNS の切り替え
ドメインの A レコードを新しいサーバーの IP に更新します。
DNS が伝播すると、ユーザーは透過的に移動します。
- 古いコンテナの廃止
元のサーバーで:
• 古いコンテナを停止
• 確信が得られたら削除
同じホスト上の他の Discourse インストールには影響しません。
なぜこれがマルチサイトより簡単なのか
マルチサイト設定では、移行には通常以下が必要です:
• データベースの分離
• サイト固有データの抽出
• multisite.yml の調整
• Sidekiq の再構築
• アップロードとメールの設定変更
スタンドアロンインストールでは、これらは不要です。
各サイトは既に独立しています。
まとめ
このアプローチは、初期の運用複雑さを少し増やす代わりに、後の非常に簡単な分離を実現します。
実験中や初期段階のコミュニティ構築において特に効果的です。
このアプローチが適していない場合
以下の場合は、この設定は通常推奨されません:
• サイトが早期に中規模または高トラフィックを想定している場合
• 公式 Discourse サポートに大きく依存している場合
• Docker、ネットワーク、リバースプロキシのデバッグに不慣れな場合
• 稼働時間の要件が厳格またはビジネスクリティカルな場合
• 複数のサイトが運用面で密接に結合している場合
• 全インスタンスで頻繁にプラグインの実験を予定している場合
これらの場合は、以下のいずれかが通常、運用上の驚きを減らします:
• サポートされたマルチサイト設定
または
• サーバーごとに 1 つの Discourse インストール
重要な注意点
このアプローチはインフラストラクチャの柔軟性を高めますが、同時に管理者の責任も増大します。
これは、フルスタックを所有することに慣れ、偶尔の故障を学習プロセスの一部として扱うことができる人が実行する場合に最も効果的です。
安定性とサポート可能性が主要な目標である場合、サポートされる構成がほぼ常に優れた選択です。