跳转至

Tailscale

OpenClaw 可以自动为 Gateway 仪表盘和 WebSocket 端口配置 Tailscale Serve(tailnet)或 Funnel(公网)。这样 Gateway 始终保持绑定到 loopback,同时 Tailscale 提供 HTTPS、路由和(对于 Serve)身份头。

Note

正在寻找分步设置?参见 为 Gateway 提供稳定的 HTTPS URL。

模式

gateway.tailscale.mode:

模式 行为
serve 通过 tailscale serve 仅限 Tailnet 的 Serve。Gateway 保持在 127.0.0.1 上。
funnel 通过 tailscale funnel 提供公网 HTTPS。需要共享密码。
off(默认) 不进行 Tailscale 自动化。

对于 OpenClaw 的这种 Serve/Funnel 模式,状态和审计输出使用 Tailscale 暴露。off 表示 OpenClaw 没有管理 Serve 或 Funnel。这并不意味着本地 Tailscale 守护进程已停止或注销。

配置示例

仅 Tailnet(Serve)

{
  gateway: {
    bind: "loopback",
    tailscale: { mode: "serve" },
  },
}

打开:https://<magicdns>/(或你配置的 gateway.controlUi.basePath)

仅 Tailnet(绑定到 Tailnet IP)

使用此配置可让 Gateway 直接监听 Tailnet IP,而不使用 Serve/Funnel:

{
  gateway: {
    bind: "tailnet",
    auth: { mode: "token", token: "your-token" },
  },
}

从另一台 Tailnet 设备连接原生或 CLI 客户端:

  • WebSocket: ws://<tailscale-ip>:18789

浏览器 Control UI 可以通过纯 JavaScript Ed25519 在直接的纯 HTTP 地址上创建并签署设备身份。使用 token/密码认证时,共享密钥仍然不能替代浏览器设备身份。

纯 HTTP 仍是一种降级传输方式:身份签署不会对页面、共享密钥或 Gateway 流量进行加密。更推荐使用 Tailscale Serve 来提供 HTTPS。参见 不安全的 HTTP。

从 Tailnet 地址本身加载 Control UI 是一个私有的同源请求,不需要 gateway.controlUi.allowedOrigins 条目。公共或跨源浏览器部署需要一个允许的来源(allowed origin)。

Note

当存在可绑定的 Tailnet IPv4 时,Gateway 还需要 http://127.0.0.1:18789 供经过认证的同主机客户端使用。如果启动时没有可用的 Tailnet 地址,则仅回退到 loopback。在 Tailscale 可用后重启,以添加直接的 Tailnet 访问。两种方式都不会增加局域网或公网暴露。

公网(Funnel + 共享密码)

{
  gateway: {
    bind: "loopback",
    tailscale: { mode: "funnel" },
    auth: { mode: "password", password: "replace-me" },
  },
}

推荐使用 OPENCLAW_GATEWAY_PASSWORD,而不是将密码提交到磁盘。

Funnel URL 也可供 tailnet 内的设备使用。Tailscale 将公共请求标记为 Funnel 流量,但会通过其 Serve 身份路径发送 tailnet 对等设备。OpenClaw 在其专用监听器上识别这两种路径,并且仍然要求配置的 Funnel 密码。

CLI 示例

openclaw gateway --tailscale serve
openclaw gateway --tailscale funnel --auth password

认证

gateway.auth.mode 控制握手过程:

模式 使用场景
none 仅限私有入口
token(默认) 通过 OPENCLAW_GATEWAY_TOKEN 或配置共享 token
password 通过 OPENCLAW_GATEWAY_PASSWORD 或配置共享密钥
trusted-proxy 感知身份的反向代理;参见 受信任代理认证

当 gateway.auth.mode 未设置时,解析出的密码会选定密码模式。如果没有密码,则默认使用 token。如果同时配置了 gateway.auth.token 和 gateway.auth.password,请显式设置模式。

当 token 模式没有凭据时,loopback 启动会生成一个仅运行时 token,而不会将其写入配置。单独的 openclaw qr 命令仍然需要可用的已配置或提供的 token/密码认证。该仅启动 token 不会配置配对。参见 QR 认证解析。

Tailscale 身份头(仅 Serve)

当 tailscale.mode: "serve" 且 gateway.auth.allowTailscale 为 true 时,Control UI/WebSocket 认证可以使用 Tailscale 身份头(tailscale-user-login)来替代 token/密码。OpenClaw 会通过本地 Tailscale 守护进程(tailscale whois)解析请求的 x-forwarded-for 地址,并将其与请求头中的登录名进行匹配,然后才接受该请求。只有请求到达 OpenClaw 专用的受管 Tailscale 监听器,并带有 Tailscale 的 x-forwarded-for、x-forwarded-proto 和 x-forwarded-host 请求头时,才符合条件。这些请求头永远不会在普通 Gateway 监听器上建立受管 Serve 来源或免 token 认证。

这种免 token 流程假定 Gateway 主机是可信的。如果同一主机上可能运行不受信任的本地代码,请将 gateway.auth.allowTailscale 设置为 false,并要求改用 token/密码认证。

绕过范围:

  • 适用于 Control UI WebSocket 认证面以及 Control UI 个人资料头像的只读 GET/HEAD 请求。其他 HTTP API 端点(/v1/*、/tools/invoke、/api/channels/* 等)从不使用 Tailscale 身份头认证。它们始终遵循 Gateway 的正常 HTTP 认证模式。
  • 对于已经携带浏览器设备身份的 Control UI 操作员会话,经过验证的 Tailscale 身份会跳过 bootstrap-token/QR 配对的往返过程。
  • 它不会绕过设备身份本身:没有设备的客户端仍会被拒绝,节点角色连接仍会经过正常的配对和认证检查。

外部管理的 Serve 和 Funnel

当另一个服务拥有路由时,你可以将原生 Tailscale Serve 或 Funnel 路由指向普通 Gateway 监听器。在 gateway.trustedProxies 中窄范围配置该路由的直接来源,并确保其覆盖或安全地重建 X-Forwarded-For。OpenClaw 随后将该请求视为通用 trusted-proxy 入口,使用转发的客户端地址进行速率限制,并正常应用已配置的 gateway 认证模式。由于 Funnel 是公开的,当 gateway.auth.mode 为 none 时,Gateway 保护的路由会拒绝外部管理的 Funnel 入口。配置 token、password 或 trusted-proxy 认证。聚合的 health、readiness 和 startup 探针保留其现有的未认证响应,不会暴露详细的 readiness 或 startup 数据。参见 健康与就绪。

此兼容性路径不会授予受管理的 Tailscale 语义。gateway.auth.allowTailscale 无法提供无 token 认证。OpenClaw 不会调用 tailscale whois。它不会拥有或清理外部路由。如果没有明确受信任的来源以及有效的非回环转发客户端地址,Gateway 认证的路由会以 proxy_attribution_required 失败。如果代理通过回环连接,将 127.0.0.1 添加到 trustedProxies 会明确信任同一主机上的进程提供代理归属。除非主机上的每个进程都属于同一信任边界,否则请保持启用 token 或 password 认证。

说明

  • Tailscale Serve/Funnel 要求已安装并登录 tailscale CLI。
  • tailscale.mode: "funnel" 除非认证模式为 password,否则拒绝启动,以避免公开暴露。
  • OpenClaw 将 Serve/Funnel 作为前台 Tailscale 声明持有。只有在声明激活后,Gateway 启动才会成功;停止或丢失 Gateway 会自动释放它。
  • 启用受管理入口后,启动可以接管其受管理端口上的先前后台 HTTPS 根路由。当目标恰好为 http://127.0.0.1:<configured-gateway-port>,或等效的 localhost URL(可带可选末尾斜杠)时,它会接管该路由。启动随后用专用受管理监听器替换该路由,并记录接管。指向其他目标的路由,或与其他处理器或主机名共享端口的根路由,保持不变。启动会报告冲突的 HTTPS 端口和恢复指导。Doctor 不会更改外部管理的配置。
  • 受管理入口不支持命名 Tailscale Services,因为 Tailscale 要求它们作为持久后台路由运行。现有 gateway.tailscale.serviceName 安装必须运行 openclaw doctor --fix。Doctor 会禁用受管理入口并移除该键。检查保留的 Service 路由,使用 tailscale serve clear <service-name> 清除它,然后如有需要,使用 gateway.tailscale.mode: "serve" 启用设备 Serve。
  • 旧版本可能会发布一个外部配置的默认 HTTPS Serve 路由,其目标为 gateway.bind: "lan" 监听器。该路由不会自动获得受信任入口来源。运行 openclaw doctor 检查它。Doctor 不会更改配置,因为它无法证明谁拥有该路由。该路由可能属于当前 Tailscale 主机名,并且是旧 OpenClaw 版本遗留的过期路由。如果确认如此,仅使用 tailscale serve --yes --https=443 --set-path=/ off 或 tailscale funnel --yes --https=443 --set-path=/ off 移除其根处理器。然后手动配置 gateway.bind: "loopback" 以及 gateway.tailscale.mode: "serve",并重启 Gateway。如果另一个服务必须保留所有权,请保持关闭受管理的 Tailscale 入口,并使用上述显式 trustedProxies 兼容性路径。
  • gateway.tailscale.preserveFunnel: true 是一个已弃用的迁移保护。它在重新应用 Serve 之前检测外部配置的 tailscale funnel 路由。如果该路由仍指向普通 Gateway 监听器,OpenClaw 会保持不变并发出警告,因为该路由不是受管理入口。Gateway 认证的路由只能通过上述显式 trustedProxies 兼容性路径工作,并且继续要求已配置的认证。插件认证的 webhook 路由(例如 Google Chat 和 SMS)继续使用它们自己的签名和认证检查。要迁移,首先配置持久的 gateway.auth.password(优先使用 SecretRef)或 OPENCLAW_GATEWAY_PASSWORD。将 gateway.auth.mode 设置为 password。运行 openclaw config set gateway.tailscale.mode funnel。然后运行 openclaw config unset gateway.tailscale.preserveFunnel。
  • gateway.bind: "tailnet" 使用直接 Tailnet 绑定(无 HTTPS,无 Serve/Funnel),并在有 Tailnet IPv4 可用时加上必需的本地 127.0.0.1。否则它仅回退到回环。
  • gateway.bind: "auto" 在检测到的容器中使用 0.0.0.0,否则优先使用回环。使用 tailnet 可将直接网络暴露限制在 Tailnet 内,同时保留同一主机的回环访问。
  • 主 Serve/Funnel 路由暴露 Gateway Control UI + WS。节点通过同一 WS 端点连接。Portals 分配单独的私有 Serve HTTPS 端口;它们从不继承 Funnel 暴露。Tailnet 授权或 ACL 必须允许 Portals 端口以及 Gateway 端口。外部管理的路由不会自动分配 Portals 入口。

Tailscale 先决条件和限制

  • Serve 要求为你的 tailnet 启用 HTTPS。如果缺失,CLI 会提示。
  • Tailnet Serve 流量会注入 Tailscale 身份头。公共 Funnel 流量改用 Funnel 标记,而 tailnet 访问同一 Funnel URL 则遵循 Serve 身份路径。
  • OpenClaw 管理的 Serve/Funnel 代理到专用的 127.0.0.1:<ephemeral-port> 监听器,而普通本地客户端继续使用已配置的 Gateway 端口。启动会失败关闭,而不是共享监听器来源;当前台声明的 Gateway 所有者消失时,它会释放该路由。
  • 当 Gateway 在启动时先于本地 Tailscale 守护进程连接而启动(tailscale status 报告 NoState 或 Starting,或守护进程尚未接受连接)时,受管理声明最多等待 90 秒,并记录进度。任何其他守护进程状态都会立即失败关闭。
  • Funnel 要求 Tailscale v1.38.3+、MagicDNS、启用 HTTPS 以及 funnel 节点属性。
  • Funnel 仅支持通过 TLS 使用端口 443、8443 和 10000。
  • macOS 上的 Funnel 要求开源 Tailscale 应用变体。

恢复孤立的 前台占用

旧版 Gateway 在强制关闭后可能仍会保留一个正在运行的 前台 Tailscale 占用。更新可防止产生新的孤立占用,但不会移除现有占用。

如果启动时报告 HTTPS 端口被占用,请运行 tailscale serve status --json。 检查 Foreground 中报告的会话、主机名、路径和代理目标。 在 macOS 或 Linux 上,使用 ps -axo pid,ppid,args | grep '[t]ailscale' 检查候选 CLI 进程。在通过 kill -TERM <confirmed-pid> 停止该进程之前,先确认是哪个进程创建了该 路由。Tailscale 状态不会 报告占用方 PID。仅凭后端监听器 PID 或孤立的父进程 无法证明所有权。如果另一个应用程序拥有该占用,请勿改动它, 并在解决冲突之前保持 OpenClaw 托管入口关闭。

确认前台会话已从 tailscale serve status --json 中消失,然后重启 Gateway。tailscale serve --https=443 --set-path=/ off 会移除后台 Web 处理器。它不会释放前台占用。

浏览器控制(远程 Gateway + 本地浏览器)

若要在一台机器上运行 Gateway,但在另一台机器上驱动浏览器,请在浏览器所在机器上运行 node host。保持两台机器位于同一 tailnet。Gateway 会将浏览器操作代理到该 node。无需单独的控制服务器或 Serve URL。

避免在浏览器控制中使用 Funnel。将 node 配对视为操作员访问。

了解更多

本页原文 Markdown:在 AtomGit 查看·内容源自开源项目 cl/openclaw