Chorus は公式 Docker イメージ **`chorusaidlc/chorus-app`** を提供しています。このガイドでは、二つの Compose 構成（組み込みデータベースを使うスタンドアロン構成と、外部の PostgreSQL と Redis を使う本番構成）、既存のデータベースに接続する `docker run`、環境変数の完全なリファレンス、コンテナの起動時の動作を説明します。

まずイメージをプルします。

```bash
docker pull chorusaidlc/chorus-app:latest
```

スタンドアロン構成と本番構成の選び方については、[デプロイ概要](/ja/guides/deployment-overview/)を参照してください。

## スタンドアロン（組み込みデータベース）

外部データベースは不要です。イメージは [PGlite](https://pglite.dev)（組み込み PostgreSQL）を同梱しており、すべてを自動的に起動します。データは Docker ボリュームに保存されるため、コンテナを再起動しても失われません。

`docker-compose.local.yml` を作成します。

```yaml
# Standalone Chorus — embedded PGlite, no external PostgreSQL or Redis
services:
  app:
    image: chorusaidlc/chorus-app:latest
    ports:
      - "8637:8637"
    environment:
      # No DATABASE_URL — entrypoint auto-starts embedded PGlite
      - REDIS_URL=
      # Leave empty: the container generates a random session secret on first
      # start and keeps it in the chorus-local-data volume. Set it explicitly
      # (openssl rand -base64 32) if you prefer to manage it yourself.
      - NEXTAUTH_SECRET=${NEXTAUTH_SECRET:-}
      - COOKIE_SECURE=false
      - DEFAULT_USER=${DEFAULT_USER:-admin@example.com}
      - DEFAULT_PASSWORD=${DEFAULT_PASSWORD:-changeme}
    volumes:
      - chorus-local-data:/app/data

volumes:
  chorus-local-data:
```

そして実行します。

```bash
docker compose -f docker-compose.local.yml up -d
```

`http://localhost:8637` を開き、`admin@example.com` / `changeme` でサインインします（`DEFAULT_USER` / `DEFAULT_PASSWORD` 環境変数で変更できます）。

スタンドアロンモードでは、コンテナは次のことを行います。

- PGlite を内部ポート（`5433`）で起動し、外部には公開しません。
- データを `chorus-local-data` Docker ボリュームに保存するため、再起動してもデータが保持されます。
- `NEXTAUTH_SECRET` を空のままにした場合、初回起動時にランダムなセッション署名用の秘密鍵を生成し、同じボリュームに保存します（[セッションの秘密鍵](#セッションの秘密鍵nextauth_secret)を参照）。
- Redis を無効化します（メモリ内のイベント配信にフォールバック。単一インスタンスのみ）。
- 起動時に Prisma マイグレーションを自動的に実行します。

## 本番（外部 PostgreSQL + Redis）

本番環境、特に複数のレプリカを動かす場合は、アプリを外部の PostgreSQL と Redis に接続します。`docker-compose.yml` を作成します。

```yaml
services:
  app:
    image: chorusaidlc/chorus-app:latest
    ports:
      - "8637:8637"
    environment:
      - DATABASE_URL=postgresql://chorus:chorus@db:5432/chorus
      - REDIS_URL=redis://default:chorus-redis@redis:6379
      # Session-signing secret. Leave empty and the container generates one on
      # first start and persists it in the chorus-app-data volume (single
      # replica only). For production, or more than one app container, set it
      # explicitly in .env or the environment:  openssl rand -base64 32
      # Changing the secret invalidates Default Auth and Super Admin sessions.
      - NEXTAUTH_SECRET=${NEXTAUTH_SECRET:-}
      - COOKIE_SECURE=${COOKIE_SECURE:-false}
      - DEFAULT_USER=admin@example.com
      - DEFAULT_PASSWORD=your-password
    volumes:
      - chorus-app-data:/app/data
    depends_on:
      db:
        condition: service_healthy
      redis:
        condition: service_healthy

  redis:
    image: redis:7-alpine
    command: redis-server --requirepass chorus-redis
    volumes:
      - redis-data:/data
    healthcheck:
      test: ["CMD", "redis-cli", "-a", "chorus-redis", "ping"]
      interval: 5s
      timeout: 3s
      retries: 5

  db:
    image: postgres:16-alpine
    environment:
      POSTGRES_USER: chorus
      POSTGRES_PASSWORD: chorus
      POSTGRES_DB: chorus
    volumes:
      - chorus-data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U chorus -d chorus"]
      interval: 5s
      timeout: 5s
      retries: 5

volumes:
  chorus-app-data:
  chorus-data:
  redis-data:
```

セッションの秘密鍵を自分で用意する場合は、起動前に一度だけ生成し、compose ファイルと同じ場所の `.env` に書き込みます。

```bash
echo "NEXTAUTH_SECRET=$(openssl rand -base64 32)" >> .env
```

そして実行します。

```bash
docker compose up -d
```

`http://localhost:8637` を開き、`DEFAULT_USER` / `DEFAULT_PASSWORD` に設定した認証情報でサインインします。

:::caution[HTTPS とセキュア Cookie]
上記の Compose ファイルは、HTTP のみのデプロイ（例：内部ネットワークでのテスト）をサポートするために `COOKIE_SECURE=false` を設定しています。`COOKIE_SECURE=false` は信頼できる内部ネットワークでのみ使用してください。この場合、Cookie は暗号化されていない HTTP で送信されます。本番で HTTPS の背後にデプロイするときは、セキュア Cookie を有効にするために `COOKIE_SECURE=true` を設定してください。
:::

## 既存の PostgreSQL に対して実行する

すでに PostgreSQL と Redis が動作しているなら、コンテナを直接起動します。

```bash
docker run -d \
  -p 8637:8637 \
  -e DATABASE_URL=postgresql://user:pass@your-db-host:5432/chorus \
  -e REDIS_URL=redis://default:password@your-redis-host:6379 \
  -v chorus-app-data:/app/data \
  -e COOKIE_SECURE=false \
  -e DEFAULT_USER=admin@example.com \
  -e DEFAULT_PASSWORD=your-password \
  chorusaidlc/chorus-app:latest
```

この例は生成した秘密鍵を `chorus-app-data` に保存し、コンテナの再作成後も再利用します。
自分で管理する場合は、永続的な `NEXTAUTH_SECRET` を渡し、毎回同じ値を使用してください。

## 環境変数

### データベースとセッション秘密鍵

<div class="table-scroll" role="region" aria-label="必須の環境変数" tabindex="0">

  | 変数 | 説明 |
  | --- | --- |
  | `DATABASE_URL` | PostgreSQL 接続文字列。形式：`postgresql://user:password@host:port/dbname`。代わりに個別の `DB_*` 変数を設定することもできます（下記参照）。**省略した場合**、エントリーポイントは組み込みの PGlite インスタンスを自動的に起動します。 |
  | `NEXTAUTH_SECRET` | セッショントークンに署名するための秘密鍵。ランダムな文字列を使用してください（例：`openssl rand -base64 32`）。**Docker では空のままでも構いません。** その場合、コンテナが初回起動時に生成し、`/app/data/.secret` に保存します。複数のアプリコンテナを動かすときは、すべてのレプリカで同じ値を明示的に設定する必要があります。[セッションの秘密鍵](#セッションの秘密鍵nextauth_secret)を参照してください。 |

</div>

### データベース（`DATABASE_URL` の代替）

`DATABASE_URL` が設定されていない場合、エントリーポイントは以下の個別変数からそれを組み立てます。

<div class="table-scroll" role="region" aria-label="データベースの環境変数" tabindex="0">

  | 変数 | 説明 |
  | --- | --- |
  | `DB_HOST` | PostgreSQL ホスト |
  | `DB_PORT` | PostgreSQL ポート（デフォルト：`5432`） |
  | `DB_USERNAME` | PostgreSQL ユーザー名 |
  | `DB_PASSWORD` | PostgreSQL パスワード |
  | `DB_NAME` | データベース名 |

</div>

### Redis

<div class="table-scroll" role="region" aria-label="Redis の環境変数" tabindex="0">

  | 変数 | 説明 |
  | --- | --- |
  | `REDIS_URL` | 完全な Redis 接続文字列。形式：`redis://username:password@host:port`。個別変数より優先されます。 |
  | `REDIS_HOST` | Redis ホスト（`REDIS_URL` が設定されていない場合に使用） |
  | `REDIS_PORT` | Redis ポート（デフォルト：`6379`） |
  | `REDIS_USERNAME` | Redis ユーザー名（デフォルト：`default`） |
  | `REDIS_PASSWORD` | Redis パスワード |

</div>

### 認証

<div class="table-scroll" role="region" aria-label="認証の環境変数" tabindex="0">

  | 変数 | 説明 |
  | --- | --- |
  | `DEFAULT_USER` | 組み込みログイン用のメールアドレス（OIDC をバイパスします）。初回サインイン時にユーザーとそのワークスペースを自動的に作成します。 |
  | `DEFAULT_PASSWORD` | デフォルトユーザーのパスワード（平文で、実行時に bcrypt で照合します）。 |
  | `NEXTAUTH_URL` | アプリの対外的なベース URL（デフォルト：`http://localhost:8637`）。リバースプロキシの背後で実行するときに設定します。 |
  | `COOKIE_SECURE` | HTTP のみのデプロイでセキュア Cookie を無効にするには `"false"` に設定します（docker-compose ではデフォルトで `"false"`）。本番で HTTPS でデプロイするときは `"true"` に設定します。 |

</div>

### ログ

<div class="table-scroll" role="region" aria-label="ログの環境変数" tabindex="0">

  | 変数 | デフォルト | 説明 |
  | --- | --- | --- |
  | `LOG_LEVEL` | `info`（本番）/ `debug`（開発） | サーバーの最低ログレベル。受け付ける値：`trace`、`debug`、`info`、`warn`、`error`、`fatal`、`silent`。Prisma のクエリログを抑制するには `info` に設定します。 |
  | `NEXT_PUBLIC_LOG_LEVEL` | `warn`（本番）/ `debug`（開発） | ブラウザの最低ログレベル。受け付ける値：`debug`、`info`、`warn`、`error`。 |

</div>

本番 Docker イメージは常に JSON を stdout に出力します（CloudWatch / ELK にそのまま対応）。色付きの整形出力はローカル開発時のみ利用できます。

### スーパー管理者

<div class="table-scroll" role="region" aria-label="スーパー管理者の環境変数" tabindex="0">

  | 変数 | 説明 |
  | --- | --- |
  | `SUPER_ADMIN_EMAIL` | スーパー管理者アカウントのメール（`/admin` パネルにアクセスできます）。 |
  | `SUPER_ADMIN_PASSWORD_HASH` | スーパー管理者パスワードの bcrypt ハッシュ。生成方法：`node -e "console.log(require('bcryptjs').hashSync('your-password', 10))"` |

</div>

## 起動時の挙動

コンテナのエントリーポイントは、起動するたびに同じ流れを実行します。

1. `NEXTAUTH_SECRET` を確認します。空の場合、または以前のサンプルファイルに載っていたプレースホルダー値の場合、コンテナは `/app/data/.secret` から秘密鍵を読み込むか新たに生成し、何をしたかをログに記録します（値そのものは決して出力しません）。自分で明示的に設定した秘密鍵はそのまま使われます。
2. `DATABASE_URL` が設定されておらず、`DB_*` 変数も一つも与えられていない場合、エントリーポイントは内部ポート（`5433`）で組み込みの PGlite インスタンスを起動します。外部データベースが**設定されている**ときは、PGlite は起動しません。
3. `prisma migrate deploy` を実行し、保留中のデータベースマイグレーションを適用します。
4. データベースがまだ準備できていない場合は、10 秒ごとにリトライします（最大 30 回、およそ 5 分）。
5. マイグレーションが成功すると、Next.js サーバーが `8637` ポートで起動します。

:::note[マイグレーションは自動的に実行される]
マイグレーションを自分で実行する必要はありません。保留中のマイグレーションを起動時に適用することはエントリーポイントの一部なので、アップグレードは同じデータベースに対して新しいイメージを起動するだけです。新しいイメージは初回起動時にスキーマをマイグレートしうるため、アップグレード前にはデータベースまたはデータボリュームをバックアップしてください。[セルフホストの Chorus を運用する](/ja/guides/deploy-operations/)を参照してください。
:::

## セッションの秘密鍵（`NEXTAUTH_SECRET`）

`NEXTAUTH_SECRET` は、Chorus 自身が発行するサインインセッション（組み込みのメール／パスワードログインと
スーパー管理者のセッション）に署名します。OIDC トークンは ID プロバイダーが署名し、
エージェントの API キーは別途検証されます。この秘密鍵の変更で無効になるのは Chorus が署名したセッションです。
API キーやプロバイダーの OIDC トークンは変更されません。

:::caution[0.18.0 以前からのアップグレード]
公開プレースホルダーの秘密鍵を使用していた場合、0.18.1 はその値を無視し、非公開の秘密鍵を
再利用または生成します。影響を受ける Chorus 署名のセッションのユーザーは、再度サインインする必要があります。
エントリーポイントは明示的に渡された安全な秘密鍵を維持します。その値を使い続ければ、ユーザーが再度サインインする
必要はありません。CDK の再デプロイでは `nextAuthSecret` を明示的に維持してください。
[CDK の秘密鍵設定](/ja/guides/deploy-production/)を参照してください。

古い Compose ファイルに `/app/data` のボリュームがない場合、コンテナの再作成ごとに生成済みの
秘密鍵が失われます。上記のボリュームを追加するか、永続的な `NEXTAUTH_SECRET` を設定してください。
:::

### コンテナの動作

- **明示的な非プレースホルダー値**：ファイルを読み書きせず、その値を使用します。
- **未設定、空、既知の公開プレースホルダー**：`/app/data/.secret` を再利用します。ファイルがないか
  空の場合、32 バイトの乱数を 64 文字の十六進数として生成し、権限 `0600` で保存します。
  環境変数にプレースホルダーが設定されている場合は警告も出します。
- **利用できない保存済み秘密鍵**：通常ファイルでない、読めない、公開プレースホルダーが保存されている、
  または生成・書き込みが失敗した場合は、マイグレーション前に停止します。
  保存済みの公開プレースホルダーを、警告なしに使用したり置き換えたりはしません。

秘密鍵の値はログに出しません。自動生成した秘密鍵を保持するには、`/app/data` を永続ボリュームに置いてください。複数のレプリカには、
すべてのインスタンスに**同じ**秘密鍵を明示的に渡します。[AWS CDK スタック](/ja/guides/deploy-production/)は
Secrets Manager を通じてすでに共有しています。

### 秘密鍵の設定と変更

`openssl rand -base64 32` で一度だけ生成し、シークレットストアか保護された `.env` に保存して
再利用します。有効な秘密鍵を変更すると、組み込みログインのユーザーとスーパー管理者は再度サインインする
必要があります。`.secret` の削除が影響するのは自動生成した秘密鍵だけで、明示的な設定値には影響しません。

自動生成を行うのは Docker エントリーポイントと npm の `chorus` ランチャーです。
`next start` や `node server.js` で直接起動する場合は、安全な値を自分で設定してください。
アプリは既知のプレースホルダーをエラーログに記録しますが、置き換えはしません。
秘密鍵が未設定だと Chorus 署名のセッションを発行できません。

## イメージの詳細

- **ベースイメージ：** `node:22-alpine`
- **内部ポート：** `8637`
- **アーキテクチャ：** `linux/amd64`、`linux/arm64`

## 次へ

- **[本番環境でデプロイ](/ja/guides/deploy-production/)**：グローバル npm パッケージから実行する方法と、
  完全な AWS CDK の手順。
- **[セルフホストの Chorus を運用する](/ja/guides/deploy-operations/)**：初回ログインのブートストラップ、デプロイ側の
  認証、そしてアップグレード前のバックアップ。
