OpenClaw Gateway 发现机制与传输方式详解:Bonjour、Tailscale 与 SSH 的多路径连接方案
【免费下载链接】openclawThe AI that really does things. Any OS. Any Platform. The lobster way. 🦞项目地址: https://gitcode.com/GitHub_Trending/cl/openclaw
OpenClaw 将"发现"拆解为两个既相关又彼此独立的问题:操作者远程控制(macOS 菜单栏 App 控制运行在其他主机上的 Gateway)与节点配对(iOS/Android 节点发现 Gateway 并安全配对)。本指南围绕 docs/gateway/discovery.md 展开,系统讲解 Gateway 的 Direct WS 与 SSH 两类传输方式、Bonjour/DNS-SD 广播信标(beacon)的 TXT 记录细节、Tailnet 跨网发现策略,以及客户端如何按策略选择传输路径。读完本文,你将掌握discovery.mdns.mode、OPENCLAW_DISABLE_BONJOUR、OPENCLAW_SSH_PORT等配置项的完整语义,并能在真实部署中判断何时该用 LAN 直连、何时回退 SSH。
两个发现问题的本质区别
OpenClaw 的发现体系服务于两种完全不同的场景:
- 操作者远程控制:macOS 菜单栏 App 需要连接运行在其他主机上的 Gateway(例如家庭台式机或 VPS 上的常驻实例)。
- 节点配对:iOS/Android(以及未来的节点形态)需要发现某个 Gateway 并与之安全配对,把节点能力挂接到 Gateway 拥有的会话上。
这两类问题共享同一套底层设施,但关注点不同:操作者关心的是"如何到达我的 Gateway",节点关心的是"如何发现并信任一个 Gateway"。所有网络发现/广播能力都集中在 Gateway(openclaw gateway)一侧实现,macOS App 与 iOS/Android 节点只是消费者,自身不广播任何服务。
核心术语
| 术语 | 含义 |
|---|---|
| Gateway | 单个长期运行进程,拥有会话(sessions)、配对(pairing)、节点注册表(node registry)等状态,并运行各渠道(channels)。多数部署一台主机一个 Gateway;也支持隔离的多 Gateway 配置 |
| Gateway WS(控制面) | WebSocket 端点,默认监听127.0.0.1:18789;可通过gateway.bind绑定到局域网/tailnet |
| Direct WS transport | 面向 LAN/tailnet 的 Gateway WS 端点(不经 SSH 转发) |
| SSH transport(fallback) | 通过 SSH 转发127.0.0.1:18789实现远程控制,作为兜底方案 |
协议层面的细节见 Gateway protocol。
为什么 Direct WS 与 SSH 同时存在
两种传输不是互相替代的关系,而是覆盖不同网络条件的互补方案:
- Direct WS 是同一网络与 tailnet 内的最佳体验:同 LAN 下通过 Bonjour 自动发现,配对 token 与 ACL 由 Gateway 全权掌控,无需任何 shell 访问权限。
- SSH 是普适兜底:只要你有 SSH 访问权限就能工作,即使跨无关网络也能连通;它能绕过组播 mDNS 无法跨网、部分 Wi-Fi 禁用组播等常见问题,且除 SSH 端口外不需要开放任何新的入站端口。
从部署实践看,SSH 通道的典型用法是 docs/gateway/remote.md 中的一行命令:
ssh -N -L 18789:127.0.0.1:18789 user@gateway-host隧道建立后,openclaw health、openclaw status --deep以及openclaw gateway status/health/probe/call(配合--url)都能经由ws://127.0.0.1:18789触达远端 Gateway。
发现输入之一:Bonjour / DNS-SD
Bonjour(mDNS/DNS-SD)是 OpenClaw 在同一局域网内发现 Gateway 的主要手段。需要注意它的边界:组播 Bonjour 是尽力而为(best-effort)的,且不能跨网络。为此 OpenClaw 同时支持通过配置的广域 DNS-SD 域(unicast DNS-SD,即 Wide-Area Bonjour)浏览同一个 Gateway 信标,使发现范围同时覆盖同 LAN 的local.与可跨网的配置域。详细的排障与信标说明见 Bonjour discovery。
启用后,Gateway 通过随附的bonjour插件广播其 WS 端点;客户端浏览并展示"选择一个 Gateway"列表,随后应用各自的连接信任策略。在 macOS 上,选择一个候选只会打开连接编辑器,不会直接保存该广播端点——最终连接仍需用户确认。
服务信标细节
- 服务类型:
_openclaw-gw._tcp(Gateway 传输信标)。 - TXT 键(均为非机密提示):
| Key | 说明 |
|---|---|
role=gateway | 始终存在 |
transport=gateway | 始终存在 |
displayName=<name> | 操作者配置的显示名 |
lanHost=<hostname>.local | 仅 LAN mDNS 广播者写入;广域 DNS-SD 不写此键 |
gatewayPort=18789 | Gateway WS + HTTP 端口 |
gatewayTls=1 | 仅当 TLS 启用时存在 |
gatewayTlsSha256=<sha256> | 仅当 TLS 启用且存在指纹时存在 |
tailnetDns=<magicdns> | 可选提示;检测到 Tailscale 时自动生成 |
sshPort=<port> | 仅当discovery.mdns.mode="full"时存在;默认"minimal"模式下省略(SSH 默认22),LAN 广播者与广域 DNS-SD 均如此 |
cliPath=<path> | 与sshPort相同的discovery.mdns.mode="full"门槛;作为 CLI 路径的远程安装提示 |
在源码层面,这些 TXT 键由 extensions/bonjour/src/advertiser.ts 构建:txtBase始终写入role、gatewayPort、lanHost、displayName,仅在gatewayTlsEnabled时追加gatewayTls/gatewayTlsSha256,仅在非 minimal 模式(!opts.minimal)下追加tailnetDns、cliPath,而transport=gateway与sshPort属于 gateway 服务自身的 TXT。对应地,advertiser.test.ts 中有一条专门用例断言minimal 模式下sshPort、cliPath、tailnetDns均为undefined。
安全要点
- Bonjour/mDNS 的 TXT 记录未经认证。客户端必须只把 TXT 值当作 UX 提示,绝不能当作权威路由信息。
- 路由(host/port)应优先使用解析后的服务端点(SRV + A/AAAA),而不是 TXT 提供的
lanHost、tailnetDns或gatewayPort。 - TLS 固定(pinning)绝不允许让广播的
gatewayTlsSha256覆盖先前已存储的固定值。 - iOS/Android 节点在所选路由为安全/TLS 路径时,存储首次固定值前应要求用户明确"信任此指纹"确认(带外验证)。
启用、禁用与覆盖
openclaw plugins enable bonjour启用 LAN 组播广播。openclaw.json中的discovery.mdns.mode控制 mDNS 广播:"minimal"(默认,只发核心 TXT 键)、"full"(向 LAN 信标与广域 DNS-SD 区域追加cliPath/sshPort)、"off"(禁用 mDNS)。OPENCLAW_DISABLE_BONJOUR=1强制禁用广播;discovery.mdns.mode="off"可独立禁用。OPENCLAW_DISABLE_BONJOUR=0是显式 opt-in,可覆盖插件在检测到容器(Docker、containerd、Kubernetes、LXC)内的自动禁用;但它不能覆盖discovery.mdns.mode="off"。随附bonjour插件在 macOS 主机上自动启动(enabledByDefaultOnPlatforms: ["darwin"],见 openclaw.plugin.json),并在检测到容器时自动禁用;Linux、Windows 及其他容器化部署需显式plugins enable bonjour。~/.openclaw/openclaw.json中的gateway.bind控制 Gateway 绑定模式。OPENCLAW_SSH_PORT覆盖广播的 SSH 端口(仅在discovery.mdns.mode="full"时生效)。OPENCLAW_TAILNET_DNS发布tailnetDns提示(MagicDNS)。OPENCLAW_CLI_PATH覆盖广播的 CLI 路径。
从源码看,OPENCLAW_DISABLE_BONJOUR的解析逻辑位于 advertiser.ts:未设置返回null(交由后续判定),真值(true/1/yes/on等经isTruthyEnvValue)返回true,0/false/no/off返回false。容器的自动禁用判定(isContainerEnvironment)综合三类信号:Fly.io 机器环境变量(FLY_MACHINE_ID+FLY_APP_NAME)、常见容器哨兵文件(/.dockerenv、/run/.containerenv、/var/run/.containerenv)以及/proc/1/cgroup中的 docker/containerd/kubepods/lxc 特征串(advertiser.ts)。测试 advertiser.test.ts 分别验证了容器自动禁用、Fly 机器自动禁用与OPENCLAW_DISABLE_BONJOUR=0显式 opt-in 三种路径。
另外,插件入口 index.ts 通过api.registerGatewayDiscoveryService注册广播服务,并把 Gateway 侧提供的gatewayPort、gatewayTlsEnabled、gatewayTlsFingerprintSha256、gatewayDirectReachable、sshPort、tailnetDns、cliPath、minimal等上下文透传给 advertiser。
发现输入之二:Tailnet(跨网络)
对于位于不同物理网络的 Gateway,Bonjour 无能为力。推荐的直接目标是一个 **Tailscale MagicDNS 名称(优先)**或稳定的 tailnet IP。
- 当 Gateway 检测到自己运行在 Tailscale 下时,会发布
tailnetDns作为客户端的可选提示(广域信标同样携带)。 - 对已配置的 macOS 连接,优先信任 MagicDNS 名称而非裸 tailnet IP,这样名称总能解析到当前地址。发现不会替换已保存的地址。
移动节点配对有一条硬性安全规则:发现提示绝不放松 tailnet/公网路由上的传输安全:
- iOS/Android 首次 tailnet/公网连接仍必须走安全路径(
wss://或 Tailscale Serve/Funnel)。 - 发现到的裸 tailnet IP 只是路由提示,不是允许在远端使用明文
ws://的授权。 - 私有 LAN 直连
ws://仍然支持。 - 移动节点最简单的 Tailscale 路径:使用 Tailscale Serve,让发现与设置都解析到同一个安全的 MagicDNS 端点。
发现输入之三:手动 / SSH 目标
当没有直接路由(或直接模式被禁用)时,客户端总可以通过 SSH 转发回环 Gateway 端口来连接,详见 Remote access。这种方式不依赖任何自动发现设施,是最可靠的兜底。
传输选择(客户端策略)
macOS App 使用其已配置的 direct 或 SSH 传输;发现不会替换这条路由,也不会替客户端选择回退方案。新建连接时,用户在连接编辑器中提供受信地址、SSH 目标或设置码并保存。基于发现的客户端选择遵循如下策略:
- 已配置且可达的直连端点 → 使用它。
- 否则,若发现机制在
local.或配置的广域域中找到 Gateway → 为该候选提供设置流程。保存直连端点前应用客户端的信任策略;发现本身不是授权。 - 否则,若配置了 tailnet DNS/IP → 尝试直连。对 tailnet/公网路由上的移动节点,"直连"指安全端点,而非明文远端
ws://。 - 否则 → 回退到 SSH。
配对与认证(Direct transport)
在直连传输下,Gateway 是节点/客户端准入的唯一事实来源:
- 配对请求在 Gateway 中创建/批准/拒绝(见 Gateway pairing)。
- Gateway 强制认证(token/密钥对)、作用域/ACL(它不是到每个方法的裸代理),并实施速率限制。
这意味着发现层只负责"找到并展示候选",真正决定"谁能连"的权力始终收敛在 Gateway 一侧,与前述"TXT 记录未认证、发现不等于授权"的安全模型一脉相承。
各组件职责
| 组件 | 职责 |
|---|---|
| Gateway | 广播发现信标、拥有配对决策、托管 WS 端点 |
| macOS App | 编辑受信 Gateway 连接、展示配对提示、使用已配置的 direct 或 SSH 传输 |
| iOS/Android 节点 | 将 Bonjour 浏览作为便利手段,连接到已配对的 Gateway WS |
深入源码:Bonjour 广播的健壮性设计
结合 extensions/bonjour 插件的实现,可以看到发现广播在工程上的若干细节:
- 服务名与主机名规范:系统主机名若含空格、下划线等非法 DNS label 字符,会回退为
openclaw.local;主机名超过 63 字节 DNS label 上限时按 UTF-8 边界安全截断(advertiser.ts)。测试 advertiser.test.ts 覆盖了非法主机名回退与多字节 CJK 主机名截断场景。也可通过OPENCLAW_MDNS_HOSTNAME显式指定。 - 冲突自动解决:同一主机广播多个 Gateway 时,Bonjour 会追加
(2)、(3)等后缀保持实例名唯一;advertiser 监听name-change/hostname-change事件并记录警告日志(advertiser.ts)。 - 日志降噪:ciao 自探测重试消息与短命 Docker 桥被移除导致的
ENODEV套接字警告被过滤,避免刷爆 Gateway 日志(advertiser.ts)。 - 单一生命周期:OpenClaw 对每个 Bonjour 服务只启动一次,探测、重试、命名冲突解决与接口变更重发布全部交给 mDNS responder,避免在网络抖动时出现重叠发布(对应测试断言广告失败后不会启动竞争性的重试循环,advertiser.test.ts)。
Gateway 的滚动日志(启动时打印gateway log file: ...)中可检索bonjour:前缀行,例如bonjour: advertise failed ...、bonjour: suppressing ciao netmask assertion ...、bonjour: ... name conflict resolved。
实战决策速查
- 同一 LAN:启用
bonjour插件(macOS 自动;Linux/Windows/容器内显式openclaw plugins enable bonjour),客户端浏览_openclaw-gw._tcp local.即可发现。 - 跨物理网络:优先 Tailscale MagicDNS + Tailscale Serve;或配置广域 DNS-SD(
discovery.wideArea.domain,配合openclaw dns setup --apply一次性搭建,见 Bonjour discovery);再不济就用 SSH 隧道。 - 容器/Docker 部署:Bonjour 默认自动禁用,
OPENCLAW_DISABLE_BONJOUR=0仅在 host 网络、macvlan 等 mDNS 组播可用的网络下才应设置;否则保持禁用,走直接 URL、Tailnet 或 SSH。 - 希望广播更多提示(
sshPort/cliPath/tailnetDns):将discovery.mdns.mode设为"full",并配合OPENCLAW_SSH_PORT、OPENCLAW_CLI_PATH、OPENCLAW_TAILNET_DNS覆盖具体值;模式变更可热生效,无需重启 Gateway 或断开客户端。
相关文档
- Remote access — SSH 隧道、CLI 远程默认值与 macOS 持久隧道
- Tailscale — tailnet 直连配置
- Bonjour discovery — mDNS 模式、Docker 注意事项与排障
- Gateway pairing — 节点配对与审批
- Gateway protocol — Gateway WS 协议细节
【免费下载链接】openclawThe AI that really does things. Any OS. Any Platform. The lobster way. 🦞项目地址: https://gitcode.com/GitHub_Trending/cl/openclaw
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考