部署
本页介绍如何在生产环境中运行 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 连接登录,可以跳过这一项。 - 一个模型服务,如果你想让 Agent(智能体)干活的话。设置完成后,通过 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。
用文件提供密钥
OpenBot 先从环境变量读取每个设置。如果没有设置该变量,OpenBot 就改读文件 /run/secrets/<NAME>,例如 /run/secrets/OPENBOT_SECRET_KEYS。Docker 和 Compose 就把密钥放在这里。空文件视为未设置。请看配置。
环境变量会出现在 docker inspect 中。/run/secrets 中的文件不会。Compose 对所有密钥都使用文件。
用 Docker 运行
把设置写进一个文件,例如 openbot.env。它只需要 OPENBOT_DATABASE_URL 和 OPENBOT_SECRET_KEYS。可以从 deploy/docker/production.env.example 开始。docker run 不会替换 ${POSTGRES_PASSWORD},所以请自己写出完整的 OPENBOT_DATABASE_URL。
生成一次密钥:
echo "OPENBOT_SECRET_KEYS=k1:$(openssl rand -hex 32)" >> openbot.env请看密钥。
准备数据库
迁移程序只需要 OPENBOT_DATABASE_URL。在启动服务器之前运行它。每次发布新版本之前,也要再运行一次:
docker run --rm --env-file openbot.env \ openbot:$OPENBOT_RELEASE /app/dist/app/Migrate.mjs多次运行它是安全的。它只应用数据库还没有的迁移。 迁移只能向前。没有办法撤销迁移,所以请先做备份。
设置平台
在新数据库上运行一次设置程序:
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
你也可以在服务器上直接用 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-migrate、openbot-setup 和 openbot。
用 Compose 运行
文件 deploy/docker/compose.production.yaml 运行以下服务:
| 服务 | 镜像 | 主机上的端口 |
|---|---|---|
postgres |
postgres:18-alpine,数据在卷 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。Compose 从 .env.production 读取它们的值。
openbot 服务只拿到 OPENBOT_DATABASE_URL 和 OPENBOT_SECRET_KEYS。它没有其他环境变量,因为其他所有设置都存放在数据库中。migrate 服务只拿到 OPENBOT_DATABASE_URL。
在模板中,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_KEYS在 .env.production 中填写这些值。
构建两个镜像
export OPENBOT_RELEASE=$(git rev-parse HEAD)TAG=$OPENBOT_RELEASE docker buildx bake -f deploy/docker/docker-bake.hcl --load检查设置
docker compose --env-file .env.production -f deploy/docker/compose.production.yaml config --quiet缺少必需的设置时,它会显示错误。不加 --quiet 时,它会打印填好所有值的完整配置。
启动全部服务
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,备份数据库,然后再次运行 up -d --wait。新的 OpenBot 启动前,migrate 会再次运行。
不要删除 postgres 卷。它保存着你的全部数据。
多个实例
你可以在一个负载均衡器后面运行多个 OpenBot 实例。给每个实例:
- 相同的
OPENBOT_DATABASE_URL, - 相同的
OPENBOT_SECRET_KEYS。
其他什么都不需要。所有共享设置都存放在数据库中。管理员修改设置后,每个实例会立即使用新设置。请看配置。 迁移程序和设置程序只运行一次,不要在每个实例上都运行。
TLS 和反向代理
在生产环境中,由反向代理处理 HTTPS,并把流量转发给 127.0.0.1:8080 上的 OpenBot。
OPENBOT_TLS_CERT 和 OPENBOT_TLS_KEY 留空。
代理必须:
- 把
Origin、Cookie和Authorization头原样转发给 OpenBot, - 不缓冲响应,因为 Turn 可以用服务器发送事件(SSE)流式输出,
- 允许长时间的响应。
GET /v1/sessions/:id/wait最多可以等待 30 秒,而一个流会持续到它的 Turn 结束。
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 / { 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 { reverse_proxy 127.0.0.1:8080 { flush_interval -1 }}同源的自有客户端
与 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 连接、审计日志、Session 及其 Timeline,以及 App 连接。
OPENBOT_SECRET_KEYS。 这些密钥用来解密数据库中的机密:App 密钥、模型提供方密钥、SSO 客户端密钥和登录密钥。没有这些密钥,数据库备份无法恢复这些机密。
使用 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
工作流 .github/workflows/ci.yml 有两个作业。第一个作业通过后,第二个作业才会运行。
| 作业 | 做什么 |
|---|---|
check |
在 devenv shell 中运行 pnpm build、pnpm typecheck 和 pnpm -r test。 |
images |
构建、检查、扫描并发布 Docker 镜像。 |
两个作业都在 ubuntu-latest 上运行。它们先用 Determinate Nix 安装器安装 Nix,再安装 devenv 2.4.0。Magic Nix Cache 把 Nix 的构建结果存进 GitHub Actions 缓存,所以之后的运行不必再构建它们。作业还会从 devenv.cachix.org 下载预先构建好的 devenv 包。check 作业把 pnpm 存储放在缓存中。
images 作业执行以下步骤:
- hadolint 和
docker buildx bake lint检查Dockerfile。后者运行 Docker 构建检查。 - Docker Bake 构建两个镜像。构建层保存在 GitHub Actions 缓存中,每个镜像一份缓存,所以之后的运行只构建有变化的部分。
deploy/docker/check.sh检查镜像。请看检查镜像。- dive 检查镜像层没有浪费空间。
- Trivy 扫描两个镜像。如果镜像有已知的、已有修复的
HIGH或CRITICAL漏洞,作业就会失败。Trivy 看不到 Node.js 的版本,因为 Node.js 是复制进镜像的,不是作为软件包安装的。 - 作业把两个镜像保存为
images-<commit-sha>制品,保留七天。 - 对于推送,作业会发布镜像。它使用构建缓存,所以不会再构建一次。
工作流在拉取请求、推送到 main 以及 v1.2.3 这样的标签时运行。它只在推送时发布镜像:
| 事件 | 发布的标签 |
|---|---|
推送到 main |
<commit-sha> 和 latest |
v1.2.3 这样的标签 |
<commit-sha> 和 v1.2.3 |
镜像发布到 GitHub 容器仓库,地址是 ghcr.io/openbot-build/openbot 和 ghcr.io/openbot-build/openbot/protocol-test。工作流不会部署 OpenBot。要在 Compose 中使用已发布的镜像,请拉取它,并打上 openbot:<tag> 标签。
发布文档网站
工作流 .github/workflows/docs.yml 把文档网站发布到 GitHub Pages,地址是 openbot.build。每次推送到 main 时它都会运行。你也可以在 Actions 标签页中手动启动它。
| 作业 | 做什么 |
|---|---|
build |
在 devenv shell 中运行 pnpm --filter "@openbot-build/docs..." build。这会构建文档及其需要的包。 |
deploy |
把 packages/docs/dist 发送到 GitHub Pages。 |
build 作业把 DOCS_URL 设为 https://openbot.build。Astro 用它生成完整的页面链接,例如站点地图。同一时间只运行一个部署。
仓库设置必须把 Pages 的来源设为 GitHub Actions,并把 openbot.build 设为自定义域名。openbot.build 的 DNS 必须指向 GitHub Pages。请看 Manage a custom domain。
检查镜像
deploy/docker/check.sh 用测试设置启动 compose.production.yaml。额外的文件 compose.check.yaml 去掉主机端口,并添加两个服务。setup 服务在 migrate 之后、openbot 启动之前,用测试值运行设置程序。check 服务运行检查。check.env 保存测试设置。其中没有任何真实的密钥。
check 服务在 OpenBot 和协议测试服务都健康之后,在 Compose 网络中运行 check.mjs。它检查:
- 不带密钥和带错误密钥时,
/v1/sessions都返回401, /openapi.json正常工作,- 协议测试的 Catalog 有正确的公开源,
- 协议测试服务上的 MCP 发现正常工作。
所以这项检查也证明,迁移、设置程序、密钥文件和健康检查在真实的生产配置中都能正常工作。最后,脚本会删除容器和测试数据库。
在你的电脑上运行同样的检查:
devenv shell -- pnpm imagesdevenv shell -- pnpm images:checkdevenv shell -- hadolint deploy/docker/Dockerfiledevenv shell -- dive --ci --source docker openbot:localdevenv shell -- trivy image --scanners vuln --severity HIGH,CRITICAL --ignore-unfixed openbot:local