Rallly 4.16 Docker Compose 部署指南

从零部署 Rallly 4.16 的两条官方路径对比与手动 Compose 全流程实测:必需环境变量、OTP 登录验证、SMTP/S3/外部反代可选组件,附 5 段真实排障实录(zod 校验、密码长度、PG 初始化、跨网络隔离、旧变量废弃)。

Rallly自托管预约调度会议2026/10/24

Rallly 4.16 Docker Compose 部署指南

适用版本:Rallly v4.16.2(2026-10-23 发布)。本文所有命令与回显均在真实服务器口径下实测(查询日期 2026-10-24),数据库迁移数量、报错文本均为逐行实录。

一、部署前决策:官方两条路径怎么选

Rallly 官方自托管文档(support.rallly.co/self-hosting)目前只维护一种"推荐形态":Rallly CLI 安装器。两条路径对比如下:

路径形态适合谁
A. 官方安装器(推荐)`curl -fsSL https://get.rallly.cobash把整套栈安装到/opt/rallly,包含 App + PostgreSQL + Garage(S3) + Traefik(反代),并用统一的 rallly.sh` 脚本管理
B. 手动 Compose(本篇主线)官方预构建应用(lukevella/rallly:4.16.2)+ 自备 PostgreSQL,自行编写 Compose 文件已有自己的 PostgreSQL/反代/证书体系,或需要把 App 编入既有部署体系

安装器路径的默认形态会申请 Let's Encrypt 证书并独占 80/443,还需要提前把域名 A 记录指向服务器。如果你的服务器已有 nginx/caddy 在跑,安装器支持 PROXY_MODE=external 切换为外部反代模式(详见第六节),但既有的证书与路由就需要自己接管。

两条路径的底层组件完全一致,本文主线走路径 B——它最透明,也最能讲清楚 Rallly 的依赖链;rallly.sh 管理命令在《Rallly 4.16 常用 CLI 命令详解》中单篇实测。

二、系统要求(官方自托管文档口径)

  • 服务器内存 ≥ 2 GB(Rallly + PostgreSQL 合计的最小实用配置)。
  • Docker 19.03+ 与 Docker Compose v2。
  • 一个可用域名,或至少一个可访问的服务器地址(应用启动强制要求 NEXT_PUBLIC_BASE_URL 指向真实可访问 URL)。
  • SMTP 投递能力:登录验证码、邀请、通知邮件都依赖邮件发送;没有 SMTP 就无法登录(验证码发不出去)。内网环境可搭 Mailpit/MailHog 做接收调试。
  • PostgreSQL:必需依赖,推荐 18(官方栈默认 POSTGRES_VERSION=18)。

三、准备目录与 Compose 文件

先在工作目录放置 Compose 文件与数据库目录(示例统一放在 /opt/rallly-stack,实际位置随意):

mkdir -p /opt/rallly-stack/pgdata
cd /opt/rallly-stack

Compose 文件(docker-compose.yml),仅包含必需的两个服务:

name: rallly-4.16.2-stack

services:
  rallly_db:
    image: postgres:18-alpine
    container_name: rallly-4.16.2-db
    restart: unless-stopped
    volumes:
      - ./pgdata:/var/lib/postgresql
    environment:
      - POSTGRES_PASSWORD=ralllydb
      - POSTGRES_DB=rallly
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 5s
      timeout: 5s
      retries: 10

  rallly_web:
    image: lukevella/rallly:4.16.2
    container_name: rallly-4.16.2-web
    restart: unless-stopped
    depends_on:
      rallly_db:
        condition: service_healthy
    ports:
      - "8133:3000"
    environment:
      - DATABASE_URL=postgres://postgres:ralllydb@rallly_db/rallly
      - SECRET_PASSWORD=q1w2e3r4q1w2e3r4q1w2e3r4q1w2e3r4
      - SUPPORT_EMAIL=admin@example.com
      - NEXT_PUBLIC_BASE_URL=http://127.0.0.1:8133

四个应用环境变量一个都不能少(作用见《Rallly 4.16 配置参数详解》):

  • DATABASE_URL:PostgreSQL 连接串,服务名 rallly_db 由 Compose 内部 DNS 解析。
  • SECRET_PASSWORD:会话加密密钥,最少 32 个字符(源码 zod 校验 z.string().min(32),实测第五节有翻车实录)。
  • SUPPORT_EMAIL:站点支持邮箱,校验类型为邮箱格式。
  • NEXT_PUBLIC_BASE_URL:站点对外访问地址(4.16 起的变量名;旧版本的 NEXT_PUBLIC_URL 已废弃,实测传入会被静默忽略)。

四、首次启动实录

$ docker compose up -d
[+] Running 3/3
 ✔ Network rallly-4162-stack_default    Created
 ✔ Container rallly-4.16.2-db           Healthy
 ✔ Container rallly-4.16.2-web          Started

首次启动会自动执行 Prisma 数据库迁移,日志实录(docker logs -f rallly-4.16.2-web,首尾节选):

No .env file found, continuing without it
Loaded Prisma config from prisma.config.ts.

Prisma schema loaded from prisma.
Datasource "db": PostgreSQL database "rallly", schema "public" at "rallly_db"

166 migrations found in prisma/migrations

Applying migration `20220315143815_init`
...(中略,共 166 条,最新一条为 20261019120000_poll_activities_user_id_index)
Applying migration `20261019120000_poll_activities_user_id_index`

探活首页:

$ curl -s -o /dev/null -w "HTTP %{http_code}\n" http://127.0.0.1:8133/
HTTP 200

运行时版本可在日志中确认(实测输出):

▲ Next.js 16.4.2

五、登录验证:OTP 全链路实测

Rallly 4.16 的账号体系是"邮箱验证码登录"(Better Auth 的 emailOTP),注册与登录是同一个入口 /login:

  1. 在登录页输入邮箱提交,系统调用 POST /api/better-auth/email-otp/send-verification-otp(实测返回 {"success":true})。
  2. 邮箱收到 6 位验证码,邮件正文实录(调试环境用 Mailpit 接收):
VERIFY YOUR EMAIL ADDRESS

Please use the following 6-digit verification code to verify your email

925718

This code is valid for 15 minutes
  1. 提交验证码后登录成功,服务端返回会话(实测响应节选):
{"token":"QPvUKKP1sg7qZpBRjQYKtVCXtGdgNxSp","user":{"email":"admin@example.com","emailVerified":true,"role":"user",...}}

浏览器会写入 better-auth.session_token Cookie(HttpOnly,默认 60 天有效期)。首个用户落库后,如果部署时配置了 INITIAL_ADMIN_EMAIL 且与该邮箱一致,访问 /admin-setup(实测 HTTP 200)即可认领管理控制面板管理员身份。

六、可选组件与生产化调整

6.1 SMTP(生产必配)

内网调试可用 Mailpit(SMTP 端口 1025、Web 界面 8025)接收验证码;生产环境换真实邮件服务,把以下变量加入 rallly_web 的 environment(完整参数见配置篇):

      - SMTP_HOST=smtp.example.com
      - SMTP_PORT=587
      - SMTP_SECURE=false
      - SMTP_USER=mailer@example.com
      - SMTP_PWD=你的SMTP密码

6.2 对象存储(可选)

头像上传等需要 S3 兼容存储;不配置 S3 时应用功能正常(实测部署未配 S3 也能完整走通登录),只是上传能力受限:

      - S3_ENDPOINT=http://minio.example.com:9000
      - S3_BUCKET_NAME=rallly
      - S3_ACCESS_KEY_ID=xxxx
      - S3_SECRET_ACCESS_KEY=xxxx
      - S3_REGION=us-east-1

6.3 外部反代模式

生产建议前置 nginx/caddy/traefik 做证书与域名,应用仅监听本机回环:

    ports:
      - "127.0.0.1:3000:3000"

反代侧需要把 NEXT_PUBLIC_BASE_URL 对应的域名(如 https://rallly.example.com)转发到 127.0.0.1:3000,并放行 WebSocket(投票页实时刷新需要)。官方安装器形态即内建 Traefik 完成这件事;手动路径 PROXY_MODE 变量是官方栈脚本层的开关,纯手动 Compose 无需设置。

七、排障实录(本篇部署路径真实踩坑)

7.1 缺必需环境变量:zod 校验直接拒绝启动

故意只给 DATABASE_URL 启动,日志实录:

❌ Invalid environment variables: [
  {
    expected: 'string',
    code: 'invalid_type',
    path: [ 'SECRET_PASSWORD' ],
    message: 'Invalid input'
  },
  {
    expected: 'string',
    code: 'invalid_type',
    path: [ 'SUPPORT_EMAIL' ],
    message: 'Invalid input'
  },
  {
    expected: 'string',
    code: 'invalid_type',
    path: [ 'NEXT_PUBLIC_BASE_URL' ],
    message: 'Invalid input'
  }
]
Failed to prepare server Error: An error occurred while loading instrumentation hook: Invalid environment variables

处置:把四个必需变量补齐即可,报错清单会精确列出缺失项。

7.2 SECRET_PASSWORD 少于 32 字符

设为 q1w2e3r4(8 字符)启动,日志实录:

❌ Invalid environment variables: [
  {
    origin: 'string',
    code: 'too_small',
    minimum: 32,
    inclusive: true,
    path: [ 'SECRET_PASSWORD' ],
    message: 'Invalid input'
  }
]

其余变量全部通过,仅这一条报错——源码校验 z.string().min(32) 与实测一致,请直接给 32 位以上随机串。

7.3 PostgreSQL 密码未设置导致数据库重启循环

官方安装器会为 PostgreSQL 自动生成密码,但手动部署若只给了 POSTGRES_DB 没给 POSTGRES_PASSWORD,数据库进入重启循环,日志实录:

Error: Database is uninitialized and superuser password is not specified.
        You must specify POSTGRES_PASSWORD to a non-empty value for the
        superuser.

处置:在数据库服务加 POSTGRES_PASSWORD=<强密码> 并同步更新 DATABASE_URL。注意若数据目录已经以"失败状态"初始化,需清空 pgdata 后重建(首次部署无数据时直接删目录即可)。

7.4 跨网络访问隔离(Compose 默认网络)

把 SMTP 调试工具(Mailpit)部署在另一个 Compose 网络时,Rallly 发信会静默失败(验证码邮件收不到,应用日志无显性报错)。实测从应用侧探测:

http=000

原因:Docker 不同 bridge 网络之间默认隔离。处置:用外部网络把两个栈挂在同一网络下,或把 Mailpit 编入同一 Compose 文件。

7.5 旧版环境变量 NEXT_PUBLIC_URL 被静默忽略

给 4.16.2 传入旧变量 NEXT_PUBLIC_URL=http://legacy.example.com,服务正常启动(HTTP 200),无任何警告——该变量已从源码 env 定义中移除,真实生效的只有 NEXT_PUBLIC_BASE_URL。从旧版本升级时必须改名,否则站点仍按旧地址生成链接。

八、升级要点

  1. 备份先行:pg_dump 导出(CLI 路径可直接用 rallly.sh backup,实测产物 rallly_20261024_112602.sql.gz)。
  2. 固定版本号升级:把 lukevella/rallly:4.16.2 改为新 tag(如跟随 4 跟踪 tag 则 docker compose pull 拉取),docker compose up -d 重建;启动时自动跑增量迁移(实测 4.16.2 首启为 166 个迁移,升级时只补新增部分)。
  3. 大版本升级前阅读官方 release notes:4.x 系列内环境变量存在改名与废弃(如 NEXT_PUBLIC_URL→NEXT_PUBLIC_BASE_URL、SMTP_TLS_ENABLED→SMTP_REJECT_UNAUTHORIZED),逐项核对配置篇的参数表。

九、相关文档