摘要:Gateway(网关)是 OpenClaw 的常驻控制进程。它在一个端口上同时处理多种协议:WebSocket用于实时控制和远程调用(RPC),HTTP提供 OpenAI 兼容的 API 接口,还有管理界面(UI)和画布(Canvas)功能。无论是即时通讯(IM)渠道、桌面客户端还是自动化脚本,都必须先连接到 Gateway,然后才能使用 Router(路由)、Brain(大脑)和 Hands(执行器)等功能。本文结合官方Gateway Runbook(运行手册)和Network model(网络模型)文档,讲解三个核心概念:单实例锁定(通过独占端口实现)、默认身份验证、健康检查与配置热重载。同时,我们将基于源码(固定 commit)走读启动流程:从openclaw gateway命令行到runGatewayLoop(处理锁和信号),再到startGatewayServer(组装运行时),为下一篇 Router 做好铺垫。
关键词:OpenClaw;Gateway(网关);WebSocket;HTTP 多路复用;单实例;openclaw gateway;startGatewayServer;健康检查;源码走读
系列文章:
- OpenClaw 深度解析与源代码导读 · 第1篇:系列导读——术语、版本与读源码方法
- OpenClaw 深度解析与源代码导读 · 第2篇:Skills——能力扩展平面与源码中的「目录即技能」
源码版本说明:本文引用路径基于 openclaw/openclaw 仓库;本地阅读使用的 commit 为0dd4958bc8a78d26b3b526b1f2e63b15110c64a2(2026-04-11)。GitHub 上可按该 SHA 查看对应版本的源码,避免main分支变动导致的差异。
1 OpenClaw 架构全景与 Gateway 的位置
在深入 Gateway 之前,先通过一张架构图理解Gateway 在 OpenClaw 整体中的位置(延续第1篇的餐厅比喻):
1.1 各组件职责速查表
| 组件 | 餐厅比喻 | 技术职责 | 与 Gateway 的关系 |
|---|---|---|---|
| Gateway | 前台/入口 | 单进程常驻控制面;单端口多协议(WebSocket + HTTP);身份验证;健康检查 | 本文主角—— 所有流量的第一站 |
| Router | 订单分发员 | 决定消息流向:进 Brain?走快捷路径?直接回包? | Gateway 收到请求后交给 Router 决策 |
| Brain | 主厨/大脑 | LLM 推理、上下文管理、工具调用循环 | 经 Gateway → Router 后进入 |
| Hands | 端锅/执行 | Shell、文件操作、浏览器控制 | 被 Brain 调用,通过 Gateway 返回结果 |
| Skills | 预制酱料包 | SKILL.md 扩展能力,按需加载 | 经 Gateway 目录扫描后暴露给 Brain |
| Memory | 台账/便签墙 | 持久化存储、会话状态、长期记忆 | 各组件通过 Gateway 协调访问 |
| Channels | 外卖平台/电话线 | IM 渠道长连接管理(WhatsApp/Slack 等) | 挂载在 Gateway 上,Gateway 保持长连接 |
1.2 数据流向示例
场景:用户发送一条 WhatsApp 消息给 Agent
💡理解要点:Gateway 是“一夫当关”的入口,但它不处理业务逻辑——只负责“接进来、送出去、保安全、管连接”。
2 为什么要单独写一篇 Gateway?
在第1篇里,我们把 Gateway 比作餐厅的前台:它不亲自炒菜(Brain 负责),也不端盘子(Hands 负责),但所有顾客(渠道消息)、外卖订单(HTTP API)、排号屏幕(控制 UI)都必须先经过它。如果跳过 Gateway 直接研究auto-reply或某个具体渠道插件,很容易混淆几个关键问题:谁负责维持长连接?谁在做身份验证?谁在检查服务是否存活?
本文解答三个核心问题:
- 产品定位:Gateway 进程负责什么、不负责什么(与多 Agent、workspace 隔离的关系在第1篇已有,本文补充网络边界和进程边界)。
- 运维操作:如何启动 / 检查健康状态 / 排查故障,以及为什么默认开启身份验证、为什么独占端口。
- 源码结构:从
openclaw gateway命令到startGatewayServer,建立后续 Router 篇需要的“入口函数地图”。
💡理解要点:本文刻意不展开每一条 WebSocket RPC 协议细节(那是协议层内容,见 D1 bridge-protocol);本文聚焦进程模型 + 端口模型 + 启动调用链。
3 运行时模型:一个进程、一个端口、多种功能
官方 Runbook(D1:Gateway runbook)用几句话概括了运行时模型,核心要点如下:
- 一个常驻进程负责消息路由、控制面和渠道的长连接管理。
- 同一个端口同时承载多种协议:
- WebSocket用于实时控制和远程调用(RPC);
- HTTP提供 OpenAI 兼容接口(如
/v1/models、/v1/chat/completions、/v1/responses、/v1/embeddings)、/tools/invoke等; - 管理 UI、Canvas 相关路由等。
- 默认绑定地址:
loopback(回环地址,即 127.0.0.1);默认身份验证:开启(通过共享密钥gateway.auth.token/password或环境变量OPENCLAW_GATEWAY_*);非回环地址场景可使用trusted-proxy(可信代理)等模式(见 D1 configuration、trusted-proxy-auth)。
🔍实际例子:默认地址是ws://127.0.0.1:18789(端口可修改)。本地命令行工具(CLI)、终端界面(TUI)、桌面客户端都通过同一个 WebSocket 地址进行远程调用;Open WebUI 这类客户端通常会先GET/v1/models获取模型列表,再 POST 聊天请求——这些请求都落在同一个 Gateway 端口上,由 HTTP 和 WebSocket 分别处理。
3.1 与网络模型文档的关系
docs/gateway/network-model.md提示部分内容已并入站点Network总页,但核心结论值得深入理解:
为什么"建议每台主机运行一个 Gateway"?
核心原因是WhatsApp Web 等渠道的技术限制。这些 IM 渠道使用QR 码扫码登录机制,且一个手机号同一时间只能有一个活跃的 Web 会话。如果同一主机上运行多个 Gateway 进程,它们会互相竞争 WhatsApp Web 连接,导致:
- 频繁掉线:后启动的 Gateway 会踢掉先登录的会话
- 消息丢失:正在处理的对话可能中断
- 状态混乱:多个进程同时尝试维持心跳,触发平台的风控
其他渠道(Discord、Slack、Telegram 等 Bot Token 机制)无此限制,但为统一管理,OpenClaw 仍建议单主机单 Gateway作为默认部署模式。
什么是"强隔离"?何时需要多 Gateway?
当以下场景出现时,需要在一台物理机上运行多个完全独立的 Gateway 实例:
| 场景 | 隔离需求 | 实现方式 |
|---|---|---|
| 多用户/多租户 | 用户 A 和用户 B 的数据绝不能互通 | 不同的OPENCLAW_HOME目录 |
| 测试 vs 生产 | 测试环境的故障不能影响生产服务 | 不同的profile(如--profile test) |
| 多 WhatsApp 号 | 一个公司需要同时运营多个 WhatsApp 业务号 | 不同的端口+ 不同的工作目录 |
| 不同网络环境 | 部分服务走 VPN,部分走公网 | 不同的绑定地址 + 路由规则 |
“多 profile、多端口、多OPENCLAW_HOME” 详解
这三个是正交维度,可以组合使用:
1. Profile(配置档案)
- 作用:隔离不同的配置集合(生产配置、测试配置、开发配置)
- 使用:
openclaw gateway --profile productionvs--profile staging - 存储位置:
~/.openclaw/profiles/<profile-name>/
2. 端口(Port)
- 作用:网络层隔离,避免端口冲突
- 使用:
openclaw gateway --port 18789(默认)vs--port 18790 - 注意:每个端口对应一个独立的Gateway 单实例锁(§4)
3.OPENCLAW_HOME(主目录)
- 作用:彻底隔离所有数据:配置、会话存储、日志、技能目录
- 使用:
export OPENCLAW_HOME=/opt/company-a/openclaw - 效果:两个 Gateway 实例即使运行在同一用户下,也看不到彼此的数据
典型部署模式示例
模式一:单用户单机(默认)
# 一个 Gateway,默认端口 18789openclaw gateway模式二:开发/测试分离
# 终端 1:生产环境echo"PROD"OPENCLAW_HOME=/home/user/openclaw-prod openclaw gateway--port18789--profiledefault# 终端 2:测试环境echo"TEST"OPENCLAW_HOME=/home/user/openclaw-test openclaw gateway--port18790--profiletest模式三:多租户隔离(伪代码)
# 租户 A - 电商客服sudo-utenant-aOPENCLAW_HOME=/var/tenants/a openclaw gateway--port18001# 租户 B - 内部 IT 支持sudo-utenant-bOPENCLAW_HOME=/var/tenants/b openclaw gateway--port18002每个租户有:
- 独立的 Linux 用户(
tenant-avstenant-b) - 独立的
$OPENCLAW_HOME(/var/tenants/{a,b}) - 独立的端口(
18001vs18002) - 独立的 WhatsApp 登录会话
💡理解要点:“单主机单 Gateway” 是建议而非强制。当业务需要隔离时,通过profile × port × OPENCLAW_HOME的组合,可以在同一台机器上构建出逻辑上完全独立的多个 Gateway 实例,每个实例有自己的进程边界、网络边界、存储边界。
详见 D1 Multiple gateways 完整文档。
4 单实例:不靠 PID 文件,靠"谁先占用端口谁运行"
D1 Gateway lock 文档解释得很清楚:
- 目的:同一主机、同一端口上只能运行一个Gateway;第二个实例必须立即失败并给出清晰的错误提示。
- 机制:启动时立即在 WebSocket 监听地址上建立独占的 TCP 监听(exclusive TCP listen);如果端口已被占用(
EADDRINUSE错误),抛出GatewayLockError——不需要额外的 lock 文件,进程崩溃或被强制终止(SIGKILL)后,操作系统会自动回收端口。 - 运维:如果端口被非 OpenClaw的程序占用,错误表现与"第二个 Gateway"相同;需要通过
openclaw gateway --port <port>更换端口,或释放占用该端口的程序。
这与"传统守护进程写/var/run/foo.pid文件"的方式不同:锁就是监听套接字(socket)本身,排查故障时直接用netstat或端口诊断工具即可。
4 生命周期(用户视角):启动、检查健康、看日志
Runbook 的5-minute local startup可直接作为本文的"验收清单":
- 启动 Gateway:
openclaw gateway --port 18789(或使用openclaw gateway --force强制释放占用端口后再启动)。 - 检查状态:
openclaw gateway status/openclaw status—— 确认看到Runtime: running和RPC probe: ok等基础信息。 - 检查渠道:
openclaw channels status --probe—— 当 Gateway可访问时,对各渠道进行在线探测;如果 Gateway 不可达,命令行工具会降级为仅显示配置摘要(Runbook 已说明这种分叉行为)。
更深入的健康检查见 D1 health.md:openclaw health、openclaw status --deep等命令会向运行中的 Gateway 请求快照或实时探测——注意openclaw health默认不直接连接各渠道的套接字,而是通过WebSocket 询问 Gateway,由 Gateway 侧协调探测。
配置热重载:Runbook 的Note说明:Gateway 监听活动配置文件路径(OPENCLAW_CONFIG_PATH或 profile 默认路径),gateway.reload.mode默认值为hybrid——首次成功加载后,进程持有内存中的配置快照,成功重载时原子化切换快照。这样 Gateway 可以在不完全重启的情况下应用部分配置变更(具体支持哪些配置项以 D1 文档为准)。
5 源码走读:从命令行到startGatewayServer
下面是一条"可放入脑图"的主路径,供你在本地用rg或跳定义功能跟随走读。
5.1 命令行注册:gateway子命令是什么?
src/cli/gateway-cli/register.ts把子命令注册到 Commander 框架上,描述直接点题:WebSocket Gateway的运行、巡检与发现功能:
// src/cli/gateway-cli/register.ts(节选)exportfunctionregisterGatewayCli(program:Command){constgateway=addGatewayRunCommand(program.command("gateway").description("Run, inspect, and query the WebSocket Gateway")// … 帮助示例:gateway run / status / discover …💡理解要点:openclaw gateway不是"另一个 REST 小工具",而是同一套运行时的运维入口——与openclaw status等命令共享“如何找到正在运行的那个进程”这一语境。
5.2 运行循环:runGatewayLoop—— 处理锁、信号、重启
src/cli/gateway-cli/run-loop.ts在真正启动startGatewayServer之前调用acquireGatewayLock;持有锁期间创建server,并处理SIGINT/SIGTERM/SIGUSR1等优雅停机和重启(包括清空队列、释放锁后再生成子进程等细节,文件后半部分继续展开)。
// src/cli/gateway-cli/run-loop.ts(节选)exportasyncfunctionrunGatewayLoop(params:{start:(params?:{startupStartedAt?:number})=>Promise<Awaited<ReturnType<typeofstartGatewayServer>>>;runtime:RuntimeEnv;lockPort?:number;}){letlock=awaitacquireGatewayLock({port:params.lockPort});letserver:Awaited<ReturnType<typeofstartGatewayServer>>|null=null;// … 注册信号;关机时 releaseLock;重启路径可能生成新进程 …读这里的目的:把“GatewayLockError = 端口冲突”与源码入口对齐——文档里的锁机制,对应代码里acquireGatewayLock+start失败路径,而不是散落在各渠道插件里。
5.3 服务器组装:startGatewayServer—— 配置、插件、渠道、WebSocket
src/gateway/server.ts只是薄转发层(thin re-export);实现位于server.impl.ts。startGatewayServer(port, opts)一进来就把端口写入环境变量OPENCLAW_GATEWAY_PORT,随后流水线大致如下:
- 加载配置快照
loadGatewayStartupConfigSnapshot→prepareGatewayStartupConfig(包含身份验证引导(auth bootstrap)、可能生成并持久化 token); - 诊断心跳、SIGUSR1 重启策略、控制 UI 的 allowedOrigins 种子等横切关注点;
prepareGatewayPluginBootstrap:整理插件 / 渠道相关注册表和gatewayMethods列表;resolveGatewayRuntimeConfig、startGatewayEarlyRuntime、attachGatewayWsHandlers(WebSocket 运行时)、createChannelManager、startManagedGatewayConfigReloader……直到 HTTP/WebSocket监听建立。
节选(只看"头部在做什么"):
// src/gateway/server.impl.ts — startGatewayServer(节选)exportasyncfunctionstartGatewayServer(port=18789,opts:GatewayServerOptions={}):Promise<GatewayServer>{constminimalTestGateway=process.env.VITEST==="1"&&process.env.OPENCLAW_TEST_MINIMAL_GATEWAY==="1";process.env.OPENCLAW_GATEWAY_PORT=String(port);constconfigSnapshot=awaitloadGatewayStartupConfigSnapshot({minimalTestGateway,log});constauthBootstrap=awaitprepareGatewayStartupConfig({configSnapshot,authOverride:opts.auth,tailscaleOverride:opts.tailscale,activateRuntimeSecrets,});constcfgAtStart=authBootstrap.cfg;// … 诊断 / 重启策略 / 控制 UI 种子 …constpluginBootstrap=awaitprepareGatewayPluginBootstrap({cfgAtStart,startupRuntimeConfig:applyConfigOverrides(configSnapshot.config),minimalTestGateway,log,});// … resolveGatewayRuntimeConfig → attachGatewayWsHandlers / channels / reload …🔍实际例子:如果启动日志出现“生成了 runtime token 但未写入配置”这类警告,对应authBootstrap分支里对persistedGeneratedToken的判断——这直接影响“重启后 token 是否会变化”,排查故障时应回到D1 configuration + secrets文档确定持久化策略。
5.4 一张总图:把 §5.1~§5.3 串起来
6 与第2篇(Skills)的边界
Skills子系统解决“磁盘上的SKILL.md如何变成模型可见的<available_skills>”(见第2篇);Gateway解决“谁长期在线、谁在哪个端口上同时接受 WebSocket/HTTP、谁去拉起渠道和健康探测”。二者在运行时交汇(会话快照、配置重载、RPC),但职责不混写:读 Skills 不必深入 HTTP 路由;读 Gateway 也不必读完整个SKILL.md解析器。
7 Gateway 安全隐患与加固建议
Gateway 作为所有流量的入口和常驻进程,其配置直接决定了系统的攻击面大小。以下是基于文档设置的关键安全风险及应对建议(更全面的安全分析将在第14篇(安全与成本)展开)。
7.1 网络暴露风险(与bind设置相关)
| Gateway 设置 | 安全风险 | 文档出处 |
|---|---|---|
默认loopback(127.0.0.1) | 仅本机可访问,风险最低 | §2 |
改为0.0.0.0或公网 IP | 任何人可尝试连接,若身份验证配置不当则完全暴露 | §2 |
trusted-proxy模式 | 依赖上游代理做鉴权,若代理配置错误(如未过滤伪造头),攻击者可绕过 | §2 |
实际风险场景:如果将 Gateway 绑定到0.0.0.0:18789且使用弱 token或关闭鉴权,攻击者可直接调用/v1/chat/completions消耗你的 API Key,或通过 WebSocket 接口操纵 Agent。
7.2 身份验证绕过(与auth设置相关)
文档提到的鉴权方式(§2):
gateway.auth.token/password(共享密钥)- 环境变量
OPENCLAW_GATEWAY_TOKEN/OPENCLAW_GATEWAY_PASSWORD trusted-proxy(可信代理,风险最高)
隐患:若使用password且密码强度不足,或 token 泄露(如提交到 GitHub),攻击者可在任何能访问该端口的主机上伪装为合法客户端。
7.3 单实例锁的副作用(与端口占用相关)
文档§3说明:“锁就是监听套接字(socket)本身”。
安全隐患:若 Gateway 崩溃后未正确释放端口(极少数内核异常),或恶意程序故意占用18789端口并伪装成 Gateway,客户端可能连接到假 Gateway,导致中间人攻击(MITM)。
7.4 配置热重载的风险(与reload.mode相关)
§4提到gateway.reload.mode默认hybrid,支持不完全重启即可应用配置变更。
安全隐患:如果攻击者通过某种方式(如配置文件注入、环境变量篡改)修改了gateway.auth.token,Gateway 可能在不中断服务的情况下应用新配置,导致合法用户被踢出或非法用户获得访问权。
7.5 健康检查信息泄露(与health端点相关)
§4提到openclaw health、openclaw status --deep等命令会返回健康快照(health snapshot)。
隐患:这些快照可能包含渠道连接状态、运行时配置片段、会话统计信息。如果 Gateway 的鉴权被绕过,攻击者可借此进行信息收集,为后续攻击做准备。
7.6 安全加固建议(基于文档设置)
| 层级 | 建议配置 | 对应文档 |
|---|---|---|
| 网络层 | 保持默认loopback;如需远程访问,使用Tailscale/SSH 隧道而非直接暴露 | §2, §2.1 |
| 认证层 | 使用强随机 token(gateway.auth.token),定期轮换;避免password模式 | §2 |
| 进程层 | 使用--force重启确保旧进程完全终止;监控GatewayLockError日志 | §3, §4 |
| 配置层 | 限制配置文件权限(~/.openclaw/目录 600);谨慎使用hybridreload | §4 |
| 监控层 | 定期检查openclaw gateway status和日志,确认无异常连接 | §4 |
💡理解要点:Gateway 的绑定地址(bind)、身份验证模式(auth mode)、端口占用策略共同构成了 OpenClaw 的第一道防线。文档§2-§4 的所有设置项都应从安全视角重新审视——它们既是功能配置,也是安全策略。
8 D3 参考阅读与扩展学习
8.1 OpenClaw 官方视角博客
- OpenClaw Gateway Explained(dench.com) —— 架构层面的 Gateway 解读,适合理解设计哲学。
- How to Set Up an OpenClaw AI Gateway in 2026(getclawhosting.com) —— 运维部署向,含端口配置、systemd 服务设置等实操内容。注意核对其端口/路径描述是否与你本机
openclaw.json一致。
8.2 AI Gateway 安全通用参考(跨项目借鉴)
以下资源虽非 OpenClaw 专属,但讨论了 AI Gateway 共性的安全挑战:
- LLM API Gateway Security Patterns(Cloudflare Blog)—— 讨论 API Key 轮换、速率限制、提示词过滤等通用模式,可借鉴到
gateway.auth配置思路。 - AI Infrastructure Security: Gateway & Proxy Patterns(MITRE/OWASP)—— 模型供应链攻击、提示词注入防御,可与第14篇安全内容对照阅读。
- Tailscale + AI Tools 安全实践(Tailscale Blog)—— 与本文§2.1提到的Tailscale 替代直接暴露思路一致,提供具体组网方案。
8.3 安全专项内容预告
更全面的安全分析将在第14篇(安全与成本)展开,包括:
- 多 Agent 攻击面与
OPENCLAW_HOME强隔离 - 沙箱逃逸风险与 Hands 权限边界
- 按 Agent 选择模型的成本与安全权衡
9 本篇小结与下一篇预告
- 小结:Gateway =单进程控制面;单端口多协议;独占 bind(绑定) = 单实例锁;身份验证默认开启;健康与渠道探测由 Gateway 侧协调;启动主链
registerGatewayCli→runGatewayLoop→startGatewayServer。安全方面需重点关注bind 地址、auth 模式、token 生命周期。 - 下一篇(第4篇):Router(路由器)——入站消息进入 Gateway 之后,如何分发到 Brain / 快捷路径 / 渠道回包(与官方 Data flow 第 2 步对齐)。
10 参考文献与链接
- OpenClaw 主仓库:https://github.com/openclaw/openclaw
- Architecture Overview(D2):http://clawdocs.org/architecture/overview
- Gateway(D2):http://clawdocs.org/architecture/gateway
- Gateway Runbook(D1):https://github.com/openclaw/openclaw/blob/0dd4958bc8a78d26b3b526b1f2e63b15110c64a2/docs/gateway/index.md
- Network model(D1):https://github.com/openclaw/openclaw/blob/0dd4958bc8a78d26b3b526b1f2e63b15110c64a2/docs/gateway/network-model.md
- Gateway lock(D1):https://github.com/openclaw/openclaw/blob/0dd4958bc8a78d26b3b526b1f2e63b15110c64a2/docs/gateway/gateway-lock.md
- Health checks(D1):https://github.com/openclaw/openclaw/blob/0dd4958bc8a78d26b3b526b1f2e63b15110c64a2/docs/gateway/health.md
- Gateway configuration(D1):https://github.com/openclaw/openclaw/blob/0dd4958bc8a78d26b3b526b1f2e63b15110c64a2/docs/gateway/configuration.md
- Bridge protocol(D1,WS/RPC):https://github.com/openclaw/openclaw/blob/0dd4958bc8a78d26b3b526b1f2e63b15110c64a2/docs/gateway/bridge-protocol.md