背景

某台小型 Linux 主机上运行着 OpenClaw Gateway,作为个人运维辅助入口使用。该实例经历过一次迁移和配置调整,迁移后需要确认几件事:

  • 当前运行的是否是预期中的主实例;
  • 服务是否正常启动;
  • 是否存在旧路径、旧配置或重复实例;
  • Web 入口和 webhook 是否存在不必要的暴露面;
  • 反向代理相关配置是否正确;
  • 日志中是否还有持续性错误;
  • 内存占用是否稳定。

本次排查的原则是只读优先:先通过 systemd、journal、监听端口、配置目录和进程状态确认现状,不直接修改、不删除、不重启。只有当证据明确显示配置变更需要重启生效,且重启本身也能释放内存压力时,才执行服务重启。

初始自检结论

自检首先确认了几个基础事实:

  • OpenClaw Gateway 服务处于 enabled / active / running 状态;
  • 当前只存在一个主要 Gateway 进程,没有发现重复运行的主实例;
  • Gateway 主服务监听在本机 loopback 地址上;
  • 用户级 systemd 服务是当前主要启动入口;
  • 配置目录和工作目录权限较收敛;
  • 模型配置、通道插件、日志目录均能正常加载;
  • 未发现 systemd failed units。

这说明迁移后的实例基本可用,不属于“服务没起来”或“运行了错误实例”的情况。

不过自检也发现了几个需要继续收尾的问题:

  • 反代头部触发了 Proxy headers detected from untrusted address
  • Gateway 曾出现 memory pressure;
  • 日志中短暂出现过 native hook relay not found
  • webhook 端口存在非 loopback 监听,需要单独确认暴露范围;
  • 部分健康检查记录中仍残留旧路径;
  • 主机名相关信息存在不一致信号。

这些问题并不等于实例不可用,但说明迁移后仍需要做一轮细化确认。

问题一:trusted proxy warning 的真正含义

日志中最容易误判的一条 warning 是:

Proxy headers detected from untrusted address.
Connection will not be treated as local.
Configure gateway.trustedProxies to restore local client detection behind your proxy.

表面看,这像是某个内网地址访问了 OpenClaw,并携带了代理头。进一步查看完整上下文后,发现实际情况并不是“路由器直接访问了 Gateway”。

真正的连接关系是:

本机 loopback 代理 → OpenClaw Gateway

日志中的关键信息可以分成两类:

remote = ::1
fwd    = 内网路由器地址

其中:

  • remote=::1 表示实际 TCP peer 是本机 IPv6 loopback;
  • fwd=内网路由器地址 表示代理头里声明的原始客户端地址;
  • OpenClaw 判断 trusted proxy 时,关注的是实际连接它的代理来源,而不是 X-Forwarded-For 中声称的原始客户端。

因此,应该加入 trustedProxies 的不是路由器地址,而是本机 loopback 地址。

正确方向是:

["::1", "127.0.0.1"]

不应在证据不足的情况下把路由器地址加入 trusted proxy。因为当前证据只说明路由器地址出现在 forwarded header 中,并不是它直接连接 OpenClaw Gateway。

问题二:配置变更需要重启才能生效

设置 gateway.trustedProxies 后,日志出现了新的提示:

config change detected; evaluating reload
config change requires gateway restart

这说明 OpenClaw 已检测到配置变化,但该项不能热重载,必须重启 Gateway 才能生效。

这里有一个重要判断:

  • 如果只是普通 warning,可以先不重启;
  • 但此时 Gateway 同时存在 memory pressure;
  • 既然配置需要重启生效,而重启也能释放内存压力,那么执行一次服务重启是合理的。

重启后进程 PID 发生变化,说明新实例已经启动。之后重新检查日志,trusted proxy warning 未再出现,只剩下正常的 webchat loopback 连接记录。

这说明 ["::1","127.0.0.1"] 的判断是正确的,trusted proxy 配置已经生效。

问题三:内存压力被重启释放

重启前,Gateway 日志中出现过 memory pressure:

rss 约 1.4 GiB
heap 接近 1 GiB

这对小型主机来说偏高,尤其是在长期运行服务上,需要关注是否存在持续增长趋势。

重启后,systemd 显示 Gateway 当前状态为:

ActiveState=active
SubState=running
NRestarts=0
MemoryCurrent≈394 MiB

这说明:

  • 服务重启成功;
  • systemd 没有记录异常重启;
  • 内存占用从 1GiB 以上回落到几百 MiB;
  • 重启后的日志没有新的 memory pressure;
  • 暂时看不到持续性内存泄漏的证据。

不过这不等于内存问题永久消失。更稳妥的结论是:

memory pressure 已通过重启释放,短期未复现;后续需要观察数小时或一天,确认内存是否重新快速增长。

问题四:nativeHook 错误未复发

重启前日志中曾出现过:

nativeHook.invoke
native hook relay not found

这类错误通常意味着某个 UI 或本地集成功能尝试调用 native hook,但当前 Gateway 没有对应 relay。

在本次场景下,它有几个特征:

  • 出现在重启前旧进程日志中;
  • 重启后未复发;
  • 不影响 Gateway 主服务启动;
  • 不影响通道加载;
  • 不影响 Control UI 的基本连接。

因此,该问题暂时不需要作为高优先级故障处理。除非后续再次出现,并且伴随某个具体功能不可用,否则可以先归类为低优先级观察项。

问题五:Telegram 菜单长度提示不是故障

重启后的完整日志中出现一条 Telegram 相关提示:

menu text exceeded the conservative payload budget;
shortening descriptions to keep commands visible

这不是错误,而是 OpenClaw 自动处理 Telegram 菜单描述过长的问题。含义是:命令菜单描述文本超过保守预算,系统自动缩短描述,以确保命令仍能显示。

这类日志属于信息项,不需要修复。

重启后的健康状态

重启后日志显示 Gateway 顺利完成启动流程:

  • 模型配置加载完成;
  • HTTP server 开始监听;
  • 插件加载完成;
  • Nextcloud Talk webhook server 启动;
  • LINE provider 启动;
  • Telegram provider 启动;
  • heartbeat 启动;
  • Gateway ready;
  • Control UI 通过 loopback 正常连接;
  • 多个 WebSocket 请求返回成功;
  • 模型状态、通道状态、定时任务状态、日志 tail 等接口均能返回。

这说明 Gateway 当前不只是“进程存在”,而是主要功能已经进入可用状态。

本次实际解决的问题

本次排查和处理主要解决了三个问题:

1. 消除了 trusted proxy 误报警

通过分析 remotefwd 的区别,确认实际代理来源是本机 loopback,而不是内网路由器。随后将 loopback 地址加入 trusted proxy,并通过重启使配置生效。

结果:重启后不再出现 Proxy headers detected from untrusted address

2. 释放了 Gateway 的异常内存压力

重启前 Gateway 出现 memory pressure,内存占用明显偏高。由于 trusted proxy 配置也需要重启生效,因此执行一次 Gateway 重启,同时释放内存。

结果:内存从 1GiB 以上回落到约 394 MiB,重启后未再出现 memory pressure。

3. 排除了 nativeHook 的持续性故障

重启前出现过 native hook relay 相关错误,但重启后没有复发。当前没有证据表明它影响核心功能。

结果:暂时归类为低优先级观察项,而不是当前故障。

没有完全收尾的问题

本次没有直接处理所有潜在问题。仍有几项适合后续继续确认。

1. webhook 端口的暴露范围

Gateway 主端口绑定在 loopback 上,风险较低。但 webhook 端口监听在非 loopback 地址时,需要确认:

  • 是否只供内网反代访问;
  • 是否被路由器转发到公网;
  • 是否有来源限制;
  • 是否需要改成本机监听后由反代转发;
  • 是否存在被局域网其他设备直接访问的可能。

这个问题和 trusted proxy warning 不是同一个问题。trusted proxy warning 解决的是 Control UI / Gateway 入口的本机代理信任问题,而 webhook 端口暴露面需要单独确认。

2. 旧路径残留

健康检查文件或历史日志中仍可能出现迁移前路径。这类路径需要分清两种情况:

  • 只是历史记录:无需处理;
  • 当前配置仍在引用:需要修复。

不能看到旧路径就直接删除,也不能看到旧路径就立即判断为故障。应先确认是否仍被当前运行实例使用。

3. 主机名不一致

系统不同命令输出的主机名存在不一致信号。这通常不是 OpenClaw 本身故障,但会影响后续日志阅读、监控命名和运维判断。

如果该主机已经确定长期承担当前角色,后续可以单独整理主机名、hosts 文件和相关记录。

排查过程中的几个经验

1. 不要只看 warning 文案,要看完整上下文

Proxy headers detected from untrusted address 容易让人误以为某个内网设备直接访问了 Gateway。只有结合 remotefwd、监听地址和路由信息,才能判断真正的连接关系。

2. trusted proxy 应该信任“实际代理 peer”

X-Forwarded-For 里的地址不等于真实连接来源。trusted proxy 的核心是信任谁递交了这些代理头,而不是信任代理头里写了谁。

在本次场景中,应该信任的是 loopback 代理来源,而不是路由器地址。

3. 配置热重载和重启生效要区分

有些配置改完可以热重载,有些配置必须重启服务。本次 gateway.trustedProxies 就属于需要重启 Gateway 才能生效的配置。

看到 config change requires gateway restart 后,如果不重启,就不能用后续 warning 判断配置是否无效。

4. 旧日志和新进程日志要分开看

重启前后 PID 不同。判断问题是否复发时,应该以新 PID 或重启时间之后的日志为准。否则容易把旧进程的 memory pressure 或 nativeHook 错误误判为仍然存在。

5. 内存问题不要一次性下结论

重启后内存回落,只能说明压力已释放,不能立刻证明不存在内存泄漏。更合理的方式是继续观察:

systemctl --user show <gateway-service> \
  -p ActiveState -p SubState -p ExecMainPID -p MemoryCurrent -p NRestarts

如果数小时后仍保持在合理范围,就可以认为短期稳定。

当前结论

本次 OpenClaw Gateway 迁移后的几个主要问题已经收敛:

  • Gateway 服务正常运行;
  • trusted proxy warning 已消失;
  • Gateway 内存占用回落到合理范围;
  • nativeHook 错误未复发;
  • 主要通道和 Control UI 均能启动并响应;
  • 当前实例可以继续使用。

更准确的状态不是“完全没有问题”,而是:

当前 OpenClaw Gateway 已恢复到可继续使用的稳定状态。反代信任配置已修正,内存压力已释放。后续重点是观察内存是否重新增长,并单独确认 webhook 端口的暴露范围和迁移旧路径残留。

Leave a Reply

Your email address will not be published. Required fields are marked *