在 VPS 上自托管 OpenBot AI 协作者
了解如何自托管 OpenBot,为每个 AI 协作者配置独立容器、Chromium 浏览器和工作区,并掌握网关如何逐项检查操作,以及每个机器人需要多少内存。
自托管 OpenBot AI 协作者的资源需求
您可以在自己控制的硬件上运行一个网关服务器,并为每个机器人运行一个容器,从而自托管 OpenBot AI 协作者。每个机器人容器都包含独立的 Chromium 浏览器和工作区卷,并使用可在会话之间持久保存的浏览器配置文件。机器人在计算机、文件、MCP(模型上下文协议)服务器或 UI 组件上执行的每个操作,都会先经过该网关。网关会在操作执行前根据策略进行检查,并在执行后记录操作。如果您还不熟悉网关所封装的代理循环,可以按照从头学习 AI 代理中的分阶段路径,先自行编写一个简单的代理循环,再为机器人提供浏览器和登录凭据。
OpenBot 由 CopilotKit 根据 MIT 许可证发布,项目地址为 github.com/CopilotKit/openbot。首个带标签的版本 v0.0.1 于 17 August 2026 发布。项目将自身描述为 alpha 版本,并处于积极开发阶段。请将其视为设计严谨但仍存在早期版本限制的软件。
该架构中最有价值的部分,也是成本最高的部分。每个代理都需要一个浏览器,这是许多人规划时最容易忽略的内存成本。因此,本教程会先进行容量规划,再开始安装。
网关如何决定每项操作
3001 端口上的 API 服务器是访问 bot 计算机的唯一通道。在浏览器操作执行前,网关会根据页面快照解析目标,针对上下文评估 CEL(通用表达式语言)策略规则,写入包含决策的审计记录,然后才调用容器。如果之后执行失败,网关会再写入第二条记录。文档明确说明了这一边界:计算机不负责决定策略,服务器网关才是操作边界。OpenBot 之外有一个名称可以描述这种分工,因为循环、工具定义、权限检查和会话状态共同构成了包裹模型的工具框架,而此网关是其中负责权限的部分。
策略默认拒绝,并且先评估拒绝规则,再评估允许规则。失败方向比规则语法更重要。缺少策略不会允许任何操作;规则损坏时,无论是拒绝规则还是允许规则,结果都会趋向阻止。因此,策略中的错误会让 bot 卡住,而不会让 bot 不受限制地访问您的账户。这一层控制 bot 执行的操作,而不控制 bot 读取的内容。因此,包含面向代理指令的页面仍是另一个独立问题,也就是您在将自建 SearXNG 实例的结果交给代理时面临的同一种提示注入攻击面。
审计记录存储在 PostgreSQL 中,因此重启后仍会保留。控制权交接记录为 computer.help_requested、computer.control_taken 和 computer.control_released。通过这些记录,您可以看到 bot 请求人工介入,也可以看到人工将控制权交还。如果记录机密信息,则只记录字符数,绝不记录具体值。文件操作记录路径和大小,绝不记录文件内容。如果您希望在没有浏览器的情况下使用相同的控制边界,在 AI 代理操作前设置审批门禁介绍了这一更具体的场景。
单个 Bot 的内存和磁盘开销
该项目公布了 arm64 架构下单个 Bot 的实测数据。这是 OpenBot 提供的唯一容量数据,描述的是单个架构上的单个 Bot,因此应将其作为起点,而不是容量规划依据。
The data behind this chart
[
{
"label": "Measured, one Bot",
"memory_gb": 0.55,
"disk_gb": 5.3,
"vcpu": 0.06
},
{
"label": "Documented minimum",
"memory_gb": 2,
"disk_gb": 8,
"vcpu": 1
},
{
"label": "Documented recommended",
"memory_gb": 4,
"disk_gb": 10,
"vcpu": 2
}
]单个 Bot 的峰值内存实测为 0.55 GB,文档记录的最低要求为 2 GB,建议值为 4 GB。实测值与最低要求之间的差额,是为 Chromium 在负载下增长预留的空间,因为浏览器的内存使用量取决于已打开的页面,而不是空闲进程的内存占用。空闲 CPU 使用量接近于零,在实测范围的最高值也只有 0.06 个核心,因此需要重点规划的是磁盘,而不是 CPU。镜像本身占用 5.3 GB,而建议卷大小为 10 GB。镜像较大的原因是其中除 Chromium 外,还包含 Playwright 的 Firefox 和 WebKit 二进制文件。
这些数据无法说明同时运行多个 Bot 的开销,项目也没有公布相关数据。文档中的最低要求,是项目方愿意公布的数值,不代表有人在负载下实际监测过。这也是为什么 在 PhotoPrism 和 Immich 之间进行选择时,应参考实测的内存下限,而不是文档公布的数值。请自行测量。启动一个 Bot,为它分配一个打开页面的真实任务,然后在运行期间监控容器。
docker stats --no-stream
free -m将 Bot 容器的 MEM USAGE 列作为单个 Bot 的开销,在此基础上加上网关和 PostgreSQL 的开销,再将单个 Bot 的开销乘以预计同时存在的 Bot 数量。空闲 Bot 仍会保留浏览器进程,因此乘数适用于所有已存在的 Bot,而不仅是正在处理任务的 Bot。计算方式与 为 coding agent VPS 规划 RAM 和 CPU 中的方法相同,浏览器部分见 在 VPS 上为 agent 运行无头浏览器。
一个 Chromium 细节会影响小型方案。OpenBot 使用 --disable-dev-shm-usage 启动 Chromium,因此浏览器会写入 /tmp,而不是 /dev/shm。这样可以避免在 /dev/shm 较小的主机上发生崩溃,但会将压力转移到根文件系统,这也是建议磁盘容量大于镜像大小的另一个原因。
如何在 VPS 上自行托管 OpenBot?
您需要 Docker、Bun 1.3 或更高版本、CopilotKit Intelligence 项目以及模型 API 密钥。开发文档还要求服务器上安装 lsof、python3 和 curl。请克隆带标签的发行版本,而不是 main,因为 alpha 项目中的 main 可能在不提示的情况下发生变化。
git clone --branch v0.0.1 https://github.com/CopilotKit/openbot.git
cd openbot
cp .env.example .env配置 Intelligence 项目。以下 3 条命令会将运行时密钥和许可证令牌写入环境文件。
npx --yes copilotkit@latest login
npx --yes copilotkit@latest project select
npx --yes copilotkit@latest license --write生成用于加密已存储凭据的密钥,并将输出写入 .env,格式为 KEY_ENCRYPTION_KEY。在同一文件中添加您的 OPENAI_API_KEY,或者将 BOT_PROVIDER 设置为 anthropic 或 google,并配置匹配的密钥。
openssl rand -base64 32然后安装并启动服务。
bun install
bash scripts/start.shscripts/start.sh 会启动 Docker 服务,执行数据库迁移,启动服务器和应用,并检查它们的运行状况。完成后,应用会在端口 3010 上响应,API 会在端口 3001 上响应。该脚本会报告端口冲突,并让已运行且匹配的服务保持不变,因此重复运行是安全的。
在对外暴露任何服务前,先从服务器本身进行检查。
curl -sS -o /dev/null -w '%{http_code}\n' http://127.0.0.1:3010
ss -ltnp | grep -E ':(3010|3001|4100|4500|5432)'第一条命令输出 200,表示应用正在提供服务。第二条命令会显示这些端口绑定到哪些地址;在 VPS 上,这才是需要关注的结果。显示 127.0.0.1:3001 的行表示服务仅对本机可用。显示 0.0.0.0:3001 的行表示任何能够路由到该服务器的主机都可以访问服务。
单容器镜像
部署文档还提供了一个单独的镜像,其中包含应用、API 和 Chromium,并通过 3001 端口提供服务。
docker build -t openbot .
docker run -p 127.0.0.1:3001:3001 --env-file .env \
-e EMBEDDED_POSTGRES=on -v openbot-data:/var/lib/postgresql/data openbotEMBEDDED_POSTGRES=on 会在容器内运行 PostgreSQL,并在启动时执行迁移。命名卷可在重新部署后保留审计历史;如果没有该卷,每次重新构建都会丢失这些历史记录。如果改为让 DATABASE_URL 连接托管数据库,则必须在该数据库上启用 vector 扩展。RDS、Cloud SQL 和 Azure Database 等托管服务都支持该扩展,但不会替您启用它。因此,针对全新的托管数据库执行迁移会失败,因为其中尚不存在 vector 列类型。
如果数据库位于外部,请将迁移作为发布步骤执行。
docker run --rm --env-file .env openbot \
sh -c "cd /app/server && bun x drizzle-kit migrate --config=drizzle.config.ts"该镜像不会发布浏览器端口。这是有意设计的。它也不包含 supervisor,因为 supervisor 需要 Docker socket,而无服务器平台不提供该接口。没有 supervisor,所有 bot 都会共享同一个浏览器,也会共享同一组登录凭据,因此无法实现按 bot 隔离;而这正是运行独立 bot 容器的意义所在。如果您需要为每个 bot 使用独立登录凭据,请在接受这一权衡的主机上设置 COMPUTER_SUPERVISOR_URL 和 SUPERVISOR_TOKEN,然后运行 compose stack。能够访问 Docker socket 的进程可以启动特权容器,因此实际上就拥有该主机上的 root 权限。基于这一点,最好将 OpenBot 部署在专用机器上,这与为 coding agent 提供一次性 VM的原则相同。
为什么 OPENBOT_SINGLE_USER 只适合在笔记本电脑上使用
.env.example 随附 OPENBOT_SINGLE_USER=true。启用该设置后,所有请求都会被视为来自同一个管理员,并完全跳过登录。在笔记本电脑上,这很方便,因为只有您自己的客户端可以访问该端口。在 VPS 上,这意味着第一个访问 3010 端口的人就会成为该系统的管理员,而该系统存储加密凭据,并驱动一个已经登录您各个账户的浏览器。
运行它有两种合理方式。保留 OPENBOT_SINGLE_USER=true,将每个端口绑定到 127.0.0.1,然后只通过 SSH 隧道或专用网络接口访问应用。
ssh -N -L 3010:127.0.0.1:3010 -L 3001:127.0.0.1:3001 you@your-vps这样,您可以在自己的浏览器中通过 http://localhost:3010 访问应用。浏览器会将其视为安全上下文,因此登录 Cookie 和实时界面所需的浏览器功能都可以正常工作。另一种方式是关闭单用户模式,并配置真正的身份提供商。支持 Google、Microsoft Entra、Okta、SAML 和 OIDC。无论使用哪种提供商,都需要将 BETTER_AUTH_SECRET 设置为至少 32 个字符,将 BETTER_AUTH_URL 设置为 OAuth 回调使用的公共 API 基础 URL,并配置 INITIAL_ADMIN_EMAILS 和 TRUSTED_ORIGINS。提供商凭据必须完整,因为配置不完整的提供商会阻止应用启动,而不会回退到开放访问模式。如果添加账户的原因是团队中的每个人都希望拥有自己的代理,而不是各自使用独立的浏览器,OneCLI 从设计之初就采用了这种模式:每个人使用一个隔离的代理,模型密钥统一保存在单个网关中。
如果应用可通过公共域名访问,请在其前面配置 TLS(传输层安全)。除 localhost 外,在任何位置通过纯 http:// 提供的页面都不是安全上下文,因此标记为 Secure 的 Cookie 不会被存储,登录会失败,而且表现得像是 OpenBot 本身存在缺陷。
对低层端口启用防火墙
OpenBot 的安全说明指出,低层服务端点由令牌保护,应保持私有,不应利用它们绕过网关。令牌是第二道防护。第一道防护是让端口完全无法访问。
agent-computer 监听 4100,并要求 COMPUTER_TOKEN。机器人端点监听 4200 和 4201。supervisor 在主机上监听 4500,在其容器内监听 4300。PostgreSQL 监听 5432。这些端口都不应绑定到公网接口;在单用户部署中,应用和 API 也不应绑定到公网接口。
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 22/tcp
sudo ufw enable
sudo ufw status verbose这里有一个容易误导使用者的陷阱:不能认为启用防火墙就足够了。使用 -p 3001:3001 发布容器端口时,Docker 会安装 DNAT 规则,因此流量会经过 FORWARD 路径,而不会经过由 ufw 默认拒绝策略控制的 INPUT 链。此时,即使 ufw status 仍显示 Status: active,端口也依然处于开放状态。在端口映射本身中将发布的端口绑定到 loopback,例如 -p 127.0.0.1:3001:3001;也可以在 compose 文件中设置主机地址。使用 ss -ltnp 验证,不要使用 ufw status。这个陷阱并非 OpenBot 特有,因此请对主机上发布的其他每个容器运行相同检查,包括提供 重建为 90 年代录像店的 Jellyfin 媒体库 的容器。
OpenBot 不是离线技术栈
在规划部署之前先明确这一点。OpenBot 依赖 CopilotKit Intelligence 项目,该项目会在服务器之外保存持久化线程和对话记忆。服务器启动时会验证 INTELLIGENCE_API_URL、INTELLIGENCE_GATEWAY_WS_URL、INTELLIGENCE_API_KEY 和 COPILOTKIT_LICENSE_TOKEN,这 4 项必须同时存在,否则启动会失败。截至 2026 年 8 月,CopilotKit 提供免费计划。Intelligence 本身也支持自托管,因此可以实现完全本地化部署,但所需工作量会超过快速入门示例中的内容。
模型是第二个外部依赖。该软件包不附带模型。BOT_PROVIDER 接受 openai、anthropic 或 google,而 OPENAI_BASE_URL 会将 OpenAI 路径指向任意兼容的端点。如果希望令牌始终留在自己的硬件上,可以参考 在 VPS 上运行 Ollama 以自托管 LLM。浏览器控制对模型的要求较高,因此在确定采用本地模型之前,应先让它完成一项真实任务并进行测试。
暂时运行 1 个副本
网关会将页面快照缓存到服务器进程内存中。运行 2 个副本时,一个进程创建的快照对另一个进程不可见,因此操作会间歇性失败,并显示看似随机的找不到元素错误。部署文档明确要求运行单个副本,并将平台允许的最大实例数固定为 1。快照缓存迁移到数据库后,才可以取消此限制。在此之前,应通过升级服务器配置来扩展 OpenBot,而不是增加服务器数量。Bot 之间仍通过各自的容器实现隔离,方式与 自托管代理沙箱 隔离不同代理的错误相同。
故障模式及其表现
填入 .env 后,启动立即退出。 服务器会先验证配置,然后才提供服务。Intelligence 块不完整、缺少 KEY_ENCRYPTION_KEY,或 OAuth 提供商只有客户端 ID 而没有密钥,都会导致启动停止,而不是静默降级。读取第一条错误信息,修复对应字段,然后再次启动。
在托管数据库上迁移失败。 默认未启用 vector 扩展,因此迁移会遇到 PostgreSQL 无法识别的列类型。以超级用户身份连接,运行 CREATE EXTENSION vector;,然后重新执行迁移步骤。
应用可以加载,但登录状态始终无法保持。 您在公网地址上通过普通 http:// 提供服务,这不是安全上下文,因此浏览器会丢弃 Secure cookie。请在前端配置 TLS,或使用 SSH 隧道,让浏览器看到 localhost。
本应彼此独立的机器人共享登录状态。 supervisor 未运行,因此没有按机器人分配的计算机,所有机器人都使用共享浏览器。确认已设置 COMPUTER_SUPERVISOR_URL,并确认 supervisor 可以访问 Docker socket。
机器人停止并请求帮助。 这表示设计正常运行。审计记录会记录 computer.help_requested,您可以接管实时屏幕,交接过程也会在双方记录。
FAQ
将 OPENBOT_SINGLE_USER 保持启用用于 VPS 部署是否安全?
仅当网关无法从互联网访问时才安全。OPENBOT_SINGLE_USER=true 会在不要求登录的情况下,将每个请求都视为同一个管理员发出的请求。因此,任何能够打开该端口的人,都可以控制整个部署、其中存储的凭据以及该管理员已登录的浏览器。将所有端口绑定到 127.0.0.1,并通过 SSH 隧道或专用网络接口访问应用时,可以接受这种配置。在公网接口上应将其关闭,并配置 Google、Microsoft Entra、Okta 或 OIDC,同时设置 BETTER_AUTH_SECRET、BETTER_AUTH_URL、INITIAL_ADMIN_EMAILS 和 TRUSTED_ORIGINS。
一个 OpenBot bot 需要多少 RAM?
项目发布的单个 arm64 Bot 数据显示,其峰值内存为 0.55 GB,文档记录的最低值为 2 GB,建议值为 4 GB。目前没有多个 bot 同时运行时的公开数据,因为每个 bot 都会单独运行一个 Chromium。让一个 bot 执行实际任务,在 docker stats 中读取其容器的内存用量,再加上网关和数据库的内存用量,最后乘以预计同时运行的 bot 数量。
自托管 OpenBot 是否需要 CopilotKit 帐户?
需要。OpenBot 依赖 CopilotKit Intelligence 项目来持久化线程和记忆。除非设置 Intelligence API URL、网关 WebSocket URL、API key 和 license token,否则服务器不会启动。截至 August 2026,CopilotKit 提供免费计划;Intelligence 也支持自托管,因此通过额外工作可以移除这项托管依赖。您还必须提供自己的模型 API key,因为 OpenBot 不附带任何模型。
为什么每个 bot 都使用独立浏览器,而不是共享一个浏览器?
因为浏览器配置文件代表一个身份。共享浏览器意味着共享 cookie 和会话,因此一个 bot 登录某个帐户后,所有 bot 都会登录该帐户。每个 bot 使用独立容器后,每个协作者都有自己的配置文件和登录信息。代价是内存占用增加,因为每个 bot 使用一个 Chromium,这是资源评估中占用最大的单项。
防火墙应开放哪些 OpenBot 端口?
底层端口都不应开放。agent-computer 使用的 4100 端口、bot 端点使用的 4200 和 4201 端口、supervisor 使用的 4500 端口,以及 PostgreSQL 使用的 5432 端口,都应保持私有。项目通过 token 保护这些端口,并要求您无论如何都不要让它们可访问。只发布用户需要打开的端口。还要注意,使用 -p 3001:3001 发布的容器端口不受 ufw 默认拒绝规则限制,因为 Docker 的 DNAT 规则会将该流量放入 FORWARD 路径,而不是 INPUT。