Keyboard shortcuts

Press ← or → to navigate between chapters

Press ? to show this help

Press Esc to hide this help

网络部署

部署 ZeroClaw 以接收入站流量:网关暴露、Webhook 通道、隧道,以及仅限局域网与面向公网的配置。树莓派和其他家庭网络主机是此场景下的首要目标。

当入站端口很重要时

模式入站端口?备注
Telegram(长轮询)不ZeroClaw 轮询 api.telegram.org,可在 NAT 后工作
Matrix / Mattermost / Nextcloud Talk不同步/WebSocket,仅出站
Discord / Slack(Socket 模式)不出站 WebSocket
Signal(signal-cli-rest-api)不本地主机容器
Nostr / IMAP / MQTT不所有出站
Webhooks(GitHub、Slack Events API、WhatsApp、Nextcloud Talk 机器人、自定义)是需要公共 POST 端点
从局域网配对网关是(局域网范围)绑定到 0.0.0.0 或使用隧道
Discord / Slack(HTTP 事件)是的如果您不使用 Socket 模式

结论: 一个仅使用 Telegram 的机器人可以在消费级路由器后面的 Pi 上运行,无需任何端口转发。而任何基于 webhook 的方案都需要一个可访问的 URL,这正是隧道发挥作用的地方。

绑定网关

默认情况下,网关绑定到 127.0.0.1,其他设备无法访问。有三种方式可将其暴露出来:

选项 1:公共绑定(局域网)

这样局域网内的任何设备都可以访问 http://<pi-ip>:42617。但这对于需要从互联网访问的 webhook 没有帮助,因为路由器的公网 IP 并未转发到这台 Pi。

安全性: 由于绑定到 0.0.0.0 是一个重大的安全策略变更,因此需要设置 allow_public_bind = true。如果没有此配置,守护进程将拒绝启动。这是有意为之的设计。

选项 2:隧道(可从互联网访问)

然后重启守护进程,隧道通过配置以声明式方式进行管理,与网关一同启动。

隧道将公共 URL 转发到 127.0.0.1 上的网关。无需路由器配置,无需开放端口。将 tunnel.tunnel_provider 设置为受支持的值之一即可;每个值的工作方式类似:

提供者设置摩擦力成本适用于
tailscale账户 + 客户端免费层级长期稳定的 URL
cloudflare账户 + cloudflared + 令牌免费自定义域名
ngrok账户 + 代理 + 令牌免费,但有使用限制测试,短期
pinggySSH,无账户免费层级快速一次性 URL
openvpn你自己的 OpenVPN 出口自托管现有 VPN 基础设施
custom[tunnel.custom] 下的命令依赖还有其他事项吗

tunnel_provider = "none"(默认值)使网关保持本地运行,不使用隧道。各提供程序的 [tunnel.<provider>] 字段请参阅 配置参考。

Tailscale:WSS 与设备注册

使用 tunnel_provider = "tailscale" 时,网关通过 tailscale serve 发布(当 [tunnel.tailscale].funnel = true 时改用 tailscale funnel)。启用 [wss] 后,守护进程还会在 tailnet 上发布 WSS RPC 监听器;启用 [enroll] 时,同样会发布注册端点。每一项都保留各自的端口:

tailscale serve --tcp <wss.port>    tcp://127.0.0.1:<wss.port>
tailscale serve --tcp <enroll.port> tcp://127.0.0.1:<enroll.port>

这些是原始 TCP 透传转发。TLS 仍在守护进程内部终止,因此 WSS 通道保持双向认证,注册时的简短认证字符串(SAS)仍绑定守护进程自身的 CA。这些转发不使用 Tailscale 的 HTTPS 代理,因为它会剥离客户端证书。通配符绑定地址(0.0.0.0 / ::)会被转发到回环地址;具体的绑定地址则转发到该地址。

注意事项:

  • 仅限 Tailnet,即使启用了 Funnel。 Funnel 只监听端口 443、8443 和 10000,将 mTLS 平面暴露到公网应当是你的明确选择。它不会因为对网关启用 Funnel 而作为附带效果被开启。要从 tailnet 外部访问 WSS,请使用 [relay]。
  • 证书名称自动管理。 当 WSS 和注册监听器通过 Tailscale 访问时,守护进程会在启动时将节点的 tailnet 名称添加到其自动生成的服务器证书中。这包括 MagicDNS 名称(<node>.<tailnet>.ts.net)、短名称(<node>)、节点的 tailnet IP 地址,以及已设置的 [tunnel.tailscale].hostname。“通过 Tailscale 访问”指的是通过此隧道访问,或将 [wss].bind / [enroll].bind 直接设置为 tailnet 地址(100.64.0.0/10 或 fd7a:115c:a1e0::/48),无论是否使用隧道。这些名称在每次守护进程启动时(以及每次重新加载时)查询一次,并由两个监听器共享,因此 WSS 和注册始终呈现相同的证书。只有在名称变化时才会重新生成服务器证书。CA 保持不变,因此已注册的客户端仍可正常工作。如果启动时无法连接 tailscaled,或者 tailscaled 在收到网络映射之前就做出响应(刚开机后很常见),守护进程会记录一条警告,并保留现有证书已包含的所有名称。新增的 [wss].sans 条目仍会生效,但名称的移除要等到 tailscaled 正常响应的那次启动才会进行。在全新安装且 tailscaled 未运行时,证书只包含无需 tailscaled 即可获知的名称(localhost、127.0.0.1、[wss].sans 和 [tunnel.tailscale].hostname);待 tailscaled 启动后重启一次即可补全其余名称。由用户自备的 cert_path 证书永远不会被修改。
  • 注册锁定是共享的。 转发的连接从本地回环(loopback)到达注册端点。这意味着每个 tailnet 注册者共享同一个配对尝试锁定,来自某个 tailnet 对等节点的多次错误代码会暂时阻止其他节点注册。该锁定采用失败关闭(fail closed)策略,绝不会削弱配对代码的校验机制。
  • 这些转发是由网关持有的前台 tailscale serve 会话,因此网关停止时它们会被撤销。如果其中某个会话之后自行退出,守护进程会记录一条 tailscale serve --tcp exited after publication 警告;请重启网关以重新发布它。
  • 注册流程取决于 CA 模式。 使用自带客户端 CA(启用 [wss.client_auth] 并配置 ca_cert_path)时,守护进程不持有签名密钥,也不运行注册端点,因此该端点同样不会被发布。

选项 3:反向代理

在网关前运行 nginx / Caddy / Traefik。在此处终止 TLS,并代理到 localhost:42617。适用于:

  • 具有真实公网 IP 的服务器
  • 使用 Let’s Encrypt 的现有反向代理设置
  • 在同一主机上托管多个服务

一个最小的 Caddy 配置:

agent.example.com {
    reverse_proxy localhost:42617
}

网关保持绑定到 127.0.0.1,由代理负责监听。

通用网关 Webhook 身份验证

网关的 POST /webhook 和仅限 SOP 的 POST /sop/* 路由可以独立于配对而要求精确匹配的共享密钥标头:

[gateway]
webhook_secret = "replace-with-a-random-secret"

将该值作为 X-Webhook-Secret 发送。当 require_pairing = true 且设置了 webhook_secret 时,调用方必须同时发送配对的 bearer 令牌和 webhook 密钥。通用网关密钥与 [channels.webhook.<alias>].secret 有意分开;频道别名各自运行监听器,并改用正文 HMAC 验证。

网关配置写入会通过实时网关配置视图生效。直接编辑文件需要执行常规守护进程重新加载(或单独重启网关)。

远程守护进程重新加载

POST /admin/reload 会重新读取 config.toml 并就地重建每个子系统(PID 不变,停机时间不到一秒)。这是无需完全重启即可应用配置变更的受支持方式。默认情况下它只接受环回(loopback)调用方,因此来自其他机器的远程仪表板或 curl 会收到 403 Forbidden。

允许经过身份验证的远程重新加载:

[gateway]
allow_remote_admin = true    # off by default
require_pairing = true        # required for remote reload (also the default)

启用此选项后,非环回(loopback)调用方只有在同时通过配对认证(Authorization: Bearer <token>)的情况下才能访问 /admin/reload。环回调用方(本地 CLI)始终被允许,且无需令牌。无论此标志如何设置,/admin/shutdown 和配对码端点都仅限于 localhost 访问。

由于远程访问是通过配对来强制实施的,因此除非 require_pairing 也已开启,否则 allow_remote_admin 不会生效:如果禁用了配对,远程调用方将无法通过身份验证,因此请求会被以 403 Forbidden 拒绝,而不是被匿名允许。这使得无法通过切换单个标志来暴露未经身份验证的远程重新加载。

安全提示: 除非你确实需要从其他主机重新加载,否则请保持 allow_remote_admin 处于关闭状态。请保持 require_pairing = true(默认值),这样就无法匿名触发重新加载。

树莓派部署

前置条件

  • Raspberry Pi 3/4/5(或类似的单板计算机),搭载 Raspberry Pi OS 或 Alpine
  • 网络连接(WiFi 或以太网)
  • 可选:用于硬件集成的 USB 外围设备

安装

克隆并运行安装程序。在不带任何参数的情况下,它会进入交互式选择界面,你可以在其中选择构建类型以及要编译的功能特性,包括 GPIO/I2C/SPI 的硬件功能。在 Pi 上,它还会使用针对 Pi 调优的 cargo 配置文件;有关交换空间设置和各型号的构建矩阵,请参阅 Raspberry Pi setup。

Raspberry Pi OS

git clone https://github.com/zeroclaw-labs/zeroclaw.git
cd zeroclaw
./install.sh

Alpine

apk add curl rust cargo openssl-dev pkgconf git
git clone https://github.com/zeroclaw-labs/zeroclaw.git
cd zeroclaw
./install.sh

当你选择硬件功能时,通过 rppal 授予对 GPIO、I2C、SPI 的访问权限。标准服务单元已经将用户添加到 gpio、spi、i2c 组中。

检查清单

  • 安装二进制文件(./install.sh,在选择器中选择你需要的功能)
  • 运行 zeroclaw quickstart
  • 配置你的频道。Telegram 无需端口;webhook 需要隧道
  • 安装服务:zeroclaw service install && zeroclaw service start
  • 对于局域网访问:设置 [gateway] host = "0.0.0.0" 和 allow_public_bind = true
  • 对于 Webhook:配置 [tunnel] 并指定一个提供商

Alpine Linux (OpenRC)

OpenRC 服务是系统范围的。以 root 用户身份安装:

sh

sudo zeroclaw service install

创建:

  • /etc/init.d/zeroclaw:init 脚本
  • /etc/zeroclaw/:配置目录
  • /var/log/zeroclaw/:日志文件

启用并启动:

sh

sudo rc-update add zeroclaw default
sudo rc-service zeroclaw start
sudo rc-service zeroclaw status

日志:

sh

sudo tail -f /var/log/zeroclaw/error.log

OpenRC 注意事项

  • 服务以 zeroclaw:zeroclaw(最小权限)运行
  • 仅限系统级:无用户级 OpenRC 服务
  • 所有服务操作都需要 sudo

Telegram 轮询的注意事项

Telegram Bot API 的 getUpdates 对每个 bot token 只允许单一轮询器。你不能使用相同的 token 运行两个实例;第二个实例会收到 Conflict: terminated by other getUpdates request。

如果您看到此内容:

  1. 执行 ps aux | grep zeroclaw 并确认只有一个守护进程在运行

  2. 检查是否有一个来自开发会话的 cargo run --bin zeroclaw -- channel start telegram 进程仍在运行

  3. 如果已过期,重置 Telegram 的投票会话:

    sh

    curl -X POST "https://api.telegram.org/bot$TOKEN/close"
    

安全地暴露 Webhook

一个公开可访问的 Webhook URL 是攻击面。至少:

  • HMAC 签名验证:在每个 webhook 通道上配置的 secret
  • 源 IP 白名单,适用于具有固定出口 IP 的服务(GitHub、AWS SNS)
  • 速率限制:webhook 通道配置中的 rate_limit_per_sec

有关完整的配置选项,请参阅 Channels → Webhooks。

另见