部署
面向平台运维人员。这些任务会影响整个部署。请按任务要求准备服务器访问权限或平台管理权限。从管理员手册开始。
本页介绍如何在生产环境中运行 OpenBot。你要构建 Docker 镜像,准备数据库,设置平台,然后在反向代理后面启动服务器。每个设置项的说明,请看配置。
- 一台装有 Docker 和 Docker Compose 的 Linux 服务器。
- 一个给 OpenBot 用的域名,例如
api.example.com,以及它的 TLS 证书。 - 一个给平台用的 OpenID Connect 提供方,例如
https://id.example.com。在其中注册一个客户端,重定向 URI 为https://api.example.com/auth/callback/oidc。如果用户只通过组织的 SSO 连接登录,可以跳过这一项。 - 一个模型服务,如果你想让 Bot(机器人)干活的话。设置完成后,通过 API 添加它。请看模型。
所有 Docker 文件都在 deploy/docker/ 中。一个 Dockerfile
生成两个镜像。每个镜像是一个构建目标(文件中一个有名字的最终阶段):
| 目标 | 镜像 | 运行什么 |
|---|---|---|
openbot |
openbot |
OpenBot 和它的迁移程序。 |
protocol-test |
openbot-protocol-test |
App Protocol 的测试服务。请看协议测试。 |
文件 docker-bake.hcl 告诉 Docker Bake
如何构建它们。在仓库根目录运行:
export OPENBOT_RELEASE=$(git rev-parse HEAD)TAG=$OPENBOT_RELEASE docker buildx bake -f deploy/docker/docker-bake.hcl --load这会为 linux/amd64 构建 openbot:$OPENBOT_RELEASE 和
openbot-protocol-test:$OPENBOT_RELEASE。--load
把它们放进你本地的 Docker。不设 TAG 时,标签是
local。如果只想构建一个镜像,就加上它的目标名,例如 openbot。
如果电脑不是
x86_64,Docker 需要 QEMU(一个能运行其他处理器代码的程序)来构建镜像。用
docker run --privileged --rm tonistiigi/binfmt --install amd64 安装一次即可。
两个镜像都基于
distroless,Node.js 版本和开发环境相同。distroless 镜像没有 shell,也没有包管理器,所以你不能用
docker exec 进入它们的 shell。它们以用户 nonroot(65532)运行。
OpenBot 镜像包含 Node.js、打包好的服务器、打包好的迁移程序和设置程序,以及数据库迁移文件。它不含构建工具,也不含任何密钥。
| 镜像中的路径 | 是什么 |
|---|---|
/app/dist/app/Main.mjs |
服务器。镜像默认运行它。 |
/app/dist/app/Migrate.mjs |
迁移程序。它负责准备数据库。 |
/app/dist/app/Setup.mjs |
设置程序。它写入最初的平台设置。 |
/app/migrations |
数据库迁移文件。 |
镜像中的服务器监听 0.0.0.0:3000。镜像带有健康检查,每五秒调用一次 /health。
用文件提供密钥
Section titled “用文件提供密钥”OpenBot 先从环境变量读取每个设置。如果没有设置该变量,OpenBot 就改读文件
/run/secrets/<NAME>,例如
/run/secrets/OPENBOT_SECRET_KEYS。Docker 和 Compose 就把密钥放在这里。空文件视为未设置。请看配置。
环境变量会出现在 docker inspect 中。/run/secrets
中的文件不会。Compose 对所有密钥都使用文件。
用 Docker 运行
Section titled “用 Docker 运行”把设置写进一个文件,例如 openbot.env。它只需要 OPENBOT_DATABASE_URL 和
OPENBOT_SECRET_KEYS 和 OPENBOT_CLUSTER_SECRET。可以从
deploy/docker/production.env.example 开始。docker run 不会替换
${POSTGRES_PASSWORD},所以请自己写出完整的 OPENBOT_DATABASE_URL。
生成一次密钥:
echo "OPENBOT_SECRET_KEYS=k1:$(openssl rand -hex 32)" >> openbot.envecho "OPENBOT_CLUSTER_SECRET=$(openssl rand -hex 32)" >> openbot.env请看密钥。
节点间的私有调用使用 /internal/executions/rpc 和
/internal/resources/rpc。请只在私有网络开放这两个路径。所有节点使用同一个随机密钥。多节点部署中,为每个节点设置不同且可访问的主机地址。私有 RPC 客户端与 App 的出站网络检查分开。
迁移程序需要 OPENBOT_DATABASE_URL 和
OPENBOT_SECRET_KEYS。运行前停止所有 OpenBot 实例。备份数据库和对象存储键的清单。保留旧密钥,数据转换需要用它们打开旧记录。首次启动服务器和每次发布新版本之前都要运行:
docker run --rm --env-file openbot.env \ openbot:$OPENBOT_RELEASE /app/dist/app/Migrate.mjs同一迁移程序会把支持转换的 UUID 列从文本改为 PostgreSQL 的 uuid
类型,每个 ID 占 16 字节。旧 v4 值不变;新的存储 ID 在时间顺序有帮助时使用 v7。含混合格式或外部 ID 的列保留文本。按上文要求,停止所有服务器后再运行。
转换中断后,再运行同一命令。每一批数据与进度一起提交。损坏的记录会停止转换,并留下加密的错误报告。程序检查数量、引用、密钥和状态后,才将数据版本标记为就绪。检查通过前,服务器不能启动。运行中的服务器持有共享数据库锁;转换程序需要独占锁。
备份保留资源 ID、历史和待处理决策。结果不明的旧外部动作保留为
outcome_unknown。没有安全检查点的工作标记为
interrupted,并保留原因。缺少原始 token 的记录不能变成不受限制的成员调用。
恢复流量前可以还原备份。重新执行外部动作后,应向前修复数据。不要还原旧数据并重复这些动作。
在新数据库上运行一次设置程序:
docker run --rm --env-file openbot.env openbot:$OPENBOT_RELEASE \ /app/dist/app/Setup.mjs \ --public-origin=https://api.example.com \ --oidc-issuer=https://id.example.com \ --oidc-client-id=openbot \ --admin-email=alice@example.com它把公开源、平台提供方和最初的平台管理员写入数据库。客户端密钥请用
-e OPENBOT_SETUP_OIDC_CLIENT_SECRET=...
传入,不要写在命令行参数里。所有参数请看平台。
你也可以在服务器启动后再运行设置。在那之前,除 /health 外的每个路由都返回
503 和 SetupRequired。
docker run -d --name openbot --env-file openbot.env \ -p 127.0.0.1:8080:3000 openbot:$OPENBOT_RELEASE服务器启动时,会检查表结构和已完成的数据版本。任一检查失败,它都会停止,并在日志中写入错误。
curl http://127.0.0.1:8080/health{ "status": "ok" }/health 只说明 HTTP 服务器能够应答。它不检查数据库、设置或模型。
现在 Alice 可以登录了。她是平台管理员。下一步,添加一个模型,以及一个关联它的模型提供方。请看模型。
不用 Docker
Section titled “不用 Docker”你也可以在服务器上直接用 Node.js 运行这些程序:
pnpm install --frozen-lockfilepnpm --filter-prod @openbot-build/openbot... buildpnpm --filter @openbot-build/openbot migratepnpm --filter @openbot-build/openbot setup --public-origin=https://api.example.com --admin-email=alice@example.compnpm --filter @openbot-build/openbot start包 @openbot-build/openbot 还提供命令 openbot-server、openbot-migrate 和
openbot-setup。有了包 @openbot-build/cli,你也可以用
openbot server、openbot migrate 和 openbot setup 运行它们。
用 Compose 运行
Section titled “用 Compose 运行”文件 deploy/docker/compose.production.yaml 运行以下服务:
| 服务 | 镜像 | 主机上的端口 |
|---|---|---|
postgres |
postgres:18.6-alpine3.24,用摘要固定,数据在卷 postgres 中 |
无 |
migrate |
openbot:$OPENBOT_RELEASE |
无 |
openbot |
openbot:$OPENBOT_RELEASE |
127.0.0.1:8080,或 OPENBOT_PUBLISHED_PORT |
protocol-test |
openbot-protocol-test:$OPENBOT_RELEASE |
127.0.0.1:3001 |
migrate 在 PostgreSQL 健康之后运行一次迁移程序。只有 migrate 成功,openbot
才会启动。所以 up 总是先迁移数据库。
protocol-test 服务是 App
Protocol 的公开测试服务。请看协议测试。即使你只用 OpenBot,这个文件也需要
PROTOCOL_TEST_PUBLIC_ORIGIN。
Compose 以 /run/secrets 中文件的形式提供 POSTGRES_PASSWORD、
OPENBOT_DATABASE_URL、OPENBOT_SECRET_KEYS 和
OPENBOT_CLUSTER_SECRET。这些值来自 .env.production。openbot 服务还接收
OPENBOT_OUTBOUND_ALLOW 和
OPENBOT_CLUSTER_HOST。产品设置保存在数据库中。migrate 服务需要
OPENBOT_DATABASE_URL 和 OPENBOT_SECRET_KEYS。
在模板中,OPENBOT_DATABASE_URL 使用
${POSTGRES_PASSWORD},所以密码只需要设置一次。
cp deploy/docker/production.env.example .env.productionopenssl rand -hex 32 # 把输出用作 POSTGRES_PASSWORDecho "k1:$(openssl rand -hex 32)" # 把输出用作 OPENBOT_SECRET_KEYSopenssl rand -hex 32 # 把输出用作 OPENBOT_CLUSTER_SECRET在 .env.production 中填写这些值。
构建两个镜像
Section titled “构建两个镜像”export OPENBOT_RELEASE=$(git rev-parse HEAD)TAG=$OPENBOT_RELEASE docker buildx bake -f deploy/docker/docker-bake.hcl --loaddocker compose --env-file .env.production -f deploy/docker/compose.production.yaml config --quiet缺少必需的设置时,它会显示错误。不加 --quiet
时,它会打印填好所有值的完整配置。
启动全部服务
Section titled “启动全部服务”docker compose --env-file .env.production -f deploy/docker/compose.production.yaml up -d --wait--wait
会等到所有服务都健康后才返回。镜像每五秒检查一次健康状态。服务进程停止时,Compose 会重新启动它。
在第一次 up 之后,运行一次设置程序:
docker compose --env-file .env.production -f deploy/docker/compose.production.yaml \ run --rm openbot /app/dist/app/Setup.mjs \ --public-origin=https://api.example.com \ --oidc-issuer=https://id.example.com \ --oidc-client-id=openbot \ --admin-email=alice@example.com在完成这一步之前,除 /health 外的每个路由都返回 503 和
SetupRequired。请看平台。
要发布新版本,请构建新镜像并设置新的
OPENBOT_RELEASE。停止全部 OpenBot 实例,备份数据库和对象键清单,再运行
up -d --wait。新的 OpenBot 启动前,migrate 会再次运行。不要删除 postgres
卷。它保存着你的全部数据。
你可以在一个负载均衡器后面运行多个 OpenBot 实例。给每个实例:
- 相同的
OPENBOT_DATABASE_URL, - 相同的
OPENBOT_SECRET_KEYS和OPENBOT_CLUSTER_SECRET, - 各不相同、且其他节点都能访问的
OPENBOT_CLUSTER_HOST, - 相同的
OPENBOT_OUTBOUND_ALLOW(如果你设置了它)。参见出站连接。
每个节点使用自己的私有地址,不要使用负载均衡器的地址。扩容 Compose 的 openbot
服务时,必须为每个新节点配置独立主机名。compose.check.yaml
中的两个节点展示了这种配置。
所有共享设置都存放在数据库中。管理员修改设置后,每个实例会立即使用新设置。请看配置。迁移程序和设置程序只运行一次,不要在每个实例上都运行。
TLS 和反向代理
Section titled “TLS 和反向代理”在生产环境中,由反向代理处理 HTTPS,并把流量转发给 127.0.0.1:8080
上的 OpenBot。OpenBot 只提供普通 HTTP,所以只有代理提供 HTTPS。
代理必须:
-
拒绝所有访问
/internal/下路径的公开请求, -
把
Origin、Cookie和Authorization头原样转发给 OpenBot, -
不缓冲响应,因为 Turn 可以用服务器发送事件(SSE)流式输出,
-
允许长时间的响应。执行事件流可以保持打开,直到执行结束。
server { listen 443 ssl; server_name api.example.com; ssl_certificate /etc/ssl/api.example.com.pem; ssl_certificate_key /etc/ssl/api.example.com.key;
location /internal/ { return 404; }
location / { proxy_pass http://127.0.0.1:8080; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header Connection ""; proxy_buffering off; proxy_cache off; proxy_read_timeout 1h; }}api.example.com { handle /internal/* { respond 404 } handle { reverse_proxy 127.0.0.1:8080 { flush_interval -1 } }}同源的自有客户端
Section titled “同源的自有客户端”与 OpenBot 同源的浏览器客户端可以使用登录 cookie。它不需要用户令牌。为此,你的代理把一部分路径转发给 OpenBot,其余路径转发给你的客户端。
| 路径 | 转发给 | 是什么 |
|---|---|---|
/auth/* |
OpenBot | 登录、退出,以及 App 授权回调。 |
/v1/* |
OpenBot | API。 |
/health |
OpenBot | 健康检查。 |
/openapi.json |
OpenBot | OpenAPI 文档。 |
/docs |
OpenBot | 交互式 API 参考。可选。 |
| 其他所有路径 | 你的客户端 | 你的页面,包括 /。 |
当你把客户端挂在 / 上时,GET /
的服务文档就不再公开。这没有问题。客户端可以直接使用上面的路径。
登录后,OpenBot 会把浏览器送回你客户端上的某个路径。默认是
/。你的客户端还必须处理这些返回地址:
- App 授权之后的
/?authorization=<flowId>。接下来调用completeAppAuthorization。请看 App。 - 开发者测试授权之后的
/?developerTest=<testId>。请看开发者工具。
返回路径可以是同源上的任意路径,但 /auth/、/v1/ 和 /development/
下的路径除外。
备份下面这些东西,并把它们放在一起:
- 数据库。 它保存平台和组织的设置、账户、组织及其成员、用户令牌、模型和模型提供方、SSO 连接、审计日志、Bot、Chat 及其历史,以及 App 连接。
OPENBOT_SECRET_KEYS。 这些密钥用来解密数据库中的机密:App 密钥、模型提供方密钥、SSO 客户端密钥和登录密钥。没有这些密钥,数据库备份无法恢复这些机密。- 文件的 bucket。 它保存人们上传的文件的字节。数据库只记录它们的名字。
使用 Compose 时,这样备份数据库:
docker compose --env-file .env.production -f deploy/docker/compose.production.yaml \ exec -T postgres pg_dump -U openbot -Fc openbot > openbot-$(date +%F).dump恢复时,先用
docker compose --env-file .env.production -f deploy/docker/compose.production.yaml stop openbot
停止 OpenBot。然后运行 pg_restore:
docker compose --env-file .env.production -f deploy/docker/compose.production.yaml \ exec -T postgres pg_restore -U openbot -d openbot --clean < openbot-2026-10-20.dumpGitHub Actions
Section titled “GitHub Actions”此开发任务请参见 发布和检查项目.