使用 Docker 部署
Chorus 提供了官方 Docker 镜像 chorusaidlc/chorus-app。本指南展示两种 Compose 形态:
独立(内置数据库)与生产(外部 PostgreSQL + Redis),一个对接现有数据库的 docker run
示例、完整的环境变量参考,以及容器启动时的行为。
先拉取镜像:
docker pull chorusaidlc/chorus-app:latest关于如何在独立与生产两种形态之间做选择,请参见部署概览。
独立(内置数据库)
Section titled “独立(内置数据库)”无需外部数据库。镜像内置了 PGlite(嵌入式 PostgreSQL),并会自动启动 一切。数据保存在 Docker 卷中,可在容器重启后持久保留。
创建 docker-compose.local.yml:
# Standalone Chorus — embedded PGlite, no external PostgreSQL or Redisservices: 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:然后运行:
docker compose -f docker-compose.local.yml up -d打开 http://localhost:8637,使用 admin@example.com / changeme 登录(或通过
DEFAULT_USER / DEFAULT_PASSWORD 环境变量覆盖)。
在独立模式下,容器会:
- 在内部端口(
5433)上启动 PGlite,不对外暴露。 - 将数据存放在
chorus-local-dataDocker 卷中,因此可在重启后持久保留。 - 当
NEXTAUTH_SECRET留空时,在首次启动生成一个随机的会话签名密钥并保存在同一个卷中(参见 会话密钥)。 - 禁用 Redis(回退到内存 EventBus,仅支持单实例)。
- 在启动时自动执行 Prisma 迁移。
生产(外部 PostgreSQL + Redis)
Section titled “生产(外部 PostgreSQL + Redis)”面向生产环境,尤其是多副本部署时,请将应用对接到外部 PostgreSQL 与 Redis。创建
docker-compose.yml:
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:
echo "NEXTAUTH_SECRET=$(openssl rand -base64 32)" >> .env然后运行:
docker compose up -d打开 http://localhost:8637,使用你在 DEFAULT_USER / DEFAULT_PASSWORD 中设置的凭据
登录。
对接现有 PostgreSQL 运行
Section titled “对接现有 PostgreSQL 运行”如果你已经有 PostgreSQL 和 Redis 在运行,可直接启动容器:
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,并在每次启动时复用同一值。
数据库与会话密钥
Section titled “数据库与会话密钥”| 变量 | 说明 |
|---|---|
DATABASE_URL | PostgreSQL 连接字符串。格式:postgresql://user:password@host:port/dbname。也可以改为设置单独的 DB_* 变量(见下文)。若省略,入口脚本会自动启动一个嵌入式 PGlite 实例。 |
NEXTAUTH_SECRET | 用于签发会话令牌的密钥。请使用随机字符串(例如 openssl rand -base64 32)。在 Docker 中可以留空:容器会在首次启动时生成一个并保存在 /app/data/.secret。运行多个应用容器时,必须在每个副本上显式设置同一个值。参见会话密钥。 |
数据库(DATABASE_URL 的替代方案)
Section titled “数据库(DATABASE_URL 的替代方案)”若未设置 DATABASE_URL,入口脚本会用以下单独变量拼装它:
| 变量 | 说明 |
|---|---|
DB_HOST | PostgreSQL 主机 |
DB_PORT | PostgreSQL 端口(默认:5432) |
DB_USERNAME | PostgreSQL 用户名 |
DB_PASSWORD | PostgreSQL 密码 |
DB_NAME | 数据库名 |
| 变量 | 说明 |
|---|---|
REDIS_URL | 完整的 Redis 连接字符串。格式:redis://username:password@host:port。优先级高于以下单独变量。 |
REDIS_HOST | Redis 主机(在未设置 REDIS_URL 时使用) |
REDIS_PORT | Redis 端口(默认:6379) |
REDIS_USERNAME | Redis 用户名(默认:default) |
REDIS_PASSWORD | Redis 密码 |
| 变量 | 说明 |
|---|---|
DEFAULT_USER | 内置登录的邮箱地址(绕过 OIDC)。首次登录时自动创建该用户及公司。 |
DEFAULT_PASSWORD | 默认用户的密码(明文,运行时通过 bcrypt 比对)。 |
NEXTAUTH_URL | 应用对外的基础 URL(默认:http://localhost:8637)。在反向代理后运行时请设置此项。 |
COOKIE_SECURE | 设为 "false" 可为纯 HTTP 部署禁用安全 Cookie(docker-compose 中默认为 "false")。以 HTTPS 部署到生产环境时设为 "true"。 |
| 变量 | 默认值 | 说明 |
|---|---|---|
LOG_LEVEL | info(生产)/ debug(开发) | 服务端最低日志级别。可选:trace、debug、info、warn、error、fatal、silent。设为 info 可抑制 Prisma 查询日志。 |
NEXT_PUBLIC_LOG_LEVEL | warn(生产)/ debug(开发) | 浏览器端最低日志级别。可选:debug、info、warn、error。 |
生产 Docker 镜像始终将 JSON 输出到 stdout(可直接对接 CloudWatch / ELK)。彩色美化输出仅在 本地开发时可用。
| 变量 | 说明 |
|---|---|
SUPER_ADMIN_EMAIL | 超级管理员账号的邮箱(可访问 /admin 面板)。 |
SUPER_ADMIN_PASSWORD_HASH | 超级管理员密码的 bcrypt 哈希。生成方式:node -e "console.log(require('bcryptjs').hashSync('your-password', 10))" |
容器的入口脚本每次启动都会执行相同的流程:
- 检查
NEXTAUTH_SECRET。若为空,或等于以前示例文件中出现过的占位值,容器会在/app/data/.secret中读取或生成密钥,并在日志中说明做了什么(但绝不打印密钥本身)。你自己 显式设置的密钥会原样使用。 - 若未设置
DATABASE_URL且未提供任何DB_*变量,入口脚本会在内部端口(5433)上启动 一个嵌入式 PGlite 实例。当已配置外部数据库时,不会启动 PGlite。 - 执行
prisma migrate deploy,应用任何待处理的数据库迁移。 - 若数据库尚未就绪,每 10 秒重试一次(最多 30 次,约五分钟)。
- 迁移成功后,Next.js 服务在
8637端口启动。
会话密钥(NEXTAUTH_SECRET)
Section titled “会话密钥(NEXTAUTH_SECRET)”NEXTAUTH_SECRET 签发 Chorus 自己的 user_session(内置登录)和 admin_session(超级管理员)JWT。
OIDC token 由身份提供方签名,Agent API key 也单独校验。轮换此密钥会使 Chorus 自签名会话失效,
不会轮换 API key,也不会使身份提供方的 OIDC token 失效。
- 显式设置非占位值:直接使用,不读写密钥文件。
- 未设置、为空或使用已知公开占位值:复用
/app/data/.secret;文件不存在或为空时, 生成 32 个随机字节,编码为 64 个十六进制字符,以0600权限保存。环境变量中的占位值还会触发警告。 - 持久化密钥不可用:文件不是普通文件、不可读、保存了公开占位值,或生成、写入失败时, 容器会在迁移前停止。已保存的公开占位值不会被悄悄接受或替换。
日志不会打印密钥值。要保留自动生成的密钥,请把 /app/data 放在持久卷上。多副本部署必须向每个实例显式注入
同一个密钥;AWS CDK 栈已通过 Secrets Manager 共享该值。
设置与轮换密钥
Section titled “设置与轮换密钥”用 openssl rand -base64 32 生成一次,存入部署的密钥库或受保护的 .env,后续启动复用。
有效密钥改变后,内置登录用户和超级管理员需要重新登录。删除 .secret 只会影响自动生成的密钥;
已显式配置密钥时,删除该文件不会轮换密钥。
Docker 入口脚本和 npm chorus 启动器会自动处理密钥。直接用 next start 或 node server.js
启动时不会自动生成,需自行配置安全密钥。应用发现已知占位值会记录错误,但警告本身不会替换该值;
未设置密钥时,无法签发 Chorus 自签名会话。
- 基础镜像:
node:22-alpine - 内部端口:
8637 - 架构:
linux/amd64、linux/arm64