概述

2026-07-17 上午发现 OpenClaw 无法使用,表现为 openclaw gateway restart 返回 command not found。经过系统性排查(系统日志、shell 历史、包管理日志、节点进程日志),定位到根因:WSL 关机重启后,nvm 未自动激活正确的 Node.js 版本,导致 npm 全局安装的 openclaw 命令不在 PATH 中,而非真正的卸载。

排查背景

  • Host:MS-Zephyrus16 (WSL2, Ubuntu 24.04.4 LTS)
  • 用户:montarius
  • OpenClaw 版本:v2026.7.1
  • Node.js 版本:v22.23.1 (nvm 管理)
  • Shell:zsh (oh-my-zsh) + bash
  • 系统架构:WSL2 子系统中运行,使用 systemctl --user 管理服务

📋 目录


排查目标与思路

目标

用户反馈:“帮我查一下昨天发生了什么,导致安装的 openclaw 被卸载”

当天上午执行 openclaw gateway restart 返回 command not found,用户据此推断 openclaw 被意外卸载。排查目标:确认是否真的发生了卸载,并定位根因。

排查思路

作为安全开发工程师,排查遵循系统取证分析标准流程:

text
┌─────────────────────────────────────────────────────┐
│  Step 1: 确认当前状态                                │
│  - openclaw 命令是否存在?                           │
│  - npm 全局包是否还在?                              │
│  - gateway 进程是否运行?                             │
├─────────────────────────────────────────────────────┤
│  Step 2: 查看系统日志 (journalctl)                   │
│  - 节点进程是否异常退出?                            │
│  - 有无信号终止 (SIGTERM/SIGKILL)?                  │
│  - 有无 OOM Killer 事件?                            │
├─────────────────────────────────────────────────────┤
│  Step 3: 分析 Shell 历史记录                        │
│  - 用户是否手动执行了 uninstall 命令?               │
│  - 确切的操作时间点                                  │
├─────────────────────────────────────────────────────┤
│  Step 4: 检查包管理器日志                            │
│  - dpkg/apt 日志中有无删除记录?                     │
├─────────────────────────────────────────────────────┤
│  Step 5: 分析身份认证日志 (auth.log)                 │
│  - sudo 执行记录,是否有 root 权限操作?             │
├─────────────────────────────────────────────────────┤
│  Step 6: 交叉验证进程生命周期                        │
│  - 节点进程 PID 生命周期                            │
│  - 系统启动/关闭时间                                │
└─────────────────────────────────────────────────────┘

排查原则:任何非预期的卸载通常会在系统层面留下痕迹。逐层排除才能定位根因,不能仅凭一个 command not found 就判断为卸载。


排查步骤详解

Step 1:确认当前状态

用户最初报告时,先确认 openclaw 的实际情况——是真卸载了还是只是 PATH 问题。

执行命令

bash
# 1. 检查命令是否存在
which openclaw
# 预期:返回路径,如 /home/montarius/.nvm/versions/node/v22.23.1/bin/openclaw
# 实际:which: no openclaw in (...)
 
# 2. 检查 npm 全局包是否还在
npm list -g openclaw
# 输出:
# /home/montarius/.nvm/versions/node/v22.23.1/lib
# └── openclaw@2026.7.1
 
# 3. 检查 nvm 状态
nvm --version   # 0.40.5
nvm list        # 查看已安装的 Node 版本
nvm ls          # 同上,查看当前激活版本

输出及解读

text
$ which openclaw
which: no openclaw in (/usr/local/bin:/usr/bin:/bin)
 
$ npm list -g openclaw
/home/montarius/.nvm/versions/node/v22.23.1/lib
└── openclaw@2026.7.1

关键发现which openclaw 找不到,但 npm list -g openclaw 显示包仍然存在。这是一个矛盾的信号——包没有被卸载,只是命令不在 PATH 中。


Step 2:分析系统日志 (journalctl)

使用 journalctl 查看 systemd 日志中的 Node.js 进程活动,确定 gateway 进程在 7/16 是否正常运行,以及退出方式。

2.1 查看 7/16 全天的节点进程日志

bash
# 查看 2026-07-16 全天日志中 openclaw 相关(PID 98829)
journalctl --since "2026-07-16 00:00:00" --until "2026-07-16 23:59:59" \
  --no-pager | grep "node\[98829\]" | less

输出示例(全天共 1142 条日志):

text
Jul 16 00:05:36 MS-Zephyrus16 node[98829]: 2026-07-16T00:05:36.521+08:00 [agents/tool-policy] tool policy removed 5 tool(s) via tools.profile (coding): agents_list, gateway, message, nodes, tts
Jul 16 00:05:36 MS-Zephyrus16 node[98829]: 2026-07-16T00:05:36.643+08:00 [provider-transport-fetch] [model-fetch] start provider=custom-claudecode-internal-geelib-360-cn api=anthropic-messages model=claude-sonnet-4-6 method=POST
Jul 16 00:05:36 MS-Zephyrus16 node[98829]: 2026-07-16T00:05:36.721+08:00 [provider-transport-fetch] [model-fetch] response provider=custom-claudecode-internal-geelib-360-cn api=anthropic-messages model=claude-sonnet-4-6 status=200 elapsedMs=75
Jul 16 00:05:40 MS-Zephyrus16 node[98829]: 2026-07-16T00:05:40.336+08:00 [tools] read failed: ENOENT: no such file or directory, access '/home/montarius/.openclaw/workspace/memory/task-queue.json'
...
Jul 16 09:00:10 MS-Zephyrus16 node[98829]: 2026-07-16T09:00:10.444+08:00 [agents/tool-policy] tool policy removed 5 tool(s) via tools.profile (coding): agents_list, gateway, message, nodes, tts
Jul 16 09:00:11 MS-Zephyrus16 node[98829]: 2026-07-16T09:00:11.095+08:00 [provider-transport-fetch] [model-fetch] response provider=... status=200 elapsedMs=102
...
Jul 16 22:19:49 MS-Zephyrus16 node[98829]: 2026-07-16T22:19:49.359+08:00 [memory] sync failed (session-start): Error: No API key found for provider "openai"

解读

  • PID 98829 在 7/16 全天都有日志输出(活跃),进程持续运行
  • 内容主要是 tool policy 变更、model-fetch 请求/响应、tools read failed(task-queue.json 不存在属于正常现象)
  • 有一个已知的 memory sync failed(OpenAI key 缺失),但这是已知问题,不影响 gateway 正常运行
  • 其中 11:07 和 11:14 有 LLM idle timeout,说明模型有超时,但进程未崩溃

2.2 检查进程退出方式

bash
# 查看 WSL 关机时刻的日志
journalctl --since "2026-07-17 00:44:00" --until "2026-07-17 00:46:00" \
  --no-pager

输出

text
Jul 17 00:44:25 MS-Zephyrus16 systemd-resolved[161]: Clock change detected. Flushing caches.
Jul 17 00:44:43 MS-Zephyrus16 node[98829]: [ws] webchat disconnected code=1006 reason=n/a
Jul 17 00:44:53 MS-Zephyrus16 node[98829]: [skills] watcher error: EFAULT: bad address
Jul 17 00:44:53 MS-Zephyrus16 node[98829]: [skills] watcher error: EIO: i/o error
Jul 17 00:45:01 MS-Zephyrus16 unknown: WSL Relay ERROR: ReceiveMessage:253: ExpectedMessage LxInitMessageExitStatus, but socket Control was closed
Jul 17 00:45:05 MS-Zephyrus16 systemd-logind[179]: The system will power off now!
Jul 17 00:45:05 MS-Zephyrus16 systemd[1]: Stopping session-2.scope...
Jul 17 00:45:05 MS-Zephyrus16 systemd[233]: Stopping openclaw-gateway.service...
Jul 17 00:45:05 MS-Zephyrus16 node[98829]: [gateway] signal SIGTERM received
Jul 17 00:45:05 MS-Zephyrus16 node[98829]: [gateway] received SIGTERM; shutting down
Jul 17 00:45:07 MS-Zephyrus16 systemd[233]: Stopped openclaw-gateway.service - OpenClaw Gateway (v2026.7.1).

解读

  • webchat disconnected code=1006 — WebSocket 在关机前先断开
  • watcher error — WSL 关机过程中文件系统不可用,属于正常行为
  • SIGTERM receivedshutting down进程正常终止(非崩溃、非 OOM)
  • Stopped openclaw-gateway.servicesystemd 安全停止服务

2.3 检查是否有 OOM Killer 事件

bash
# 方法一:journalctl 内核日志
journalctl -k | grep -iE "oom|kill|out of memory"
 
# 方法二:dmesg
dmesg | grep -iE "oom|kill|out of memory"

输出

text
[  823.630231] WSL (219 - GnsEngine) ERROR: nft -a list chain ip nat WSLPOSTROUTING killed by signal 13

解读:唯一的相关日志是 WSL 内一个 nft(网络过滤)进程被 signal 13 杀死,与 openclaw 完全无关。无 OOM 事件


Step 3:分析 Shell 历史记录

系统上有两个历史文件:~/.bash_history(bash,记录命令文本)和 ~/.zsh_history(zsh,带 Unix 时间戳)。

3.1 zsh 历史文件格式说明

zsh 历史记录中的每一行格式如下:

text
: <unix_timestamp>:<elapsed_seconds>;<command>

示例:

text
: 1784025455:0;openclaw gateway restart

时间戳 1784025455 是 Unix 时间戳(自 1970-01-01 以来的秒数),可用 date 命令转换为可读时间:

bash
date -d @1784025455 '+%Y-%m-%d %H:%M:%S %Z'
# 输出:2026-07-14 18:37:35 CST

3.2 提取目标时间段的所有命令(shell 脚本方式)

bash
# 提取 2026-07-14 的所有 openclaw 相关命令
cat /home/montarius/.zsh_history | while IFS= read -r line; do
    ts=$(echo "$line" | grep -oP '^: \K[0-9]+')
    cmd=$(echo "$line" | sed 's/^: [0-9]*:[0-9]*;//')
    if [ -n "$ts" ]; then
        day=$(date -d @"$ts" '+%Y-%m-%d' 2>/dev/null)
        if [ "$day" = "2026-07-14" ]; then
            echo "$(date -d @"$ts" '+%Y-%m-%d %H:%M:%S') | $cmd"
        fi
    fi
done 2>/dev/null | grep -E "openclaw|uninstall|rm " | head -40

3.3 关键发现(7/14 的操作)

bash
# 插件安装和清理
2026-07-14 17:32:50 | openclaw plugins install headroom          # 安装 headroom 插件
2026-07-14 17:38:20 | openclaw update                            # 检查更新
2026-07-14 17:42:38 | curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.5/install.sh | bash  # 升级 nvm
2026-07-14 17:43:11 | nvm install 22                              # 安装 Node.js v22
2026-07-14 17:45:05 | npm i -g openclaw                           # 重新安装 openclaw
2026-07-14 17:45:23 | npm i -g openclaw@latest                     # 安装最新版
2026-07-14 17:55:43 | ps aux | grep openclaw                       # 检查进程
2026-07-14 17:59:29 | rm -rf ~/.openclaw/extensions/feishu         # 删除 feishu 插件目录
2026-07-14 18:06:17 | rm -rf ~/.openclaw/extensions/headroom       # 删除 headroom 插件目录
2026-07-14 18:27:00 | pkill -f openclaw                            # 强制终止旧 gateway
2026-07-14 18:27:06 | find ~/.openclaw -name "*.lock" -o -name "*migration*" 2>/dev/null  # 清理锁文件
2026-07-14 18:27:41 | rm -rf ~/.openclaw/.openclaw-install-stage-* # 清理安装残留
2026-07-14 18:27:45 | rm -f ~/.openclaw/*.db-wal ~/.openclaw/*.db-shm  # 清理数据库 WAL 文件
2026-07-14 18:37:35 | openclaw plugins uninstall feishu --force     # 卸载 feishu 插件
2026-07-14 18:38:33 | openclaw plugins install @openclaw/feishu     # 重新安装 feishu
2026-07-14 18:40:00 | nvm use --delete-prefix v22.23.1              # 设置正确的 Node 版本

解读

  • 7/14 的操作全部是插件管理(安装/卸载 feishu、headroom)和 nvm 版本升级,没有 npm uninstall openclawapt remove openclaw 等真正的卸载命令
  • 唯一的 uninstall 命令是 openclaw plugins uninstall feishu --force,这是卸载插件而非主程序
  • 所有 rm -rf 针对的是 ~/.openclaw/extensions/(插件目录),不是 openclaw 主程序目录
  • 用户确实在 7/14 做了大量清理工作(共涉及 20+ 条命令),但这些都是清理插件、升级版本,不是卸载主程序

3.4 检查 7/17 当天的操作记录

bash
# 提取今天 (2026-07-17) 的所有命令
cat /home/montarius/.zsh_history | while IFS= read -r line; do
    ts=$(echo "$line" | grep -oP '^: \\K[0-9]+')
    cmd=$(echo "$line" | sed 's/^: [0-9]*:[0-9]*;//')
    if [ -n "$ts" ]; then
        day=$(date -d @"$ts" '+%Y-%m-%d' 2>/dev/null)
        if [ "$day" = "2026-07-17" ]; then
            echo "$(date -d @"$ts" '+%Y-%m-%d %H:%M:%S') | $cmd"
        fi
    fi
done 2>/dev/null | head -30

输出

text
2026-07-17 08:09:51 | openclaw gateway restart          ← 第一次尝试,command not found ❌
2026-07-17 08:10:29 | which openclaw                     ← 确认命令不存在
2026-07-17 08:12:17 | echo $PATH                         ← 查看当前 PATH
2026-07-17 08:13:34 | source ~/.zshrc                     ← 尝试重新加载配置
2026-07-17 08:13:41 | which openclaw                     ← 仍然找不到
2026-07-17 08:14:52 | npm list -g openclaw                ← 检查包是否存在
2026-07-17 08:15:51 | nvm --version                       ← 检查 nvm 状态
2026-07-17 08:15:56 | nvm list                            ← 列出 Node 版本
2026-07-17 08:16:06 | nvm use --delete-prefix v22.23.1    ← 激活正确版本
2026-07-17 08:16:14 | which openclaw                     ← ✅ 现在能找到了!
2026-07-17 08:16:18 | nvm ls
2026-07-17 08:17:04 | node -v
2026-07-17 08:17:17 | which npm
2026-07-17 08:17:29 | npm install -g openclaw              ← 重新安装(保证万无一失)
2026-07-17 08:18:28 | openclaw doctor --fix                ← 修复配置
2026-07-17 08:19:10 | openclaw gateway restart             ← ✅ 成功启动!
2026-07-17 08:24:13 | which openclaw                     ← 确认持久可用

解读

  • 08:09 报 command not found → 用户推断为被卸载,但实际上包仍在,只是 PATH 中没有
  • 08:10–08:14 是排查阶段(检查 PATH、nvm、npm)
  • 08:16 nvm use --delete-prefix v22.23.1which openclaw 立刻恢复 ✅ 这是锁死根因的关键
  • 08:17 虽然是”重新安装”,但实际上包已经存在,这是出于保险操作的

3.5 验证无 uninstall 命令

bash
# 在全量历史中搜索任何可能的卸载命令
cat /home/montarius/.zsh_history | while IFS= read -r line; do
    ts=$(echo "$line" | grep -oP '^: \K[0-9]+')
    cmd=$(echo "$line" | sed 's/^: [0-9]*:[0-9]*;//')
    if echo "$cmd" | grep -qiE "uninstall|unlink|remove.*openclaw"; then
        dt=$(date -d @"$ts" '+%Y-%m-%d %H:%M:%S')
        echo "$dt | $cmd"
    fi
done 2>/dev/null

输出:(无任何匹配项)

同样检查 bash_history 中是否有卸载命令:

bash
grep -iE "uninstall|remove.*openclaw|unlink" /home/montarius/.bash_history

输出:(无任何匹配项)


Step 4:分析系统包管理器日志

因为 openclaw 不是系统包(非 apt/dpkg 安装的),这个步骤主要是为了确认系统层面没有任何卸载操作,以及检查是否有系统回滚或依赖冲突。

4.1 检查 dpkg 日志

bash
# 查看 7/16 的 dpkg 变更
grep "2026-07-16" /var/log/dpkg.log

输出:(无任何输出——7/16 没有任何 dpkg 操作)

4.2 检查 apt history 日志

bash
cat /var/log/apt/history.log | tail -50

输出

text
Start-Date: 2026-07-15  08:42:15
Commandline: /usr/bin/unattended-upgrade
Upgrade: libasound2t64:amd64 (1.2.11-1ubuntu0.2, 1.2.11-1ubuntu0.3)
End-Date: 2026-07-15  08:42:16
 
Start-Date: 2026-07-15  08:42:17
Commandline: /usr/bin/unattended-upgrade
Upgrade: openssh-client:amd64 (1:9.6p1-3ubuntu13.16, 1:9.6p1-3ubuntu13.18)
End-Date: 2026-07-15  08:42:18
 
Start-Date: 2026-07-17  08:21:59
Commandline: /usr/bin/unattended-upgrade
Upgrade: python3-idna:amd64 (3.6-2ubuntu0.1, 3.6-2ubuntu0.2)
End-Date: 2026-07-17  08:21:59
 
Start-Date: 2026-07-17  08:22:01
Commandline: /usr/bin/unattended-upgrade
Upgrade: libheif1:amd64 (1.17.6-1ubuntu4.4, 1.17.6-1ubuntu4.6), ...
End-Date: 2026-07-17  08:22:02
 
Start-Date: 2026-07-17  08:22:03
Commandline: /usr/bin/unattended-upgrade
Upgrade: vim:amd64 (2:9.1.0016-1ubuntu7.17, 2:9.1.0016-1ubuntu7.18), ...
End-Date: 2026-07-17  08:22:06
 
Start-Date: 2026-07-17  08:22:06
Commandline: /usr/bin/unattended-upgrade
Upgrade: wget:amd64 (1.21.4-1ubuntu4.1, 1.21.4-1ubuntu4.3)
End-Date: 2026-07-17  08:22:07

解读:7/16 没有任何 apt 操作。7/15 和 7/17 的变更都是 unattended-upgrades 自动安全更新(libasound、openssh-client、python3-idna、vim、wget 等)——与 openclaw 无关


Step 5:分析身份认证日志 (auth.log)

检查是否有 sudo 或 root 权限下的 uninstall 操作,排除安全事件可能性。

bash
# 查看 7/16 的身份认证日志
cat /var/log/auth.log | grep "2026-07-16"

输出

text
2026-07-16T00:00:06.395748+08:00 MS-Zephyrus16 CRON[200787]: pam_unix(cron:session): session opened for user montarius(uid=1000) by montarius(uid=0)
2026-07-16T00:00:06.656527+08:00 MS-Zephyrus16 CRON[200787]: pam_unix(cron:session): session closed for user montarius
2026-07-16T00:10:06.203752+08:00 MS-Zephyrus16 CRON[202512]: pam_unix(cron:session): session opened for user montarius(uid=1000) by montarius(uid=0)
2026-07-16T00:10:06.509337+08:00 MS-Zephyrus16 CRON[202512]: pam_unix(cron:session): session closed for user montarius
2026-07-16T00:17:05.643630+08:00 MS-Zephyrus16 CRON[203677]: pam_unix(cron:session): session opened for user root(uid=0) by root(uid=0)
2026-07-16T00:17:05.646844+08:00 MS-Zephyrus16 CRON[203677]: pam_unix(cron:session): session closed for user root
2026-07-16T00:20:06.311747+08:00 MS-Zephyrus16 CRON[204173]: pam_unix(cron:session): session opened for user montarius(uid=1000) by montarius(uid=0)
2026-07-16T00:20:06.494510+08:00 MS-Zephyrus16 CRON[204173]: pam_unix(cron:session): session closed for user montarius
...

解读:全部是 CRON 定时任务会话的 open/close 事件,只有两种用户:

  • montarius(uid=1000) — 用户自身的 cron 任务(session-tagger,每 10 分钟执行一次)
  • root(uid=0) — root 的 cron 任务

没有任何 sudo 执行记录、没有任何 apt-get/dpkg 提权操作


Step 6:交叉验证关机和重启事件

通过 last -xwho -b 确定系统的完整运行和重启历史。

bash
# 查看系统启动记录
who -b
 
# 查看完整的运行级别变更历史
last -x | head -20

输出

text
         system boot  2026-07-17 08:07
 
runlevel (to lvl 5)   6.6.87.2-microso Fri Jul 17 08:08   still running
reboot   system boot  6.6.87.2-microso Fri Jul 17 08:07   still running
shutdown system down  6.6.87.2-microso Fri Jul 17 00:45 - 08:07  (07:22)
runlevel (to lvl 5)   6.6.87.2-microso Tue Jul 14 18:25 - 00:45 (2+06:19)
reboot   system boot  6.6.87.2-microso Tue Jul 14 18:25 - 00:45 (2+06:19)
shutdown system down  6.6.87.2-microso Tue Jul 14 18:25 - 18:25  (00:00)
runlevel (to lvl 5)   6.6.87.2-microso Tue Jul 14 16:30 - 18:25  (01:54)
reboot   system boot  6.6.87.2-microso Tue Jul 14 16:30 - 18:25  (01:54)
runlevel (to lvl 5)   6.6.87.2-microso Thu Jul  9 12:48 - 16:30 (5+03:41)
reboot   system boot  6.6.87.2-microso Thu Jul  9 12:48 - 18:25 (5+05:36)

解读

text
系统运行时间表:
──────────────────────────────────────────────────────
7/8  08:15 ─→ 08:22   (0h07m)
7/8  08:28 ─→ 7/9 12:48 (1d04h)
7/9  12:48 ─→ 7/14 18:25 (5d05h)  ← 最长运行
7/14 18:25 ─→ 7/17 00:45 (2d06h)  ← 本次关键周期 ↑
                  ↓ ★ 关机 ★
7/17 08:07 ─→ 至今                ← 本次重启后出问题
──────────────────────────────────────────────────────

关键时间点:

  • 7/14 18:25 系统重启(当时 openclaw 正常工作)
  • 7/17 00:45 系统 shutdown(openclaw gateway 收到 SIGTERM 正常停止)
  • 7/17 08:07 系统重启(这是问题发生的时间点——重启后 nvm 未激活)

排查结论:根因定位

根因:nvm Node.js 版本未自动激活

bash
# openclaw 的实际安装路径
# npm 全局包位置:
/home/montarius/.nvm/versions/node/v22.23.1/lib/node_modules/openclaw/
 
# 对应的二进制链接(symlink):
/home/montarius/.nvm/versions/node/v22.23.1/bin/openclaw
 
# nvm 的安装路径(从 ~/.zshrc 配置确认):
export NVM_DIR="$HOME/.nvm"                                    # line 128
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"              # line 129
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"  # line 130

问题链

text
WSL 关机 (7/17 00:45)   ← 用户关闭 WSL/Windows 导致

WSL 重启 (7/17 08:07)   ← 用户重新打开

Shell 启动(zsh)

~/.zshrc 执行 → nvm.sh 理论上应被 source

但 nvm 的 default alias **可能没有设置**,或者 ~/.zshrc 的 nvm 初始化
  在非交互模式下未被正确调用

PATH 中不包含 /home/montarius/.nvm/versions/node/v22.23.1/bin/
   (该路径由 nvm use 激活后动态添加到 PATH)

which openclaw → 找不到该命令

用户误认为 openclaw 被卸载

为什么 nvm 版本没激活?

有几种可能性:

  1. nvm default alias 未设置:执行 nvm alias default v22.23.1 后才算设好默认版本,否则 nvm 不会在 shell 启动时自动切换
  2. 首次打开的 Shell 可能不是交互式:WSL 启动后的某些自动化任务可能使用非交互 shell
  3. ~/.zshrc 条件判断分支:某些 .zshrc 配置在不同条件下(本地/SSH)加载不同的 PATH
  4. --delete-prefix 的必要性:从输出看,用户最终用了 nvm use --delete-prefix 而非 nvm use,说明之前存在 prefix 冲突

关键证据

从 shell history 可以看到精确的修复过程:

text
08:15:56 | nvm list                  ← 查看已安装版本
08:16:06 | nvm use --delete-prefix v22.23.1  ← 激活版本(需要 --delete-prefix!)
08:16:14 | which openclaw            ← ✅ 立刻找到了!

nvm use 之后立刻 which openclaw 成功,这直接证明了问题确实出在 nvm 版本激活上

问题复原场景

“作案”过程复原

text
你在 7/14 晚上做了一些插件清理和 nvm 升级操作:
  ├─ 安装 nvm 0.40.5(之前是旧版)
  ├─ nvm install 22(安装 Node 22)
  ├─ 重新安装 openclaw
  └─ 删除插件目录、清理残留
 
然后系统持续正常运行了约 2 天(7/14 18:25 → 7/17 00:45)
 
7/17 凌晨你关闭了 WSL(或 Windows 关机/休眠)
  → openclaw gateway 收到 SIGTERM,正常停止
 
7/17 早上你重新打开 WSL
  → WSL 启动
  → systemd 启动 openclaw-gateway.service(服务本身正常,用了硬编码路径)
  → 但你打开的交互式 Shell 中,nvm 没有激活 Node 22
  → PATH 中没有 node/npm 的 bin 目录
  → 你运行 openclaw → command not found
 
后续排查:
  → which openclaw → 找不到
  → npm list -g openclaw → 发现包还在 ✅
  → nvm use → 激活版本
  → which openclaw → ✅ 恢复了!
  → 保险起见还是重新安装了一次

为什么不是真正的卸载

排除项证据结论
npm uninstallShell history 中没有任何 npm uninstall 命令非卸载
apt/dpkg 卸载dpkg.log 中 7/16 无记录,apt history 只有 unattended-upgrades非系统包操作
OOM Killerjournalctl -k 和 dmesg 无 OOM 事件非进程崩溃
用户手动删除所有 rm 操作针对的是插件目录,非主程序非手动删除
系统回滚apt history.log 只有普通安全更新非系统变更
恶意软件/入侵auth.log 无异常 sudo/root 操作非安全事件
磁盘损坏/坏道磁盘 I/O 日志无异常非硬件问题

完整事件时间线

text
2026-07-09
  ├─ 16:34   安装 nvm、Node.js、配置 node 版本
  └─ 16:55   npm install -g openclaw
 
2026-07-12
  └─ 09:44   openclaw gateway restart
 
2026-07-14
  ├─ 17:23   开始处理 headroom 插件 (openclaw plugins install headroom)
  ├─ 17:42   nvm 操作 (升级到 v0.40.5)
  ├─ 17:43   nvm install 22
  ├─ 17:45   npm install -g openclaw & openclaw@latest
  ├─ 17:59   rm -rf ~/.openclaw/extensions/feishu          ← 删除插件目录
  ├─ 18:06   rm -rf ~/.openclaw/extensions/headroom         ← 删除插件目录
  ├─ 18:27   pkill -f openclaw                              ← 强制重启 gateway
  ├─ 18:27   清理:锁文件、安装残留、数据库 WAL
  ├─ 18:37   openclaw plugins uninstall feishu --force      ← 卸载 feishu 插件
  ├─ 18:38   openclaw plugins install @openclaw/feishu      ← 重新安装
  └─ 18:40   nvm use --delete-prefix v22.23.1               ← 设置 Node 版本
 
2026-07-15                  ← openclaw 正常运行一整天
  ├─ 08:44   openclaw gateway restart
  ├─ 11:22   openclaw gateway restart
  ├─ 14:46   openclaw gateway restart
  └─ 17:14   openclaw gateway restart
 
2026-07-16                  ← openclaw 正常运行(7/15 22:22 启动后持续运行)
  ├─ 00:05~22:19   节点进程 98829 持续活跃(1142 条日志)
  ├─ 01:35~全天    memory sync failed(OpenAI key 缺失,已知问题)
  ├─ 11:07~11:14   LLM idle timeout(模型超时,不影响进程)
  ├─ 19:47         feishu/lark 连接 ping_timeout 出错
  └─ 全天          session-tagger cron 每 10分钟运行一次
 
2026-07-17 (今天)
  ├─ 00:18         openclaw gateway 正常运行(tool policy 更新)
  ├─ 00:44         webchat 断开(WSL 关机前兆)
  ├─ 00:45 ★★★    系统关机 (WSL shutdown) ★★★
  │                 └─ openclaw-gateway.service 收到 SIGTERM → 正常停止
  ├─ 08:07 ★★★    系统重启 (WSL boot) ★★★
  │                 └─ ⚠️ 此时 nvm 默认版本未激活 → openclaw 命令不可用
  ├─ 08:09         openclaw gateway restart → command not found ❌  ← 用户报告的时刻
  ├─ 08:10         which openclaw → 找不到
  ├─ 08:14         npm list -g openclaw → 发现包仍在 ✅
  ├─ 08:16         nvm use --delete-prefix v22.23.1 ✅  ← 根因确认
  ├─ 08:17         npm install -g openclaw(保险操作)
  ├─ 08:18         openclaw doctor --fix(修复配置)
  └─ 08:19         openclaw gateway restart → 成功启动 ✅

修复步骤

已执行的操作

bash
# 1. 激活正确的 Node.js 版本(核心修复)
nvm use --delete-prefix v22.23.1
# 注:--delete-prefix 参数必要,说明之前可能存在 nvm prefix 冲突
 
# 2. 确认 node/npm 正常
node -v     # v22.23.1
npm -v      # 10.x.x
which npm   # 确认 npm 在 PATH 中
 
# 3. 重新安装 openclaw 全局包(保险操作,覆盖安装)
npm install -g openclaw
 
# 4. 运行诊断修复(修复可能残缺的配置)
openclaw doctor --fix
 
# 5. 重启 gateway
openclaw gateway restart
 
# 6. 验证持久可用
which openclaw
openclaw --version

建议的预防措施

1. 设置 nvm 默认版本

bash
# 设置默认版本——下次 shell 启动时会自动切换
nvm alias default v22.23.1
 
# 验证默认版本已设置
nvm ls
# 输出应看到:
#       v22.23.1
# default -> v22.23.1

2. 验证 ~/.zshrc 中的 nvm 初始化配置

bash
# 检查 ~/.zshrc 中是否有以下配置
grep -n "NVM_DIR\|nvm.sh" ~/.zshrc

期望输出(当前已有):

text
128:export NVM_DIR="$HOME/.nvm"
129:[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"  # This loads nvm
130:[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"  # This loads nvm bash_completion

3. 在 ~/.profile 中也添加 nvm 初始化

WSL 启动时 ~/.profile 会被读取,而 ~/.zshrc 只在交互式 zsh 会话中读取。为保险起见建议也在 ~/.profile 中添加:

bash
# ~/.profile 中添加
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"

4. 验证开机自启服务

bash
# 检查 openclaw gateway 的 systemd 用户服务状态
systemctl --user status openclaw-gateway.service
 
# 注意:systemd service 使用硬编码的绝对路径
# 见 ~/.config/systemd/user/openclaw-gateway.service 中的 ExecStart
# 所以服务本身会正常启动,不受 nvm 影响

5. 手动诊断工具

bash
# 遇到类似情况时,快速诊断命令链
alias diag_openclaw='echo "--- PATH check ---"; echo $PATH | tr ":" "\n" | grep nvm; echo "--- npm global ---"; npm list -g openclaw 2>/dev/null; echo "--- which ---"; which openclaw; echo "--- nvm ---"; nvm current'

附录

命令参考速查表

Step 1:当前状态检查

bash
# 命令是否存在
which openclaw
 
# npm 全局包
npm list -g openclaw
 
# 查看 nvm 状态
nvm --version
nvm list
nvm current
node -v

Step 2:系统日志

bash
# 查看时间段内节点进程日志
journalctl --since "2026-07-16 00:00:00" --until "2026-07-16 23:59:59" --no-pager | grep "node\[98829\]"
 
# 查看关机时刻日志
journalctl --since "2026-07-17 00:44:00" --until "2026-07-17 00:46:00" --no-pager
 
# 检查 OOM
journalctl -k | grep -iE "oom|kill|out of memory"
dmesg | grep -iE "oom|kill|out of memory"

Step 3:Shell 历史

bash
# zsh 历史时间戳转换(单条)
date -d @1784025455 '+%Y-%m-%d %H:%M:%S %Z'
 
# 批量提取某天的历史
cat /home/montarius/.zsh_history | while IFS= read -r line; do
    ts=$(echo "$line" | grep -oP '^: \K[0-9]+')
    cmd=$(echo "$line" | sed 's/^: [0-9]*:[0-9]*;//')
    if [ -n "$ts" ]; then
        day=$(date -d @"$ts" '+%Y-%m-%d' 2>/dev/null)
        if [ "$day" = "2026-07-17" ]; then
            echo "$(date -d @"$ts" '+%Y-%m-%d %H:%M:%S') | $cmd"
        fi
    fi
done 2>/dev/null

Step 4:包管理器日志

bash
# dpkg 日志
cat /var/log/dpkg.log | grep "2026-07-16"
 
# apt 历史
cat /var/log/apt/history.log | tail -50

Step 5:身份认证日志

bash
cat /var/log/auth.log | grep "2026-07-16"

Step 6:系统重启记录

bash
who -b                           # 最近一次启动时间
last -x | grep -E "reboot|shutdown|runlevel"  # 完整启动/关闭历史

nvm 相关操作

bash
# 查看当前版本
nvm current
 
# 列出所有版本
nvm ls
 
# 激活版本(有 prefix 冲突时加 --delete-prefix)
nvm use v22.23.1
nvm use --delete-prefix v22.23.1   # 处理 prefix 冲突
 
# 设置默认版本
nvm alias default v22.23.1
 
# 查看 nvm 配置
echo $NVM_DIR
cat ~/.zshrc | grep nvm

日志文件路径索引

日志路径用途
systemd 日志journalctl(命令行工具)系统服务、节点进程、关机事件
内核日志journalctl -k / dmesgOOM Killer、硬件错误
apt 历史/var/log/apt/history.logapt 安装/升级/删除记录
dpkg 操作/var/log/dpkg.log包管理器详细操作日志
身份认证/var/log/auth.logsudo、su、登录等鉴权事件
Zsh 历史~/.zsh_history用户交互式 shell 命令(带时间戳)
Bash 历史~/.bash_historybash 命令记录(无时间戳)
npm 全局包npm list -gnpm 全局安装的包列表
npm 日志~/.npm/_logs/*.lognpm 安装/卸载详细日志
OpenClaw 日志/tmp/openclaw/openclaw-*.loggateway 进程日志
用户 serivce 配置~/.config/systemd/user/openclaw-gateway.servicesystemd 服务定义
session-tagger 日志~/.openclaw/workspace/skills/session-tagger/runner.log自动标签 cron 任务日志

systemd 服务配置原文

ini
# /home/montarius/.config/systemd/user/openclaw-gateway.service
[Unit]
Description=OpenClaw Gateway (v2026.7.1)
After=network-online.target
Wants=network-online.target
StartLimitBurst=5
StartLimitIntervalSec=60
 
[Service]
ExecStart=/home/montarius/.nvm/versions/node/v22.23.1/bin/node \
  /home/montarius/.npm-global/lib/node_modules/openclaw/dist/index.js \
  gateway --port 18789
Restart=always
RestartSec=5
RestartPreventExitStatus=78
TimeoutStopSec=30
TimeoutStartSec=30
SuccessExitStatus=0 143
OOMPolicy=continue
KillMode=control-group
Environment=HOME=/home/montarius
Environment=TMPDIR=/tmp
Environment=NODE_EXTRA_CA_CERTS=/etc/ssl/certs/ca-certificates.crt
Environment=PATH=/home/montarius/.nvm/versions/node/v22.23.1/bin:\
  /home/montarius/.npm-global/bin:/usr/local/bin:/usr/bin:/bin:\
  /home/montarius/.nvm/current/bin
Environment=OPENCLAW_GATEWAY_PORT=18789
Environment=OPENCLAW_SYSTEMD_UNIT=openclaw-gateway.service
Environment="OPENCLAW_WINDOWS_TASK_NAME=OpenClaw Gateway"
Environment=OPENCLAW_WINDOWS_TASK_HIDDEN_LAUNCHER=1
Environment=OPENCLAW_SERVICE_MARKER=openclaw
Environment=OPENCLAW_SERVICE_KIND=gateway
Environment=OPENCLAW_SERVICE_VERSION=2026.7.1
 
[Install]
WantedBy=default.target

注意:systemd 服务中 ExecStart 使用硬编码的绝对路径/home/montarius/.nvm/versions/node/v22.23.1/bin/),因此服务在系统启动时能正常启动,不受用户的交互式 shell PATH 影响。这解释了为什么 systemctl --user status openclaw-gateway.service 显示服务在运行,但用户在终端中输入 openclaw 却找不到命令——这是用户 shell 环境变量的问题,不是服务本身的问题。


声明:本文撰写于排查事件当天(2026-07-17),为安全取证过程的完整记录。文中所有日志时间戳均为 Asia/Shanghai (UTC+8) 时区。