Skip to content

Control UI 是 OpenClaw Gateway 内置的浏览器管理页面,默认在 http://localhost:18789/ 提供。首次从新浏览器连接需通过 openclaw devices approve 完成设备配对;支持 Tailscale Serve HTTPS 访问和 13 种语言界面;可直接在浏览器中操作聊天(含实时语音对话)、频道状态、会话覆盖、Dreams、定时任务、技能与节点、exec 批准、配置编辑与验证、日志实时跟踪及更新重启。配置表单包含 base-hash 并发保护、SecretRef 只读显示、Schema 驱动渲染与原始 JSON 编辑器。

OpenClaw Control UI 浏览器界面:访问、配对与配置指南

快速打开(本地)

如果 Gateway 运行在同一台计算机上,直接在浏览器访问:

若页面加载失败,先启动 Gateway:openclaw gateway

认证方式通过 WebSocket 握手携带以下凭据之一:

  • connect.params.auth.token(共享密钥令牌)
  • connect.params.auth.password
  • Tailscale Serve 身份头(当 gateway.auth.allowTailscale: true 时)
  • 可信代理头(当 gateway.auth.mode: "trusted-proxy" 时)

设置面板会为当前浏览器标签和选定的 Gateway URL 保存令牌;密码不会被持久化。初次连接时,引导流程通常会自动生成一个 Gateway 令牌,但密码认证在 gateway.auth.mode 设为 "password" 时也能工作。

设备配对(首次连接)

当从新浏览器或设备连接 Control UI 时,Gateway 通常会要求一次性配对批准,以防止未授权访问。

表现形式: WebSocket 报错 "disconnected (1008): pairing required"

批准步骤:

  1. 列出待处理请求:
    bash
    openclaw devices list
  2. 按请求 ID 批准:
    bash
    openclaw devices approve <requestId>

如果浏览器在配对前改变了认证详情(角色/范围/公钥),之前的待处理请求会被取代,并生成新的 requestId,批准前应重新运行 openclaw devices list

已批准的设备会被记住,除非通过 openclaw devices revoke --device &lt;id&gt; --role &lt;role&gt; 吊销,否则无需重新配对。详见 Devices CLI

注意事项:

  • 本地回环连接(127.0.0.1 / localhost)自动获批,无需配对。
  • Tailscale Serve 中,如果 gateway.auth.allowTailscale: true 且浏览器带有设备身份,操作员会话可跳过配对;但无设备身份的浏览器或节点角色连接仍需正常配对。
  • 每个浏览器配置文件会生成唯一的设备 ID,切换浏览器或清除浏览器数据会重新触发配对。

个人身份(浏览器本地)

Control UI 支持每个浏览器独立的个人身份(显示名称和头像),附加在发出的消息上,用于共享会话中的归属。此设置存储在浏览器存储中,仅对当前浏览器配置文件有效,不会同步到其他设备,也不会持久化在服务端(除了实际发送消息时的作者元数据)。清除站点数据或切换浏览器会重置为空。

助理头像覆盖也遵循相同规则:上传的助理头像仅覆盖本地浏览器,不会通过 config.patch 回传到网关。共享配置字段 ui.assistant.avatar 仍可供非 UI 客户端(如脚本网关或自定义面板)直接写入。

运行时配置端点

Control UI 从 /__openclaw/control-ui-config.json 拉取运行时设置。该端点受与 HTTP 表面相同的网关认证保护:未认证的浏览器无法获取,成功获取需要有效的网关令牌/密码、Tailscale Serve 身份或可信代理身份。

语言支持

Control UI 在首次加载时根据浏览器语言自动本地化。之后可通过 Overview -> Gateway Access -> Language 手动切换(语言选择器在 Gateway Access 卡片内,不在 Appearance 下)。

  • 支持的语言:en, zh-CN, zh-TW, pt-BR, de, es, ja-JP, ko, fr, ar, it, tr, uk, id, pl, th, vi, nl, fa
  • 非英语翻译在浏览器中延迟加载。
  • 所选语言保存在浏览器存储中,下次访问自动复用。
  • 缺失的翻译键回退到英语。

文档翻译覆盖相同的非英语语言集,但文档站点内置的 Mintlify 语言选择器仅支持 Mintlify 接受的代码。泰语 (th) 和波斯语 (fa) 的文档仍在发布仓库中生成;在 Mintlify 支持这些代码前,它们可能不会出现在选择器中。

外观主题

Appearance 面板提供内置的 Claw、Knot、Dash 主题,以及一个浏览器本地的 tweakcn 导入插槽。要导入主题,打开 tweakcn 编辑器,选择或创建主题,点击 Share,然后将复制的主题链接粘贴到 Appearance。导入器还接受 https://tweakcn.com/r/themes/&lt;id&gt; 注册表 URL、编辑器 URL(如 https://tweakcn.com/editor/theme?theme=amethyst-haze)、相对路径 /themes/&lt;id&gt;、原始主题 ID 以及默认主题名称(如 amethyst-haze)。

Appearance 还包含浏览器本地的文字大小设置。此设置与其他 Control UI 偏好一起存储,应用于聊天文本、编辑器文本、工具卡片和聊天侧边栏,并保持文本输入至少 16px,防止移动 Safari 聚焦时自动缩放。

导入的主题仅存储在当前浏览器配置文件中,不会写入网关配置,也不会跨设备同步。替换导入主题会更新本地插槽;清除导入主题后,如果之前选择的是导入主题,则活动主题会回退到 Claw。

当前功能

聊天与语音对话

  • 通过 Gateway WebSocket 与模型聊天(chat.history, chat.send, chat.abort, chat.inject)。
  • 聊天历史请求限制在最近的一个窗口内,并对每条消息有文本大小上限,避免大会话导致浏览器渲染完整转录时卡死。
  • 语音对话:支持浏览器实时会话。OpenAI 使用直接 WebRTC,Google Live 使用通过 WebSocket 获得的单次约束令牌,后端实时语音插件使用 Gateway 中继传输。客户端拥有的提供商会话以 talk.client.create 开始;Gateway 中继会话以 talk.session.create 开始。中继将提供者凭据保留在 Gateway 上,同时浏览器通过 talk.session.appendAudio 流式传输麦克风 PCM,并通过 talk.client.toolCall 转发工具调用。
  • 在聊天中流式显示工具调用及实时工具输出卡片(代理事件)。

频道、实例、会话、Dreams

  • 频道:内置 + 捆绑/外部插件频道的状态、二维码登录、每频道配置(channels.status, web.login.*, config.patch)。频道探测刷新时,会保留上一个快照直到慢的提供者检查完成;部分快照会在 UI 预算超时时标记。
  • 实例:存在列表及刷新(system-presence)。
  • 会话:默认列出已配置代理的会话,并从过期的未配置代理会话键回退,支持每会话的模型/思考/快速/详细/跟踪/推理覆盖(sessions.list, sessions.patch)。
  • Dreams:做梦状态、启用/禁用切换、梦日记读取(doctor.memory.status, doctor.memory.dreamDiary, config.patch)。

Cron 定时任务、技能、节点、Exec 批准

  • Cron 任务:列表/添加/编辑/运行/启用/禁用 + 运行历史(cron.*)。
  • 技能:状态、启用/禁用、安装、API 密钥更新(skills.*)。
  • 节点:列表 + 能力(node.list)。
  • Exec 批准:编辑网关或节点允许列表 + exec host=gateway/node 的询问策略(exec.approvals.*)。

配置

  • 查看/编辑 ~/.openclaw/openclaw.jsonconfig.get, config.set)。
  • 带验证的应用 + 重启,并唤醒最后活跃的会话(config.apply)。
  • 写入操作包含基础哈希防护,防止并发编辑冲突。
  • 写入前预检提交配置载荷中的活跃 SecretRef 解析;未解析的提交引用会被拒绝。
  • 表单保存会丢弃无法从已保存配置恢复的陈旧占位符,同时保留仍映射到已保存机密的值。
  • Schema + 表单渲染(config.schema / config.schema.lookup),包括字段 title / description、匹配的 UI 提示、直接子项摘要、嵌套对象/通配符/数组/组合节点的文档元数据,以及插件 + 频道 schema(如果有);原始 JSON 编辑器仅在快照能安全往返时可用。
  • 如果快照无法安全往返,Control UI 强制使用表单模式并禁用原始模式。
  • 结构化 SecretRef 对象值在表单文本输入中以只读方式呈现,防止意外对象到字符串损坏。

调试、日志、更新

  • 调试:状态/健康/模型快照 + 事件日志 + 手动 RPC 调用(status, health, models.list)。
  • 事件日志:包含 Control UI 刷新/RPC 计时、慢聊天/配置渲染计时,以及浏览器长动画帧或长任务条目(当浏览器暴露这些 PerformanceObserver 条目类型时)。
  • 日志:实时跟踪网关文件日志,支持过滤/导出(logs.tail)。
  • 更新:运行包/git 更新 + 重启(update.run),附带重启报告,重连后轮询 update.status 验证运行中的网关版本。

Cron 任务面板详细说明

  • 对于隔离任务,投递默认设为通告摘要;如果只想要内部运行,可以改为无投递。
  • 选择通告时显示频道/目标字段。
  • Webhook 模式使用 delivery.mode = "webhook"delivery.to 设为有效 HTTP(S) Webhook URL。
  • 对于主会话任务,webhook 和无投递模式均可用。
  • 高级编辑控件包括:运行后删除、清除代理覆盖、cron 精确/交错选项、代理模型/思考覆盖、尽力投递开关。
  • 表单验证内联显示字段级错误;无效值禁用保存按钮。
  • 设置 cron.webhookToken 可发送专用 bearer token;若省略,发送时不带认证头。
  • 弃用回退:存储了 notify: true 的旧版任务在迁移前仍可使用 cron.webhook

聊天行为

发送和历史语义

  • chat.send非阻塞 的:立即以 { runId, status: "started" } 确认,响应通过 chat 事件流式传输。
  • 上传支持图片及非视频文件:图片保留原生图片路径;其他文件存储为托管媒体,在历史中显示为附件链接。
  • 使用相同 idempotencyKey 重新发送时,运行中返回 { status: "in_flight" },完成后返回 { status: "ok" }
  • chat.history 响应有尺寸限制以确保 UI 安全。当转录条目过大时,Gateway 可能截断长文本字段、省略重型元数据块,并用占位符 [chat.history omitted: message too large] 替换超大消息。
  • 助理/生成图片持久化为托管媒体引用,通过认证的 Gateway 媒体 URL 返回,因此重载不依赖原始 base64 图片负载留在聊天历史中。
  • 在渲染 chat.history 时,Control UI 会从可见助理文本中剥离显示用的内联指令标签(例如 [[reply_to_*]][[audio_as_voice]])、纯文本工具调用 XML 负载(包括 &lt;tool_call&gt;...&lt;/tool_call&gt;, &lt;function_call&gt;...&lt;/function_call&gt;, &lt;tool_calls&gt;...&lt;/tool_calls&gt;, &lt;function_calls&gt;...&lt;/function_calls&gt; 和截断的工具调用块)以及泄漏的 ASCII/全角模型控制令牌,并省略整个可见文本仅为精确静默令牌 NO_REPLY / no_reply 或心跳确认令牌 HEARTBEAT_OK 的助理条目。
  • 在活跃发送及最终历史刷新期间,如果 chat.history 短暂返回较旧的快照,聊天视图会保持本地的乐观用户/助理消息可见;一旦 Gateway 历史追赶,正式转录会替换这些本地消息。
  • 临场 chat 事件是投递状态,而 chat.history 从持久会话转录重建。在工具最终事件后,Control UI 会重新加载历史并只合并一小段乐观尾部;转录边界在 WebChat 中有文档说明。
  • chat.inject 在会话转录中追加助理备注,并广播 chat 事件给 UI(无代理运行,无频道投递)。
  • 聊天头部先显示代理过滤器,再显示会话选择器;会话选择器的范围按所选代理限定。切换代理时只显示该代理的会话,如果没有已保存的面板会话则回退到该代理的主会话。
  • 桌面宽度下,聊天控件保持在一行紧凑布局,向下滚动转录时收起;向上滚动、返回顶部或到达底部时重新显示。
  • 连续重复的纯文本消息合并为一个气泡,并显示计数徽章。包含图片、附件、工具输出或画布预览的消息不合并。
  • 聊天头部的模型和思考选择器通过 sessions.patch 立即修补当前活跃会话;这些是持久的会话覆盖,不是单次发送选项。
  • 如果在同一会话的模型选择更改仍在保存时发送消息,编辑器会等待会话修补完成后再调用 chat.send,确保发送使用所选模型。
  • 输入 /new 会创建并切换到新的空白面板会话(与"新建聊天"相同),但当配置了 session.dmScope: "main" 且当前父会话是代理的主会话时,它会在原地重置主会话例外。输入 /reset 会执行 Gateway 明确的当前会话重置。
  • 聊天模型选择器会请求 Gateway 的已配置模型视图。如果存在 agents.defaults.models,该允许列表驱动选择器,包括 provider/* 条目以保持提供者范围的目录动态。否则,选择器显示显式的 models.providers.*.models 条目加上具有可用认证的提供者。完整目录仍可通过调试 RPC models.list 配合 view: "all" 获取。
  • 当网关会话使用报告包含当前上下文令牌时,聊天编辑器区域会显示一个紧凑的上下文使用指示器。在高上下文压力下切换为警告样式,在推荐压缩水平时显示一个紧凑按钮,用于执行常规会话压缩路径。旧的令牌快照会隐藏,直到网关报告新的使用情况。

语音模式(浏览器实时)

Talk 模式需要注册一个实时语音提供者。配置 OpenAI 需要 talk.realtime.provider: "openai" 加上 talk.realtime.providers.openai.apiKeyOPENAI_API_KEY 或一个 openai-codex OAuth Profile;配置 Google 需要 talk.realtime.provider: "google" 加上 talk.realtime.providers.google.apiKey。浏览器永远不会拿到标准的提供者 API 密钥。OpenAI 收到用于 WebRTC 的临时 Realtime 客户端密钥;Google Live 收到用于浏览器 WebSocket 会话的单次约束 Live API 认证令牌,指令和工具声明由 Gateway 锁定到令牌中。仅暴露后端实时桥的提供者通过 Gateway 中继传输运行,因此凭据和供应商套接字保留在服务端,浏览器音频通过认证的 Gateway RPC 传输。实时会话提示由 Gateway 组装;talk.client.create 不接受调用者提供的指令覆盖。

聊天编辑器在 Talk 启动/停止按钮旁边有一个 Talk 选项按钮。选项适用于下一个 Talk 会话,可以覆盖提供者、传输、模型、语音、推理 effort、VAD 阈值、静音持续时间和前缀填充。当某个选项为空时,Gateway 使用配置的默认值或提供者默认值。选择 Gateway 中继强制使用后端中继路径;选择 WebRTC 保持会话客户端拥有,如果提供者无法创建浏览器会话则失败,不会静默回退到中继。

在聊天编辑器中,Talk 控制是麦克风听写按钮旁边的波形按钮。Talk 启动后,编辑器状态行依次显示 Connecting Talk...Talk live(音频已连接)或 Asking OpenClaw...(实时工具调用正在咨询配置的更大模型)。

维护者实时冒烟测试命令:

bash
OPENAI_API_KEY=... GEMINI_API_KEY=... node --import tsx scripts/dev/realtime-talk-live-smoke.ts

该命令验证 OpenAI 后端 WebSocket 桥、OpenAI 浏览器 WebRTC SDP 交换、Google Live 约束令牌浏览器 WebSocket 设置以及 Gateway 中继浏览器适配器(含虚拟麦克风媒体),只输出提供者状态,不记录密钥。

停止和中止

  • 点击 Stop(调用 chat.abort)。
  • 当有活跃运行时,正常后续消息会排队。点击排队消息上的 Steer 可将该后续注入当前轮次。
  • 输入 /stop 或独立中止短语(如 stop, stop action, stop run, stop openclaw, please stop)进行带外中止。
  • chat.abort 支持 { sessionKey }(不带 runId)以中止该会话的所有活跃运行。

中止部分保留

  • 运行中止时,部分助理文本仍可在 UI 中显示。
  • 当存在缓冲输出时,Gateway 会将中止的部分助理文本持久化到转录历史中。
  • 持久化的条目包含中止元数据,以便转录消费者区分中止部分与正常完成输出。

PWA 安装与 Web Push

Control UI 提供 manifest.webmanifest 和一个 Service Worker,因此现代浏览器可以将其安装为独立 PWA。Web Push 允许 Gateway 唤醒已安装的 PWA 并发送通知,即使标签页或浏览器窗口未打开。

如果 OpenClaw 更新后页面显示 Protocol mismatch,先重新打开面板(openclaw dashboard)并硬刷新页面。如果仍然失败,清除面板源站的站点数据或在隐私窗口中测试;旧的标签或浏览器 Service Worker 缓存可能导致更新前的 Control UI 捆绑包与新 Gateway 通信。

文件/路径作用
ui/public/manifest.webmanifestPWA 清单。浏览器会在可访问时提供"安装应用"选项。
ui/public/sw.jsService Worker,处理 push 事件和通知点击。
push/vapid-keys.json(位于 OpenClaw 状态目录下)自动生成的 VAPID 密钥对,用于签署 Web Push 负载。
push/web-push-subscriptions.json持久化的浏览器订阅端点。

可通过环境变量覆盖 VAPID 密钥对(适用于多主机部署、密钥轮换或测试):

  • OPENCLAW_VAPID_PUBLIC_KEY
  • OPENCLAW_VAPID_PRIVATE_KEY
  • OPENCLAW_VAPID_SUBJECT(默认为 https://openclaw.ai

Control UI 使用以下作用域限定的 Gateway 方法注册和测试浏览器订阅:

  • push.web.vapidPublicKey — 获取当前 VAPID 公钥。
  • push.web.subscribe — 注册 endpointkeys.p256dh/keys.auth
  • push.web.unsubscribe — 移除已注册的端点。
  • push.web.test — 向调用者的订阅发送测试通知。

TIP

Web Push 与 iOS APNS 中继路径(参见 Configuration 了解中继推送)和现有的 push.test 方法无关,后者面向原生移动配对。

托管嵌入

助理消息可以使用 [embed ...] 短代码内联渲染托管 Web 内容。iframe 沙箱策略由 gateway.controlUi.embedSandbox 控制:

  • strict:禁用托管嵌入内的脚本执行。
  • scripts(默认):允许交互式嵌入,同时保持源隔离;通常适用于自包含的浏览器游戏/小部件。
  • trusted:在 allow-scripts 基础上添加 allow-same-origin,用于有意需要更强权限的同站文档。

示例配置:

json5
{
  gateway: {
    controlUi: {
      embedSandbox: "scripts",
    },
  },
}

WARNING

仅当嵌入文档确实需要同源行为时才使用 trusted。对于大多数代理生成的游戏和交互式画布,scripts 是更安全的选择。

绝对外部的 http(s) 嵌入 URL 默认被阻止。如果你故意希望 [embed url="https://..."] 加载第三方页面,设置 gateway.controlUi.allowExternalEmbedUrls: true

聊天消息宽度

分组聊天消息使用可读的默认最大宽度。宽屏部署可通过设置 gateway.controlUi.chatMessageMaxWidth 覆盖,无需修补打包的 CSS:

json5
{
  gateway: {
    controlUi: {
      chatMessageMaxWidth: "min(1280px, 82%)",
    },
  },
}

该值在到达浏览器前经过验证。支持纯长度和百分比(如 960px82%),以及受限的 min(...), max(...), clamp(...), calc(...), fit-content(...) 宽度表达式。

Tailnet 访问(推荐)

集成 Tailscale Serve(首选)

将 Gateway 保留在回环接口,让 Tailscale Serve 用 HTTPS 代理:

bash
openclaw gateway --tailscale serve

打开:https://&lt;magicdns&gt;/(或你配置的 gateway.controlUi.basePath)。

默认情况下,当 gateway.auth.allowTailscaletrue 时,Control UI/WebSocket Serve 请求可通过 Tailscale 身份头(tailscale-user-login)进行认证。OpenClaw 通过 tailscale whois 解析 x-forwarded-for 地址并与头部匹配来验证身份,且仅当请求通过 Tailscale 的 x-forwarded-* 头到达回环时才接受。对于带有浏览器设备身份的 Control UI 操作员会话,此已验证的 Serve 路径还会跳过设备配对往返;无设备浏览器的请求和节点角色连接仍遵循常规设备检查。如果要求即使对 Serve 流量也使用显式共享密钥凭据,设置 gateway.auth.allowTailscale: false(随后使用 gateway.auth.mode: "token""password")。无令牌的 Serve 认证假定网关主机是可信的;如果主机上可能运行不可信的本地代码,则需要令牌/密码认证。

对于异步 Serve 身份路径,同一客户端 IP 和认证范围的失败认证尝试会在速率限制写入前序列化。因此,同一浏览器的并发错误重试可能显示 retry later,而不是两个并行不匹配。

绑定到 tailnet + 令牌

bash
openclaw gateway --bind tailnet --token "$(openssl rand -hex 32)"

打开:http://&lt;tailscale-ip&gt;:18789/(或你配置的 gateway.controlUi.basePath)。将匹配的共享密钥粘贴到 UI 设置中(作为 connect.params.auth.tokenconnect.params.auth.password 发送)。

不安全 HTTP

如果通过纯 HTTP(http://&lt;lan-ip&gt;http://&lt;tailscale-ip&gt;)打开面板,浏览器运行在非安全上下文中并阻止 WebCrypto。默认情况下,OpenClaw 阻止没有设备身份的 Control UI 连接。

已登记的例外:

  • 设置 gateway.controlUi.allowInsecureAuth=true 后,仅 localhost 不安全 HTTP 兼容。
  • 通过 gateway.auth.mode: "trusted-proxy" 的成功操作员 Control UI 认证。
  • 紧急情况:gateway.controlUi.dangerouslyDisableDeviceAuth=true

推荐修复: 使用 HTTPS(Tailscale Serve)或在本地打开 UI:

  • https://&lt;magicdns&gt;/(Serve)
  • http://127.0.0.1:18789/(在网关主机上)

不安全认证切换行为

json5
{
  gateway: {
    controlUi: { allowInsecureAuth: true },
    bind: "tailnet",
    auth: { mode: "token", token: "replace-me" },
  },
}

allowInsecureAuth 仅是本地兼容性切换:允许 localhost 的 Control UI 会话在非安全 HTTP 上下文中无设备身份继续;不会绕过配对检查;不会放宽远程(非 localhost)设备身份要求。

紧急情况专用

json5
{
  gateway: {
    controlUi: { dangerouslyDisableDeviceAuth: true },
    bind: "tailnet",
    auth: { mode: "token", token: "replace-me" },
  },
}

WARNING

dangerouslyDisableDeviceAuth 禁用 Control UI 设备身份检查,是严重的安全降级。紧急使用后请尽快恢复。

可信代理说明

  • 成功的可信代理认证可让操作员 Control UI 会话无需设备身份接入。
  • 这不适用于节点角色 Control UI 会话。
  • 同主机回环反向代理仍不满足可信代理认证;参阅 Trusted proxy auth

关于 HTTPS 设置指南,见 Tailscale

内容安全策略

Control UI 使用严格的 img-src 策略:只允许 同源 资源、data: URL 和本地生成的 blob: URL。远程 http(s) 和协议相对图片 URL 会被浏览器拒绝,不发网络请求。

实际效果:

  • 以相对路径提供的头像和图片(例如 /avatars/&lt;id&gt;)仍可渲染,包括 UI 获取并转为本地 blob: URL 的认证头像路由。
  • 内联 data:image/... URL 仍可渲染。
  • Control UI 创建的本地 blob: URL 仍可渲染。
  • 频道元数据发出的远程头像 URL 会在 Control UI 的头像辅助函数中剥离,替换为内置徽标/徽章,因此被入侵或恶意的频道无法强制从操作员浏览器加载任意远程图片。

此行为始终开启,不可配置。

头像路由认证

当配置了网关认证时,Control UI 头像端点需要与 API 其他部分相同的网关令牌:

  • GET /avatar/<agentId> 仅对已认证调用者返回头像图片。GET /avatar/<agentId>?meta=1 在相同规则下返回头像元数据。
  • 未认证请求到这两个路由都会被拒绝(与同级助理媒体路由一致),防止在受保护主机上泄露代理身份。
  • Control UI 本身在获取头像时,作为 bearer 头发送网关令牌,并使用认证的 blob URL 以确保在面板中正常渲染。

如果禁用网关认证(不建议在共享主机上),头像路由也会变为未认证,与网关其他部分一致。

助理媒体路由认证

当配置了网关认证时,助理本地媒体预览使用两步路由:

  • GET /__openclaw__/assistant-media?meta=1&source=&lt;path&gt; 需要常规的 Control UI 操作员认证。浏览器在检查可用性时,发送网关令牌作为 bearer 头。
  • 成功的元数据响应包含一个短期 mediaTicket,作用域限于该确切源路径。
  • 浏览器渲染的图片、音频、视频和文档 URL 使用 mediaTicket=&lt;ticket&gt; 而不是活动网关令牌或密码。票证很快过期,不能用于授权其他源。

这样,媒体渲染可与浏览器原生媒体元素兼容,无需将可重复使用的网关凭据放在可见的媒体 URL 中。

构建 UI

Gateway 从 dist/control-ui 提供静态文件。构建方式:

bash
pnpm ui:build

可选绝对基础路径(当你需要固定资源 URL 时):

bash
OPENCLAW_CONTROL_UI_BASE_PATH=/openclaw/ pnpm ui:build

本地开发(独立开发服务器):

bash
pnpm ui:dev

然后将 UI 指向你的 Gateway WS URL(如 ws://127.0.0.1:18789)。

空白 Control UI 页面

如果浏览器加载面板为空白且 DevTools 没有有用错误,可能是扩展或早期内容脚本阻止了 JavaScript 模块应用求值。静态页面包含一个纯 HTML 恢复面板,当 &lt;openclaw-app&gt; 在启动后未注册时出现。

改变浏览器环境后,使用面板的 Try again 操作,或手动重新加载前进行以下检查:

  • 禁用注入所有页面的扩展,尤其是带有 &lt;all_urls&gt; 内容脚本的扩展。
  • 尝试隐私窗口、干净的浏览器配置文件或其他浏览器。
  • 保持 Gateway 运行,验证浏览器更改后同一面板 URL。

调试/测试:开发服务器 + 远程 Gateway

Control UI 是静态文件;WebSocket 目标可配置,可以与 HTTP 来源不同。当你希望 Vite 开发服务器在本地运行但 Gateway 在其他地方时很方便。

  1. 启动 UI 开发服务器:pnpm ui:dev
  2. 打开带 gatewayUrl 参数的 URL:
    http://localhost:5173/?gatewayUrl=ws%3A%2F%2F<gateway-host>%3A18789
    可选一次性认证(如需要):
    http://localhost:5173/?gatewayUrl=wss%3A%2F%2F<gateway-host>%3A18789#token=<gateway-token>

注意事项:

  • gatewayUrl 加载后存储在 localStorage 中并从 URL 中移除。
  • 如果通过 gatewayUrl 传递完整的 ws://wss:// 端点,务必对 gatewayUrl 值进行 URL 编码。
  • token 应尽可能通过 URL 片段(#token=...)传递。片段不会发送到服务器,避免请求日志和 Referer 泄漏。旧版 ?token= 查询参数作为回退一次性导入,立即引导后会被清除。
  • password 仅保存在内存中。
  • 设置 gatewayUrl 时,UI 不会回退到配置或环境凭据。必须显式提供 token(或 password)。缺少显式凭据是错误。
  • Gateway 在 TLS 后面时(Tailscale Serve、HTTPS 代理等)使用 wss://
  • gatewayUrl 仅在顶级窗口(非嵌入)中被接受,防止点击劫持。
  • 非回环 Control UI 部署必须显式设置 gateway.controlUi.allowedOrigins(完整来源)。私有同源 LAN/Tailnet 从回环、RFC1918/链路本地、.local.ts.net 或 Tailscale CGNAT 主机的加载会被接受,无需启用 Host-header 回退。
  • Gateway 启动时可能根据实际运行时绑定和端口播种本地来源(如 http://localhost:&lt;port&gt;http://127.0.0.1:&lt;port&gt;),但远程浏览器来源仍需要显式条目。
  • 不要使用 gateway.controlUi.allowedOrigins: ["*"],除非是严格控制的本地测试环境。这意味着允许任何浏览器来源,而不是"匹配我使用的任何主机"。
  • gateway.controlUi.dangerouslyAllowHostHeaderOriginFallback=true 启用 Host-header 来源回退模式,但这是一个危险的模式。

示例配置:

json5
{
  gateway: {
    controlUi: {
      allowedOrigins: ["http://localhost:5173"],
    },
  },
}

远程访问设置详情:Remote access

相关

常见问题

为什么每次换浏览器或清缓存都需要重新配对?

Control UI 使用设备身份验证防止未授权访问。每个浏览器配置文件生成唯一的设备 ID——切换浏览器、使用无痕模式或清除浏览器存储会产生新的设备 ID,因此需要重新配对。本地回环连接(127.0.0.1/localhost)是例外,自动批准无需配对。

语言选择器在哪里?支持哪些语言?

语言选择器在 Overview → Gateway Access → Language 内(不是 Appearance 下)。支持 20 种语言:en, zh-CN, zh-TW, pt-BR, de, es, ja-JP, ko, fr, ar, it, tr, uk, id, pl, th, vi, nl, fa。非英语翻译延迟加载,缺失键回退到英语。

在不安全 HTTP 下 Control UI 无法连接怎么办?

在不安全上下文(如 http://&lt;tailscale-ip&gt;)中,浏览器阻止 WebCrypto,默认连接会被阻止。推荐方案:使用 HTTPS(Tailscale Serve)或在本地通过 http://127.0.0.1:18789/ 访问。紧急情况下可设置 gateway.controlUi.allowInsecureAuth=true(仅限 localhost)或使用 gateway.auth.mode: "trusted-proxy";更极端的 dangerouslyDisableDeviceAuth=true 会严重降级安全,紧急使用后应尽快恢复。