---
title: "Docker Compose による Quire のインストール"
description: "自分のインフラに Docker Compose で Quire をインストールします。"
image: "https://docs.quirelms.com/og.png"
---

> Documentation Index
> Fetch the complete documentation index at: https://docs.quirelms.com/ja/llms.txt
> Use this file to discover all available pages before exploring further.

# Docker Compose による Quire のインストール

<span id="installing-quire-with-docker-compose"></span>

これは 1 台のホストで LMS、バックグラウンド処理、リアルタイムサービス、共同編集、プロファイルで有効化する各種サービスを動かす完全な製品です。設計は `docs/architecture/23-ops.md` のセクション 2 を参照してください。

その他の構成: [Vercel](/ja/ops/vercel/) と [Cloudflare Workers](/ja/ops/cloudflare/) では Web 層だけを動かします。アップグレードは [upgrade.md](/ja/ops/upgrade/)、バックアップと復元ドリルは [backup-restore.md](/ja/ops/backup-restore/) を参照してください。

## 必要なもの <!--quire:what-you-need-->

- Compose プラグイン 2.30 以降を含む Docker Engine 27 以降。
- 既定のスタックには CPU 4 コアとメモリー 8 GB。`--profile full` では 8 コア、16 GB (ClamAV だけで約 1.5 GB の署名データを保持します)。
- Web 層用 DNS 名と、信頼できないコンテンツ用の別の DNS 名。ホスト名を分けてください。SCORM パッケージとアップロードした HTML はコンテンツオリジンで実行し、LMS の Cookie を読めないようにします。
- ローカルテストでは `lvh.me` と `*.localhost` が 127.0.0.1 に解決されます。これは `docker/.env.example` が使う設定です。スタックの `proxy` サービスがローカル認証局を使って両方に https を提供するため、追加ソフトウェアは不要です (「TLS」を参照)。
- ホストでポート 80 と 443 が空いていること (`QUIRE_PROXY_HTTP_PORT`、`QUIRE_PROXY_HTTPS_PORT` で変更できます)。

## 初回起動 <!--quire:first-run-->

```sh
QUIRE_APP_ORIGIN=https://learn.example.org \
QUIRE_CONTENT_ORIGIN=https://content.example-content.org \
QUIRE_SETUP_ADMIN_EMAIL=you@example.org \
  docker/scripts/init-env.sh
docker compose -f docker/compose.yaml up -d --build
docker compose -f docker/compose.yaml logs init
```

`docker/scripts/init-env.sh` は `docker/.env` を `docker/.env.example` から を作成し、データベースのパスワード、署名鍵とマスターキー、コンテンツ起動用鍵ペアなどのシークレットを生成します。また、監査チェックポイント署名鍵を `docker/secrets/audit-signing-key.pem` に作成します。Compose はこれをシークレットとして worker にマウントします。必要なのは `sh`、`awk`、`openssl` だけです。既存の `docker/.env` は上書きしません。両方のファイルをホスト外にコピーしてください。`QUIRE_MASTER_KEY` がないと、復元した DB 内の保存済み認証情報を復号できません。手動でファイルを作る場合は `cp docker/.env.example docker/.env` を実行し、ファイル内の説明に従って各シークレットを生成します。

両方のオリジンは `https` を使い、登録可能ドメインも異なる必要があります。本番環境ではコンテンツサービスが平文 http を拒否します。`proxy` サービスが両方の TLS を終端します (「TLS」を参照)。`init-env.sh` は `http://` のオリジンを拒否します。

スタックは決められた順番で起動し、各段階で前の段階を待ちます。

1. `postgres` が正常状態になります。初回起動時に init スクリプト (`docker/postgres/init/90-passwords.sh`) が 4 つのロールのパスワードを設定します。
2. `migrate` がすべてのマイグレーションを適用し、制御 DB と専用テナント DB すべてにジョブキューを初期設定して、一致を確認した後に終了します (docs/ops/upgrade.md)。起動のたびにマイグレーションが動き、冪等です。アップグレードでは新しいイメージを使い、再起動します。
3. `init` (`apps/web/src/first-run.ts`) が `QUIRE_DATABASE_ID` のアプリケーション DB を記録します。`QUIRE_SETUP_ADMIN_EMAIL` を設定した場合、最初の組織と管理者を作成します。サインインアドレスと生成したパスワードは `docker compose logs init` に一度だけ表示されます。
4. `web`、`content`、`worker`、`scheduler`、`collab`、`centrifugo` が起動します。
5. `proxy` は `web` と `content` が正常状態になってから起動します。

`https://demo.` にアプリケーションドメインを続けたアドレスを開き、サインインします (`init` ログに正確なアドレスが表示されます)。ローカル環境では最初に proxy の認証局を信頼してください (「TLS」を参照)。生成したパスワードは `/account/security` で変更します。

必須シークレットがないプロセスは起動を拒否し、ログに不足している設定名を表示します。不完全な状態で起動することはありません。

## サービスとプロファイル <!--quire:services-and-profiles-->

| サービス | プロファイル | 役割 |
| --- | --- | --- |
| postgres | 常時 | データベース (PostgreSQL 18、pgvector 入り。`docker/postgres.Dockerfile` で構築)。初回起動から WAL をアーカイブ |
| migrate、init | 常時 | 1 回実行: マイグレーション、次に初回設定 |
| web | 常時 | LMS。`QUIRE_HTTP_PORT` (8080) で待ち受け |
| content | 常時 | 信頼されないコンテンツのオリジン。`QUIRE_CONTENT_PORT` (8081) で待ち受け |
| worker | 常時 | メール、レポート、ファイル処理、webhook などのバックグラウンドジョブ |
| scheduler | 常時 | 64 個の実行時スケジュールを登録して worker へ渡す。リーダーは常に 1 つ |
| collab | 常時 | 共同編集 websocket。`QUIRE_COLLAB_HTTP_PORT` (1234) で待ち受け |
| centrifugo | 常時 | リアルタイム配信。`QUIRE_REALTIME_PORT` (8000) で待ち受け |
| proxy | 常時 | Caddy。ポート 80 と 443 の TLS 入口 (「TLS」を参照) |
| valkey | `cache` | キャッシュとレート制限 |
| clamav | `scan` | アップロードのマルウェアスキャン |
| gotenberg | `preview` | Office 文書の PDF プレビューと証明書の描画 |
| imgproxy | `images` | 画像サイズの変更と形式変換 |
| transcoder | `video` | LGPL の ffmpeg だけを含む worker イメージ。動画バージョンを生成 |
| seaweedfs | `storage` | このホスト上の S3 互換オブジェクトストレージ |
| otelcol | `observability` | OpenTelemetry コレクター |
| mailpit | `devmail` | 動作確認用に送信メールをすべて受信 |
| backup | `backup` | 1 回実行のベースバックアップ。を参照 |
| backup-scheduler、backup-offsite | `backup` | `QUIRE_BACKUP_INTERVAL_HOURS` ごとにベースバックアップを作成し、暗号化したホスト外コピーと週次検証ドリルを実行 |
| h5p | `h5p` | 用意した `QUIRE_H5P_IMAGE` の H5P LTI 1.3 ツールイメージ。`QUIRE_H5P_PORT` (8090) で待ち受け。「H5P プロバイダーの接続」を参照 |

`--profile full` は `backup` と `h5p` 以外のすべての任意サービスを起動します。個別サービスは `docker compose -f docker/compose.yaml --profile scan up -d` のように起動します。任意サービスがなくても Quire は動きますが、不足内容を知らせます。スキャナーがないとアップロードはスキャンなしで保存され、管理者に通知されます。Gotenberg がないとプレビューの代わりにダウンロードを提供します。トランスコーダーがないと動画は元ファイルのまま再生されます。

サードパーティの各イメージとライセンス上の義務は `docker/third-party-containers.yaml` に記載されています。

### H5P プロバイダーの接続 <!--quire:connecting-an-h5p-provider-->

Quire は H5P の実行環境やサイドカーを埋め込み・同梱しません (ADR 0019)。H5P を使う場合は、Quire と別にホスト型サブスクリプションを用意するか、セルフホストの H5P インスタンスを運用してください。そのプロバイダーを LTI 1.3 外部ツールとして登録し、コースにツールアクティビティとしてコンテンツを追加します。Quire は LTI Assignment and Grade Services (AGS) 経由で成績とアクティビティ・採点の進捗を交換します。プロバイダーが xAPI ステートメントも送信する場合は、Quire の xAPI ステートメントストア向けに別途設定してください。AGS の成績・進捗交換は xAPI ステートメントを送りません。Moodle からのインポートでは H5P アクティビティに LTI ツール接続が必要と表示されます。H5P 実行環境、作成機能、コンテンツバンク、受験履歴の管理はプロバイダー側です。

同じホストでセルフホストのインスタンスを動かすには、`QUIRE_H5P_IMAGE` にそのイメージを設定して `h5p` プロファイルを起動します。Compose は `QUIRE_H5P_PORT` (8090) で公開し、`h5p-data` ボリュームにデータを保存します。イメージとそれに伴う義務は利用者側のものです。

## 設定 <!--quire:settings-->

すべてのプロセスは `docker/.env` を読み込みます。設定の既定値はテンプレート `docker/.env.example` に記載されています。設定は次のグループに分かれます。

### アドレス <!--quire:addresses-->

| 設定 | 意味 |
| --- | --- |
| `QUIRE_APP_ORIGIN` | LMS の公開アドレス。例: `https://learn.example.com` |
| `QUIRE_CONTENT_ORIGIN` | 別のホストにあるコンテンツオリジン |
| `QUIRE_PLATFORM_DOMAINS` | 組織が属するドメイン。コンマ区切り |
| `QUIRE_MARKETING_ORIGIN` | Optional. The marketing site, default `https://quirelms.com`. The only origin the waitlist form (`POST /api/waitlist`, `POST /waitlist`) accepts and redirects to. Comma separated; a `www.` variant is allowed only if listed |
| `QUIRE_DEPLOY_TARGET` | この環境では `compose`。`vercel` と `cloudflare` は各ガイドを参照 |
| `QUIRE_TRUSTED_PROXY_CIDRS` | `X-Forwarded-For` を信頼するプロキシ |

### シークレット <!--quire:secrets-->

| 設定 | 意味 |
| --- | --- |
| `QUIRE_SECRET_KEY` | セッションとトークンに署名。16 進数 64 文字 |
| `QUIRE_MASTER_KEY` | SSO や webhook のシークレットなど、保存済み認証情報をラップ。32 バイト、base64。Web 層と worker で同じ値が必要。ローテーションは [key-rotation.md](/ja/ops/key-rotation/) を参照 |
| `QUIRE_MASTER_KEY_VERSION` | マスターキーのバージョンラベル。未設定時は `v1`。ローテーション時に更新 |
| `QUIRE_MASTER_KEY_RETIRED` | 暗号化済みデータを読むために必要な旧マスターキー。`v1=<base64>` 形式。未解決なしでローテーションが終わったら削除 |
| `QUIRE_COLLAB_SIGNING_KEY` | Web と collab で共有し、編集トークンに署名 |
| `QUIRE_BACKUP_SIGNING_KEY` | コースバックアップに署名 (任意) |

`QUIRE_MASTER_KEY` のコピーをホスト外に保管します。鍵なしで復元した DB は、保存済み認証情報を復号できません。

### データベース <!--quire:database-->

| 設定 | 意味 |
| --- | --- |
| `POSTGRES_PASSWORD` | コンテナとバックアップが使う superuser |
| `QUIRE_DB_APP_PASSWORD`、`QUIRE_DB_MIGRATOR_PASSWORD`、`QUIRE_DB_REPORT_PASSWORD`、`QUIRE_DB_AUDIT_PASSWORD` | 初回起動時に設定する各ロールのパスワード |
| `DATABASE_URL` | アプリケーションロール。各クエリに行レベルセキュリティが適用されます |
| `DATABASE_MIGRATOR_URL`、`QUIRE_MIGRATION_URL` | `migrate` と `init` が使う migrator ロール |
| `QUIRE_SUPERUSER_URL` | 初回起動時のみ使用 |
| `QUIRE_REPORT_DATABASE_URL` | レポートとレポートビルダー用の読み取り専用ロール |
| `QUIRE_AUDIT_DATABASE_URL` | 監査コンソールと SIEM エクスポート用の監査ロール |
| `QUIRE_DATABASE_ID` | 任意の UUID。インストール中は固定 |

ロールのパスワードを設定するのは、最初にデータベースボリュームを作るときだけです。後で変更するには `ALTER ROLE` を使い、対応する URL も更新してください。

`QUIRE_REPORT_DATABASE_URL` は `DATABASE_URL` が示す物理 DB で使われます。他の登録済み物理 DB では、その DB 専用の `quire_report` 接続 URL を Web と worker の環境に設定し、変数名を DB の **Reporting environment variable** 欄に `env:NAME` として登録します。参照先はアプリ接続先と同じ DB (できれば読み取りレプリカ) である必要があります。レポートビルダー、保存済みレポート、定期配信、エクスポート、分析、監査ログ、REST 監査リソース、アシスタントの監査検索を含むレポート機能は、そのテナント専用のレポート接続を使います。別 DB の URL を借りることはありません。レポート接続のない DB では通常のレポートは独自のアプリケーション接続で実行されますが、アプリケーションロールでは監査記録を読めないため、分析と監査の読み取りは拒否されます。

### ドライバー <!--quire:drivers-->

| 設定 | このリリースの値 | 注記 |
| --- | --- | --- |
| `QUIRE_STORAGE_DRIVER` | `local` (既定)、`s3`、`azure` | `local` はファイルを `files` ボリュームに保存します。`s3` は AWS S3、R2、GCS との相互運用、他の S3 互換ストアに対応し、再開可能なマルチパートアップロードを使います |
| `QUIRE_REALTIME_DRIVER` | `inprocess` (既定)、`sse`、`centrifugo`、`durable_objects` | Web コンテナが 1 つなら `inprocess`。複数なら `centrifugo` または `sse` を使います |
| `QUIRE_CACHE_DRIVER` | `memory` (既定)、`postgres`、`valkey` | `memory` はプロセスごとです。複数コンテナ間で上限を維持するには `valkey` または `postgres` を使います |
| `QUIRE_VIDEO_DRIVER` | `ffmpeg` (既定)、`progressive_mp4` | Cloudflare Stream、Mux、Bunny のホスト型プロバイダーも鍵で設定できます |
| `QUIRE_IMAGE_DRIVER` | `noop` (既定)、`imgproxy`、`cloudflare` | `noop` は元サイズで画像を配信します。`imgproxy` には `images` プロファイルと下記設定が必要です。`cloudflare` は Cloudflare Images を使います |
| `QUIRE_MEETING_PROVIDER` | `bbb`、`zoom`、`teams`、`meet`、`jitsi`、`in_process` | ライブセッション向けのプラットフォーム既定プロバイダーです。未設定では組織が Integrations、Live session provider で独自アカウントを接続するまで、ライブセッションは未設定と表示されます。組織独自のアカウントが常にこの値より優先されます。各プロバイダーの設定 (`BBB_URL` と `BBB_SECRET`、`ZOOM_*`、`TEAMS_*`、`GOOGLE_MEET_*`、`JITSI_*`) は、ここで指定したプロバイダーのものだけ読み込みます |
| `QUIRE_MEETING_REGIONS` | `eu`、`uk`、`us` のコンマ区切り | プラットフォーム既定プロバイダーが会議を処理するリージョンです。未設定の場合、リージョンに固定された組織との照合は行いません。組織独自アカウントでは設定ページにリージョンを記載します |

このリリースで提供されないドライバー値は、既定値に黙って置き換えず、Web 層の起動時に設定名を示して拒否します。

### 画像 <!--quire:images-->

ページは `/api/files/{id}/image/{size}` 経由で 4 種類の固定サイズの画像を要求します。ファイルと同じアクセス権を確認してから画像サービスへリダイレクトします。各組織は 1 時間あたり `QUIRE_IMAGE_SPECS_PER_HOUR` (既定値 2000) 組まで新しい画像とサイズを要求できます。その時間内に生成済みのサイズは数えません。Web コンテナが複数ある場合、複数の Web コンテナでは上限を維持するため `valkey` または `postgres` を `QUIRE_CACHE_DRIVER` に設定します。

| 設定 | ドライバー | 注記 |
| --- | --- | --- |
| `IMGPROXY_URL` | `imgproxy` | ブラウザーからアクセスできる imgproxy のアドレス。例: `https://images.example.org`。プロファイル `images` は `QUIRE_IMAGES_PORT` (8082) に公開します |
| `IMGPROXY_KEY`、`IMGPROXY_SALT` | `imgproxy` | imgproxy の起動時と同じ 16 進数文字列。各値を `openssl rand -hex 32` で生成します。Quire がすべての画像 URL に署名するため、Quire が要求していない画像を imgproxy が描画することはありません |
| `QUIRE_IMAGE_SOURCE_ORIGIN` | ローカルストレージでの `imgproxy` | imgproxy が元画像を取得する場所。Compose は `http://web:3000` を設定します。`s3` や `azure` のストレージではバケットから取得するため使いません |
| `CLOUDFLARE_ACCOUNT_ID`、`CLOUDFLARE_IMAGES_TOKEN`、`CLOUDFLARE_IMAGES_ACCOUNT_HASH` | `cloudflare` | Images の編集権限を持つ API token と、Images の Developer resources にある account hash。アカウントの flexible variants を有効にします |
| `CLOUDFLARE_IMAGES_SIGNING_KEY` | `cloudflare` | 任意。設定すると画像は非公開になり、各 URL に署名と有効期限が付きます。未設定の場合、画像は公開され、`QUIRE_SECRET_KEY` から派生した推測できない URL を使います |

Cloudflare Images は配信した元画像のコピーを保持します。ファイルが削除されると worker が元ファイルより先にコピーを削除します。

### キュー <!--quire:queue-->

バックグラウンドジョブは同じ Postgres にある pg-boss を使うため、キューサービスの起動や設定は不要です。ジョブは原因となった変更と同じトランザクション内で登録されるので、クラッシュで消失したり二重送信されたりしません。この環境での `QUIRE_QUEUE_DRIVER` の既定値は `pgboss` です。`vercel` と `cloudflare` は軽量な通知と webhook 配信だけを各プラットフォームのキューに移します。登録方法は Vercel と Cloudflare のガイドを参照してください。

### メール <!--quire:email-->

次のどちらかを設定します。

- `QUIRE_EMAIL_PROVIDER_CONFIG`: HTTP プロバイダーと認証情報を指定する JSON オブジェクト。例: `{"provider":"postmark","token":"..."}`。Postmark、Amazon SES、Mailgun、SendGrid、Resend に対応します。
- `QUIRE_SMTP_URL`: `smtp://user:password@host:587`。この構成だけで使えます。サーバーレス環境では SMTP をブロックします。

`QUIRE_MAIL_FROM` は送信者です。動作確認では `devmail` プロファイルを起動し、`QUIRE_SMTP_URL=smtp://mailpit:1025` に設定して `http://localhost:8025` でメールを確認します。

### 任意のサービス <!--quire:optional-services-->

| 設定 | プロファイル |
| --- | --- |
| `CLAMAV_URL=tcp://clamav:3310` | `scan` |
| `GOTENBERG_URL=http://gotenberg:3000` | `preview` |
| `IMGPROXY_KEY`、`IMGPROXY_SALT` | `images` |
| `VALKEY_URL=redis://valkey:6379` | `cache` |
| `QUIRE_OPENSEARCH_URL` または `QUIRE_MEILISEARCH_URL` | 外部検索。未設定なら Postgres 全文検索 |
| `QUIRE_BREACH_CHECK_PROVIDER=off`、`QUIRE_BREACH_CHECK_URL` | パスワード漏えい検査。既定では `api.pwnedpasswords.com` に対して有効 (ハッシュ先頭 5 文字だけ送信)。`off` で無効化し、URL には自分でホストする range API を指定 |

### 可観測性 <!--quire:observability-->

`OTEL_EXPORTER_OTLP_ENDPOINT` に各プロセスがトレースとメトリクスを送るコレクターを指定します。`observability` プロファイルでは `http://otelcol:4318` です。バックエンドへの exporter は `docker/otel-collector.yaml` に追加します。Web 層、worker、scheduler、content、collab は、この設定があれば OTLP/HTTP でスパン (Web リクエスト、テナント DB トランザクション、worker ジョブ、外部への呼び出し) と毎分のメトリクスを同じエンドポイントへ送信します。`OTEL_METRICS_EXPORTER=none` でメトリクスを無効にできます。`OTEL_TRACES_SAMPLER_ARG` は保持するトレースの割合です。ログは `LOG_LEVEL` に従って標準出力へ書き、Compose がローテーションします。トレースには個人データが入りません。

### EU データ所在地のリージョン別送信先 <!--quire:regional-egress-eu-data-residency-->

`QUIRE_REGION=eu` は EU 組織をこのスタックで提供することを示します。worker は EU に固定された組織から外部へ送る各リクエストを許可リストで制限します (21-compliance.md セクション 8.1)。許可リストには設定済みサービスがリージョン用に申告するホスト (ストレージエンドポイント、メール、ホスト型動画、組織独自のストレージ、AI プロバイダー、メールアカウント)、有効な例外対象サービスのホスト、`QUIRE_EGRESS_ALLOW_HOSTS` に記載したホストが含まれます。他の公開ホストへのリクエストは送信前に拒否され、拒否内容は組織の監査ログに `privacy/egress_refused` と記録され、Compliance、Data residency に表示されます。

| 設定 | 値 | 効果 |
| --- | --- | --- |
| `QUIRE_EGRESS_ALLOW_HOSTS` | ホスト名のコンマ区切り、または全サブドメイン用の `*.example.org` | EU 組織が追加で接続できるホスト。Webhook、xAPI、SIEM エンドポイント、ブログフィード、Amazon SES は組織が選ぶものでありサービス側の宣言がないため、ここに記載します。ループバック、プライベートアドレス、`web` や `clamav` のような単一ラベル名は自分のネットワークなので検査されません |

英国と米国の組織にはホスト一覧の制限を適用せず、サービスのリージョン確認を使います。リストは worker に設定します。管理画面は Web 層で読み込んで許可リストを表示するため、すべてのサービスが読む `docker/.env` に設定してください。

アプリケーションの確認は明確なエラーと監査エントリーを残しますが、それだけでは保証になりません。コードは誤る可能性があります。保証するのはネットワークです。Compose はネットワーク制限を自動で設定しません。リージョン用スタックでは `worker` と `web` を `internal: true` ネットワークに置き、唯一の外向き経路を egress proxy (Squid や tinyproxy コンテナなど) に限定します。プロキシは `QUIRE_EGRESS_ALLOW_HOSTS` と設定済みサービスのホストだけを許可し、各サービスの `HTTPS_PROXY` を設定します。レジデンシーページにアプリケーションの許可ホスト一覧が表示されるため、ネットワーク側と照合できます。

## ヘルス <!--quire:health-->

| エンドポイント | 意味 |
| --- | --- |
| `/healthz` | 生存確認: プロセスが応答します。Compose のヘルスチェックが使います |
| `/readyz` | 準備状態: 依存サービスへ接続でき、任意サービスごとに設定済みかどうかを報告します。ロードバランサーはこちらを確認します |

`docker compose -f docker/compose.yaml ps` で各サービスの状態を確認します。

## TLS <!--quire:tls-->

`proxy` サービス (Caddy、Apache-2.0、`docker/caddy/Caddyfile`) は既定スタックに含まれ、ポート 80 と 443 で応答して次のようにルーティングします。

| ホストまたはパス | 転送先 |
| --- | --- |
| `QUIRE_PROXY_CONTENT_HOST` | `content` |
| `QUIRE_PROXY_APP_HOST`、すべてのテナントサブドメインとカスタムドメイン | `web` |
| それらのホストの `/_collab/` | `collab` (websocket、`QUIRE_COLLAB_URL`) |
| それらのホストの `/_realtime/connection/` | `centrifugo` のクライアント websocket。サーバー API は公開されません |
| それらのホストの `/_images/` | `imgproxy`、`images` プロファイル (`IMGPROXY_URL`) |

`init-env.sh` は 2 つのオリジンから `QUIRE_PROXY_APP_HOST`、`QUIRE_PROXY_CONTENT_HOST`、`QUIRE_PROXY_HTTPS_PORT`、`QUIRE_COLLAB_URL`、`IMGPROXY_URL` を導出し、設定の不整合を防ぎます。オリジンを手動変更する場合は、関連値を一緒に変更してください。

証明書は `QUIRE_PROXY_TLS` で選びます。

- `internal` (既定): `localhost`、`*.localhost`、`lvh.me` 向けの Caddy 独自認証局です。ルート証明書を一度信頼設定に追加してから、次のように取得します。

  ```sh
  docker compose -f docker/compose.yaml cp \
    proxy:/data/caddy/pki/authorities/local/root.crt ./quire-local-ca.crt
  ```

  `quire-local-ca.crt` を OS またはブラウザーの信頼ストアに追加します。`curl` では `--cacert` を指定します。
- メールアドレス: 実ホスト名用 ACME 証明書を自動発行します (Let's Encrypt、次に ZeroSSL)。両オリジンとすべてのテナントホストの DNS をこのホストへ向け、ポート 80 と 443 をインターネットから到達可能にしてください。

テナント用ホストの証明書は初回アクセス時に必要に応じて発行します。ただし、Web が Compose ネットワーク経由の `/tls-allowed` で、その名前がこのインストールに属することを確認した場合だけです。ワイルドカード証明書や DNS プロバイダープラグインは不要で、無関係な人が自分のドメインをホストへ向けても証明書を要求できません。証明書とローカル認証局は `caddy-data` ボリュームに保存されます。`internal` を使う場合は他のデータと一緒にバックアップしてください。

Web は proxy からの `X-Forwarded-For` だけを信頼します。proxy は固定アドレス (`QUIRE_PROXY_ADDRESS`、既定値 `172.29.64.10`) を固定サブネット (`QUIRE_COMPOSE_SUBNET`) 上に持ち、`QUIRE_TRUSTED_PROXY_CIDRS` にそのアドレスを指定します。サブネットがホストのネットワークと重複する場合は両方を変更してから `docker compose down`、続けて `up` を実行します。

## 独自リバースプロキシの背後で運用 <!--quire:behind-your-own-reverse-proxy-->

既存のロードバランサーやプロキシを使う場合は `proxy` を外し (`docker compose up -d --scale proxy=0`)、`web` (8080)、`content` (8081)、`collab` (1234、websocket)、`centrifugo` (8000、websocket) の前で TLS を終端します。公開アドレスを `QUIRE_APP_ORIGIN`、`QUIRE_CONTENT_ORIGIN`、`QUIRE_COLLAB_URL` (`wss://`) に、プロキシのアドレス範囲を `QUIRE_TRUSTED_PROXY_CIDRS` に設定します。

## トラブルシューティング <!--quire:troubleshooting-->

- `init` が "QUIRE_DATABASE_ID is not a UUID" で終了する場合は、`uuidgen` で値を設定します。
- `web` が "did not start on compose" で再起動する場合、ログに対応できない設定と代わりに使う値が表示されます。
- 初回起動後に `.env` でロールパスワードを変更しても反映されません。init スクリプトは 1 度しか実行しません。`ALTER ROLE` を使ってください。
- `CLAMAV_URL` を設定中にスキャンエラーでアップロードが失敗する場合、ClamAV が初回起動時に署名をダウンロードしています。数分待ってください。

Source: https://docs.quirelms.com/ja/ops/install/index.mdx
