部署团队服务器
本指南将生产环境团队部署的各部分串联起来:一个持久化的 Gateway、Cloudflare Tunnel 与 Access、个人登录、GitHub 身份、操作者角色,以及可选地从另一个 Gateway 进行只读共享。先从一台服务器开始。当需要不同的凭据、更新时机或操作者时,再添加独立的发布或暂存服务器。
更简短的协作演练请参阅 团队设置。本指南使用 team.example.com 作为协作域名,release.example.com 作为可选的第二个 Gateway。请将它们替换为你自己的主机名;每个 Gateway 都需要自己的配置和状态。
我们如何用 OpenClaw 构建 OpenClaw¶
我们使用 team.openclaw.ai 作为 OpenClaw 自身的共享开发工作区。维护者和 agent 在同一个会话中推进仓库变更:
- 启动一个仓库任务。 在 New conversation 中选择 OpenClaw 项目,并选择 Worktree 以获得受管分支与检出。给 agent 一个具体的变更以及证明其有效的检查项。
- 协同工作。 具有访问权限的队友可以打开会话、添加上下文,并引导下一轮操作。为后续跟进分配所有者;创建者和参与者的归属保持分离。
- 审查工作。 检查 agent 的结果和检出差异,运行相关测试,并在落地前解决审查发现的问题。
- 发布并跟踪 CI。 检查选定的 GitHub 发布账户后,使用 Publish PR。关联的拉取请求及其 CI 详情会保留在会话中。
该截图显示了一个实时仓库任务,画面被裁剪至其会话范围。有关 diff、文件和 PR 控件,请参阅聊天与代码审查。
构建下一个版本并不会替换正在运行的服务器。我们让部署拥有自己的审批流程和生命周期负责人,并协调激活与验证。请参阅让运维可恢复。
开始之前¶
- 一台具有持久化存储和专用服务账户的 Linux 主机。使用受支持的 Node 运行时和 OpenClaw 安装。
- 一个由 Cloudflare 管理的域名、Zero Trust 账户,以及主机上的
cloudflared。 - 一个身份提供者,以及一份明确允许哪些人登录的策略。
- 模型凭据,以及(如果需要)一个用于团队聊天的机器人账户。
- 管理 SSH 访问、私有机密存储,以及一个位于服务器故障域之外的备份目标。
Gateway 是一个信任边界。角色和会话所有权支持协作;它们不会将恶意用户彼此隔离。将不受信任的代码放在沙箱或远程 worker 中。对于互不信任的团队,请使用单独的 Gateway、操作系统用户或主机。请参阅多租户托管。
1. 在单一服务账户下安装¶
以将要运行 Gateway 的账户完成入门指南,包括模型设置和托管服务安装:
后续的配置、备份和更新命令也应在同一账户下执行。之后以 root 身份运行安装会创建不同的主目录,并可能选择不同的 Gateway。请在服务与维护环境中保留任何自定义的 OPENCLAW_STATE_DIR、OPENCLAW_CONFIG_PATH 和 profile 选择器。在 Linux 上,请验证用户服务在注销后仍然可用;请参阅 Gateway 服务管理。
仅允许来自你管理网络的 SSH。将 Gateway 保持在 loopback 上,不要公开打开 TCP 18789。Cloudflare Tunnel 发起的是出站连接;它不需要入站的 Gateway 防火墙规则。
选择一个 agent ID,例如 assistant,并在频道绑定和角色 agent 列表中一致地使用它。下面的示例假定该 agent 已经存在。保持共享工作区说明的简洁,并将部署机密排除在 AGENTS.md、IDENTITY.md 和个人说明之外。
2. 配置公共 URL 和经身份验证的入口¶
在暴露隧道之前,为 team.example.com 创建 Access 应用程序。最初仅允许将完成设置的管理员访问。选择由你计划使用的身份提供者支持的 Access 策略;不要为 Control UI 或其 WebSocket 创建公共绕过规则。
按照 Cloudflare Tunnel 与 Access 创建隧道和 DNS 记录。其 ingress 应仅将所选主机名路由到 loopback Gateway:
tunnel: <tunnel-id>
credentials-file: /etc/cloudflared/<tunnel-id>.json
ingress:
- hostname: team.example.com
service: http://localhost:18789
- service: http_status:404
保护隧道凭据文件,并将 cloudflared 作为服务运行。使用 SecretRef 保有一个私有的本地维护密码;下面的示例期望 OPENCLAW_GATEWAY_PASSWORD 同时可用于 Gateway 服务和所属账户的 CLI。不要将该密码分发给队友:本地密码访问代表着共享的所有者。
将以下内容合并到现有配置中,同时保留你的 agent、模型和频道:
{
gateway: {
mode: "local",
bind: "loopback",
publicOrigin: "https://team.example.com",
trustedProxies: ["127.0.0.1", "::1"],
auth: {
mode: "trusted-proxy",
password: { source: "env", provider: "default", id: "OPENCLAW_GATEWAY_PASSWORD" },
identityScopes: {
"admin@example.com": ["operator.admin"],
},
trustedProxy: {
userHeader: "cf-access-authenticated-user-email",
requiredHeaders: ["cf-access-jwt-assertion"],
allowLoopback: true,
deviceAutoApprove: {
enabled: true,
scopes: ["operator.read", "operator.write", "operator.approvals", "operator.questions"],
},
},
},
roles: {
default: "observer",
definitions: {
observer: {
sessions: { others: "view" },
agents: [],
scopes: ["operator.read"],
},
member: {
sessions: { others: "write" },
agents: ["assistant"],
scopes: ["operator.read", "operator.write", "operator.approvals", "operator.questions"],
},
administrator: {
sessions: { others: "write" },
agents: "*",
scopes: ["operator.admin"],
},
},
},
},
}
切换到可信代理身份验证时,移除任何早前的 gateway.auth.token 和 OPENCLAW_GATEWAY_TOKEN:共享 Token 与此模式不兼容。支持私有本地密码回退。验证配置,然后使用所属服务的生命周期来激活配置更改:
allowLoopback 会信任本地进程以及 cloudflared。OpenClaw 会检查代理来源和必需请求头;这些字段的存在并不等同于 Access JWT 签名验证。外部身份验证边界是 Access 加上私有源。不要运行可以访问此监听器的恶意工作负载。有关请求头和客户端地址要求,请参阅 可信代理身份验证。
一次性设置公共 URL¶
publicOrigin 告诉 OpenClaw 要对外宣传哪个外部 URL,并提供默认的浏览器源允许列表。对于从同一源提供的 Control UI,请保持 gateway.controlUi.allowedOrigins 未设置。
仅当需要不同的浏览器策略(例如单独托管的 Control UI)时,才设置显式的 allowedOrigins 列表。显式列表会替换公共源默认值;如果两者都应连接,也请包含公共源。显式空列表不会继承 publicOrigin。现有的本地和私有网络源规则仍然适用。
如果没有 gateway.publicOrigin,浏览器可能仍可工作,但代理的会话查找没有链接构建规则,其运行时上下文也没有会话 URL。设置不带路径、查询或凭据的纯 HTTPS 源。如果 Control UI 使用路径前缀,请单独配置 gateway.controlUi.basePath。
对于仅缺少此设置的现有服务器:
此条件写入拒绝覆盖现有值。启用实时配置重载后,公共源无需重启 Gateway 即可生效。当允许列表被继承时,使用旧源的浏览器必须从被接受的源重新连接。显式允许列表保持不变。新准备的工具上下文会接收链接规则;已在运行的回合可以保留其较早的上下文。在第二台服务器上设置 https://release.example.com,而不是复制第一台服务器的 URL。
现有安装会保留其显式允许列表,包括早期设置或 Doctor 运行保存的值。升级到具有此默认值的版本后,如果你希望它遵循 publicOrigin,请使用 openclaw config unset gateway.controlUi.allowedOrigins 删除该列表;首先检查是否不需要额外的 UI 源。启动和 Doctor 会将继承的默认值排除在已保存配置之外。
3. 引导管理员并分配角色¶
让管理员通过 Access 登录一次。其持久 Gateway 用户资料会被创建,初始为 observer 角色。从本地维护 shell 中列出用户资料并识别已验证人员:
openclaw users list --json
openclaw gateway call users.setRole \
--params '{"profileId":"<administrator-profile-id>","role":"administrator"}' \
--json
角色更改会关闭该人员当前活动的 Gateway 连接。重新连接浏览器。管理员需要显式的 identityScopes 授权和管理员角色上限。本地共享 owner 仍可用于维护,并且不能被分配个人角色。
将 Access 策略扩展到团队。每位成员首次登录后,通过相同方法为其用户资料分配 member 角色。observer 可以读取可见会话,但在此示例中不能启动代理工作。不要为了引导某人而临时将默认角色设为管理员。
该示例有意自动批准具有非管理员范围的 UI 设备,然后通过其角色限制每个人。如果你希望手动设备注册,请省略自动批准。不要将 operator.admin 添加到自动设备授权中;请改用选定的已验证身份。有关更窄的仅限会话和需要沙箱的角色,请参阅 操作员范围。
对于发布 Gateway,保持 observer 默认值并只分配少数发布操作员会很有用。角色分配对每个 Gateway 都是本地的;被协作服务器接纳不会授予发布权限。
4. 使用已验证的 GitHub 身份同步人员¶
保持这些职责分离:
| 职责 | 配置或所有者 |
|---|---|
| 谁可以访问网站 | Cloudflare Access 及其身份提供商 |
| 谁已登录 | 已验证登录和 Gateway 用户资料 |
| 该人员可以执行哪些操作 | 连接范围和命名操作员角色 |
| 哪个账户发布代码 | 系统、代理或个人 GitHub 连接 |
在 Access 中使用 GitHub 身份提供商时,OpenClaw 会查询 Access 的身份端点,验证其电子邮件是否与已认证的代理主体匹配,并将不可变的数字 GitHub 账户 ID 解析为其当前登录名。之后,姓名和头像可以通过正常的登录/用户资料同步进行更新。已保存的自定义用户资料选择仍由 用户模型 管理。
这是由登录驱动的同步,而不是后台导入每个 GitHub 组织成员。用户资料和角色对每个 Gateway 都是本地的。同一个已验证的 GitHub 账户可以在两台服务器上识别同一个人,而无需使他们的本地用户资料 ID 相等。
使用 OIDC 提供商而不丢失现有用户资料¶
OIDC 登录可以通过其已验证的电子邮件保留现有用户资料。在更改提供商或电子邮件地址之前,从管理员的维护会话中将新的已验证地址链接到现有人员:
在切换登录之前,还需将新的已验证地址添加到该人员所需的任何 gateway.auth.identityScopes 授权中。对于上述管理员,新地址需要拥有自己的 ["operator.admin"] 条目:关联电子邮件会保留个人资料和角色,但不会复制旧地址的作用域授权。根据需要更新任何 Access 策略或 trustedProxy.allowUsers 电子邮件允许列表。在迁移期间保留旧授权,使用新地址重新连接后,验证个人资料、别名、角色和有效权限,然后如果该身份不应再拥有访问权限,则停用旧授权。不要通过显示名称合并人员,也不要在线服务器之间复制个人资料数据库。
对于通过 OIDC 获得的已验证 GitHub 署名,请配置 Cloudflare OIDC 设置 中描述的显式 cloudflareAccessOidc 颁发者、提供商 ID 和账户 ID 声明。提供商必须验证关联的 GitHub 账户,并且 Access 必须转发其数字账户 ID 声明。用户名或任意 OIDC 主体都不是已验证的 GitHub 账户 ID。冲突需要管理员关联;该声明不会分配角色,也不会更改发布代码的账户。
如果准入取决于 GitHub 组织成员身份或仓库权限,请在 Access 或身份提供商中强制执行该要求。针对 GitHub IdP 的组织策略不会自动覆盖单独的 OIDC IdP。了解资格何时重新检查,并在移除必须在正常过期前生效时撤销现有 Access 会话。
为仓库工作配置 GitHub 访问¶
为 Gateway 服务账户安装 gh。在 设置 → 个人资料 → GitHub 连接 中,管理员选择 为系统 以连接共享发布账户。代理可以在 代理 → 工具 下拥有管理员覆盖。发布前请验证所选账户。
我的 GitHub 是一个独立的个人连接,用于明确选择的发布。它不会更改共享 shell 账户,也不会建立已验证的登录身份。Git 共同作者署名也是独立的:它使用已验证的人类参与者及其保存的同意偏好。
使用 Gateway 的 发布 PR 操作作为其托管发布路径。托管身份不会重写现有本地仓库的 SSH 远程或 Git 网络凭据。成功的账户验证也不能证明对每个仓库都有写入权限。参见 代理工具的 GitHub 身份。
可选的 gateway.controlUi.github.token 用于 GitHub 查询和项目发现。请将其保存在专用 SecretRef 中,而不是通过进程范围的 GH_TOKEN 或 GITHUB_TOKEN 意外选择发布者。读取凭据、发布凭据和每个人的登录身份各有不同职责。
5. 连接聊天和远程客户端¶
按照 团队设置 配置频道允许列表、提及要求和 DM 配对。网站准入不会配置机器人的频道允许列表。如果频道发送者应解析为现有人员,请使用 用户模型 中明确由管理员证明的频道身份链接;匹配的显示名称是不够的。
浏览器 Cookie 不会认证 CLI、TUI 或节点连接。远程 CLI 客户端需要 gateway.remote.edgeAuth 和它们自己的 Access 登录;参见 远程访问。
节点和云工作器需要一个路由,用于认证每个必需的加入、WebSocket 和传输请求。优先使用 Cloudflare 机器访问 中的 Access 服务令牌设置。当浏览器可以工作而 openclaw connect 收到 HTTP 302 时,这意味着机器请求到达了 Access,而不是节点配对成功。请将机器凭据排除在浏览器链接之外,并且不要为整个 Gateway 绕过 Access。
6. 为组件提供独立的沙箱源¶
内联 Canvas 组件和 MCP Apps 使用独立的沙箱监听器。在 HTTPS 入口后面,请配置第二个主机名以到达该监听器,而不是让浏览器尝试通过端口 18790 访问 Gateway 的公共主机名:
为 team-sandbox.example.com 创建单独的代理 DNS CNAME,指向 <tunnel-id>.cfargotunnel.com,然后在隧道入口的 catch-all 规则之前添加 team-sandbox.example.com -> http://localhost:18790,如果不同则使用已配置的沙箱端口。仅添加入口规则不会创建 DNS 记录。参见 Cloudflare 的 隧道 DNS 路由。请将此主机名放在交互式 Access 应用之外,并且只将其路由到沙箱监听器,绝不路由到主 Gateway。沙箱提供隔离的渲染器 shell;经过身份验证的组件内容通过 Gateway 传输。不要将其他经过身份验证的应用程序放在沙箱源上。
即使未启用 MCP Apps,Canvas 也可以延迟启动此监听器。仅当你需要该功能时,才单独启用 MCP Apps;参见 MCP Apps。设置完成后,请测试一个真实组件:健康的聊天页面并不能证明其 iframe 可以加载。
7. 从另一个 Gateway 共享选定会话¶
要在协作服务器上显示 release-server 的对话,请配置 Session Share。在源端,使用显式组启用该插件:
{
plugins: {
entries: {
"session-share": {
enabled: true,
config: { share: { groups: ["Team"] } },
},
},
},
}
在接收端,上述配置的 gateway.publicOrigin 会在回环 Gateway 没有其他已通告路由时提供加入端点。对于上述 Access 服务令牌拓扑,请使用相同的 HTTPS 主机名。如果你运营一个独立的经过身份验证的机器端点,请改为将 plugins.entries.device-pair.config.publicUrl 设置为该 URL:
连接码在回退到 publicOrigin 之前,会保留现有的 Tailscale、远程和 bind 派生路由。特定配对的 publicUrl 覆盖项优先于发现机制。核心连接码的创建不需要启用 device-pair 插件。参见节点接入。
在源端,使用源 Gateway 的账户、状态目录和配置运行节点,且仅使用这两条只读会话命令:
openclaw connect <join-url> --service \
--commands openclaw.sessions.list.v1,openclaw.sessions.read.v1
在接收端批准目标设备,并确认这两条命令的允许列表。将选定的源会话移入 Team 组。子代理和隐身会话仍被排除。移除该组会撤销新的读取,但无法收回已被他人阅读的文本。
接收端的 linkGitHubIdentities: true(为配对的节点 ID 配置)可以将经过验证的远程 GitHub 账户 ID 显示为匹配的本地个人资料。这是归属说明,而非角色或所有权授予。该视图保持只读;它不授权继续源会话或在那里执行命令。普通源会话 URL 仍指向该源自身的 publicOrigin,并且需要源访问权限。
8. 验证完整流程¶
同时使用主机检查和两个真实用户账户:
- 以服务所有者身份运行
openclaw config validate --json、openclaw gateway status --deep和openclaw security audit。解决意外暴露。 - 确认未认证的公共请求能够通过 Access,然后登录并访问已连接的 Control UI。仅凭 Access 重定向并不能证明 Gateway 健康。
- 确认两个人的个人资料各不相同,管理员/成员行为正确,观察者限制生效。更改角色后重新连接。
- 让代理提供当前会话的链接和另一个可见会话的链接。打开两者并检查主机和目标。缺少链接规则时会指向
publicOrigin,而不是allowedOrigins。 - 执行一个模型轮次、预期的频道回复、一个(如果启用了的)小组件,以及一个(如果使用了的)节点连接。在请求发布之前,检查所选的 GitHub 账户和实际的仓库权限。
- 如果共享会话,请从接收端读取选定的源对话,然后从源组中移除一个一次性的共享会话,并确认接收端新的读取请求被拒绝。
保持操作可恢复¶
每次安装使用一个生命周期所有者。对于常规托管安装,请使用 openclaw update 和原生 Gateway 服务命令。如果外部部署系统拥有该服务,请改用该所有者;不要用第二个更新器、直接重启或就地源码构建与它竞争。与团队协调中断时间,并在激活后验证服务版本。参见更新和重启恢复。
协作服务器和发布服务器可以有意识地采用不同的更新计划。让每项策略明确;复制配置不应在另一台服务器上静默启用自动部署。通过 gateway.controlUi.environment 保持视觉环境标签的区分。
在进行重大更新之前,创建并验证备份:
openclaw backup create --verify
openclaw backup restore <archive.tar.gz> --target <fresh-restore-directory>
restore 命令会暂存恢复数据;激活它是单独的离线操作。保护凭据,并保留一份主机外副本。使用原生备份所有者的 SQLite 快照,而不是复制实时数据库/WAL 文件。不要用旧快照覆盖当前数据库来回滚运行中的服务器。参见备份。
为依赖项、构建、SQLite 快照验证和备份预留持久磁盘和临时空间。根磁盘有大量空闲空间并不能帮助 /tmp 的小配额。在实际服务环境中配置所需的临时空间,而不仅仅是在 SSH shell 中。在 Btrfs 上,除了 df,还要检查元数据分配和保留的快照:快照可能在文件删除后固定占用空间。仅清理已知的一次性数据和已完成的恢复点。
监控进程重启、就绪状态、频道连接、存储以及真实的会话/模型故障。将事件警报放在可能宕机的 Gateway 之外。HTTP 根路径显示绿色、机器人保持安静或 Access 登录成功,都不足以证明服务能够完成工作。
故障排除¶
| 症状 | 检查 |
|---|---|
| 浏览器正常;代理无法提供会话链接 | 设置此服务器的 gateway.publicOrigin;重新加载后准备一个新轮次。 |
| Access 成功但 Gateway 拒绝连接 | 检查回环信任、转发的客户端地址、所需的身份标头以及 allowedOrigins。 |
| 管理员以观察者身份登录 | 为真实个人资料分配管理角色,并授予已验证身份 operator.admin,然后重新连接。 |
| OIDC 迁移创建了另一个人 | 验证登录电子邮件,并将其别名显式链接到现有个人资料。 |
| GitHub 登录看起来正确,但发布使用了另一个账户 | 分别检查系统/代理/个人发布选择以及仓库 Git 身份验证。 |
| 聊天正常但小组件失败 | 检查该主机名上不同的沙箱来源、隧道端口,以及是否没有交互式 Access 挑战。 |
| ``` |
| 症状 | 检查 |
|---|---|
| 节点加入时收到 HTTP 302 | 在每个必需路由上提供机器 Access 身份验证。 |
| 共享会话缺失或名称未关联 | 检查源组、节点账户/状态、双命令允许列表、接收方角色以及已验证的数字 GitHub ID。 |
| 磁盘空间充足但更新失败 | 重试前,检查服务临时空间配额、文件系统元数据和保留的快照。 |
本页原文 Markdown:在 AtomGit 查看·内容源自开源项目 cl/openclaw