网络部署
部署 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 | 账户 + 代理 + 令牌 | 免费,但有使用限制 | 测试,短期 |
pinggy | SSH,无账户 | 免费层级 | 快速一次性 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。
如果您看到此内容:
-
执行
ps aux | grep zeroclaw并确认只有一个守护进程在运行 -
检查是否有一个来自开发会话的
cargo run --bin zeroclaw -- channel start telegram进程仍在运行 -
如果已过期,重置 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。