一个 npm install -g 命令,把线上服务干没了。不是网络问题,不是权限问题,是内存不够——升级进程被内核 OOM Killer 直接杀掉,留下一个残缺的安装目录。
这篇记录完整的故障链、修复过程,以及一个可复用的安全升级脚本。
发生了什么
2026-02-10 下午,在一台 2GB 内存的阿里云实例上执行 openclaw update。升级跑到一半,命令消失了:
/usr/bin/openclaw: No such file or directory
日志里是经典的 OOM 信号:
npm i openclaw@ invoked oom-killer
Out of memory: Killed process 198355 (npm i openclaw@)
为什么会这样

npm install -g 的全局安装流程是"先删旧版,再装新版"。中间没有事务保护。
当时的内存分布:
- npm install 进程:~700MB
- 运行中的 openclaw-gateway:~440MB
- 系统总内存:1.9GB,Swap:0
两个进程叠加超过物理内存上限,内核回收了 npm 进程。安装中断在"解压主包"阶段:
node_modules/目录存在,但只有依赖,没有主程序/usr/bin/openclaw软链接指向一个不存在的文件
结果:命令消失,服务不可用。
修复
补 Swap
dd if=/dev/zero of=/swapfile bs=1M count=2048
mkswap /swapfile && swapon /swapfile
echo '/swapfile none swap sw 0 0' >> /etc/fstab
清理残留 + 重装
rm -rf /usr/lib/node_modules/openclaw
npm install -g openclaw --ignore-scripts
--ignore-scripts 跳过 node-llama-cpp 编译。这台机器只做 Gateway 转发,不跑本地推理,编译步骤纯粹浪费内存。
安全升级脚本
手工升级每次都要记住"先停服务、看内存、跳过编译",迟早漏一步。脚本化:
#!/usr/bin/env bash
set -euo pipefail
echo "[1/5] stop gateway"
systemctl stop openclaw-gateway || true
echo "[2/5] cleanup old package"
rm -rf /usr/lib/node_modules/openclaw
rm -rf /usr/lib/node_modules/.openclaw-*
npm cache clean --force
echo "[3/5] install (skip local compilation)"
npm install -g openclaw --ignore-scripts
echo "[4/5] start gateway"
systemctl start openclaw-gateway || openclaw gateway --daemon
echo "[5/5] verify"
openclaw --version && openclaw status
核心思路:停服务释放内存 → 清理残留 → 低风险安装 → 重启验证。
几个教训

升级前看峰值,不是看空闲。空闲内存够不代表升级期间够。npm 安装会临时吃大量内存,和已有进程叠加很容易打穿上限。
Gateway-only 场景做依赖减法。不跑本地推理就不需要编译 llama.cpp。--ignore-scripts 一个参数能砍掉几百 MB 的内存峰值和 cmake 依赖。
低内存机器必须有 Swap。2GB 内存、0 Swap 的配置下,一次升级中断就能让服务不可用。加 2GB Swap 是成本最低的保险。
一次性操作固化成脚本。人会忘步骤,脚本不会。