ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

Windows+WSL2部署OpenClaw常驻助手:环境、systemd与排错

Windows+WSL2部署OpenClaw常驻助手:环境、systemd与排错

很多人第一次在 Windows 上折腾这类开源自托管助手,卡住的地方往往不是软件本身,而是环境。我去年年底第一次把 OpenClaw 拉到本地时,图省事直接在本机装了 Node 就跑,结果从依赖编译到浏览器自动化一路报错,折腾了两个晚上没跑起来。后来换成 WSL2 里的 Ubuntu,同样的命令一次就通过了——不是因为 WSL 更“高级”,而是因为 OpenClaw 这类的项目从设计之初就是奔着 Linux 服务器去的,它的进程管理、伪终端、文件监听、后台常驻逻辑全都建立在 POSIX 语义上。这篇就把我在 Windows + WSL2 环境下把 OpenClaw 从零装到能长期稳定挂着跑的完整过程写清楚,包括每一步为什么这么做、哪些地方最容易翻车、翻车之后怎么定位。适合手上只有一台 Windows 笔记本、又想在自己机器上跑一个常驻助手的同学,完全没接触过 Linux 的也能跟着走。

1. 为什么这套东西必须放进 WSL 而不是硬刚 Windows

1.1 依赖树里那些只认 Linux 的硬骨头

先说清楚一个前提:把 OpenClaw 装进 WSL,不是因为我偏爱 Linux,而是纯 Windows 环境下有几处结构性障碍绕不过去。第一处是进程与伪终端。这类助手型项目要执行命令、要开交互式子进程、要读取子进程的实时输出流,依赖的是pty(伪终端)这套机制。Windows 的conhost和 Win32 管道模型跟 POSIX 完全是两套东西,Node 生态里那些封装node-pty的包在 Windows 上虽然能编译,但对交互式程序的兼容性极差,经常出现输出卡住、Ctrl+C 传不进去、进程退出了但句柄没释放的情况。

第二处是文件监听。助手要盯着工作目录里的文件变化来触发行为,底层靠inotify。Windows 上 Node 用的是轮询式 fallback,几千个文件的项目目录一盯,CPU 直接飙上去,而且事件还有几百毫秒延迟。第三处是构建期依赖。npm 生态里相当一部分包在postinstall阶段会跑 shell 脚本,写法是sh -c,在 Windows 上要么被跳过、要么需要装一整套 MSYS/MinGW 才能跑通,而这套工具链本身又会跟系统里的 Python、Visual Studio Build Tools 抢环境变量。

第四处,也是最容易被忽略的:后台常驻。OpenClaw 这类项目理想状态是开机就在那儿挂着,随时接消息。Linux 上有一个systemd --user就能优雅解决的事,Windows 上得去折腾任务计划程序、NSSM 之类的包装器,还要处理“用户没登录时服务起不来”这类诡异场景。所以结论很直接:不要在 Windows 上跟它较劲,把运行环境整个挪进 Linux 子系统,Windows 只负责提供窗口和浏览器。

1.2 WSL2 和 WSL1 的区别,为什么必须是 2

WSL 有两个版本,很多人装完不检查,默认抽到哪个用哪个,然后在 WSL1 上被各种奇怪问题折磨。简单说,WSL1 是一层系统调用翻译层——它把 Linux 的系统调用实时翻译成 Windows 的 NT 调用,本身没有 Linux 内核。听起来很轻量,但代价是:inotify支持残缺、epoll行为不一致、/proc是模拟出来的、Docker 跑不了、内存管理完全交给 Windows。

WSL2 则是一个跑在轻量虚拟机里的真正的 Linux 内核,系统调用是原生的,文件监听、网络栈、进程隔离全都正常。代价是要开虚拟化、有一点点内存开销,以及跨系统访问文件会变慢。

对 OpenClaw 这种需要长时间稳定运行、需要文件监听、需要开子进程的服务端程序来说,WSL2 是唯一选择。检查方法很简单,在 PowerShell 里执行:

wsl.exe -l -v

输出里VERSION那一列必须是2。如果是1,用下面这条转换(发行版名字按你实际的填):

wsl.exe --set-version Ubuntu-24.04 2

转换过程要几分钟,中途别关窗口。

1.3 项目放 /home 还是 /mnt/c:一个影响全程性能的选址

这是新手最容易埋雷的地方。很多人习惯把项目放在C:\Users\xxx\projects,然后在 WSL 里用/mnt/c/Users/xxx/projects访问,觉得这样“两边都能看见,多方便”。实际上这个路径走的是 9p 协议做跨系统文件转发,代价有三:

  • IO 慢一个数量级。npm install装几百个包,在/mnt/c下可能要十几分钟,在/home下两分钟。因为每个小文件的元数据操作都要跨越虚拟化边界。
  • inotify 事件不通。Linux 侧的文件监听器盯不住 Windows 侧的文件变化,热重载直接失效。
  • 权限是全 777。Linux 看到的所有文件都是 777,chmod改不动,ssh 密钥、API Key 配置文件放在这种目录下等于裸奔,而且有些程序会因为“权限过于宽松”直接拒绝加载密钥。

我现在的做法是:项目代码、配置、数据全放~/(也就是 WSL 内部的/home/你的用户名/),需要跟 Windows 交换的文件单独建一个~/share目录,再在 Windows 资源管理器里通过\\wsl$\路径访问。Windows 侧的文件放进 WSL 只是为了“看一眼”,绝不作为运行时工作目录。

2. 打底子:WSL2 + Ubuntu 的安装与三重验证

2.1 虚拟化开关和组件启用顺序

安装 WSL2 的完整流程其实只有一步命令,但前面有个硬件前提:主板 BIOS 里的 CPU 虚拟化必须打开(Intel 平台叫 VT-x,AMD 平台叫 SVM / AMD-V)。这个开关默认可能是关的,判断方法是在任务管理器 → 性能 → CPU 页面看右下角有没有“虚拟化:已启用”。如果显示已禁用,开机进 BIOS 手动打开,不同品牌机器的入口不一样,一般在 Advanced 或 Security 菜单下。

确认虚拟化可用之后,用管理员权限打开 PowerShell,执行:

wsl.exe --install -d Ubuntu-24.04

这条命令会自动启用“虚拟机平台”和“适用于 Linux 的 Windows 子系统”两个可选组件,下载内核更新包,装好发行版并设为默认。执行完需要重启一次。如果你之前手动在“启用或关闭 Windows 功能”里勾过组件,可能会遇到组件已启用但内核包没更新的情况,那就再补一条:

wsl.exe --update

提示:如果你在执行--install时报0x80370102,几乎百分之百是 BIOS 虚拟化没开,或者被 Hyper-V 相关的其他虚拟化软件占用了。先回 BIOS 确认,再看有没有装其他虚拟机监控程序在抢资源。

2.2 首次进入后该做的三件事

首次启动 Ubuntu 会让你设置用户名和密码,这个用户名跟 Windows 账号完全无关,密码在输入时不显示,正常现象。进去之后先做三件事:

sudo apt update && sudo apt upgrade -y sudo apt install -y build-essential curl git unzip ca-certificates

第一件是刷新软件源并升级,第二件是装编译工具链(后面如果有 npm 包需要node-gyp编译,没有这个必失败),第三件里的ca-certificates很容易被忽略,缺了它后面所有 HTTPS 请求都会报证书错误,而报错信息通常长得完全不像证书问题。

第三件事是可选但强烈建议的:换软件源。默认源在国外,apt update可能要等一两分钟。改成本地镜像之后基本秒回。具体地址各大镜像站都有,改完sudo apt update验证一下没报错就行。

2.3 三重验证:确认你确实在 WSL2 里

装完之后不要急着装下一层,先花三十秒验证环境,能省掉后面几小时的困惑。三条命令:

uname -r cat /proc/version free -h

第一条输出的版本号里,WSL2 会带上microsoft-standard-WSL2字样;如果只看到4.4.0-xxx-Microsoft这种老式版本号,那还在 WSL1 上。第二条能确认内核编译信息。第三条看内存,WSL2 会分配一块独立内存,默认是物理内存的一半左右;如果显示的内存跟 Windows 完全一致且swap为 0,也要怀疑是 WSL1。

再加一条从 Windows 侧看的命令,交叉验证:

wsl.exe -l -v

看到VERSION 2就放心往下走。

3. Node 运行时:版本管理器和 PATH 的那点事

3.1 为什么不用 apt 装 nodejs

Ubuntu 软件源里的 Node.js 版本通常落后官方两三年,比如 24.04 自带的是 18.x 或 20.x,而 OpenClaw 这类新项目的硬性要求往往在 22 以上,直接apt install nodejs装完跑起来会报语法错误——SyntaxError: Unexpected token '??'这类,因为新版语法在旧引擎上不认。

正确姿势是用版本管理器。它的价值不只是“能装新版本”,更重要的是版本可切换、可回滚、权限干净。一旦你用sudo npm install -g装过东西,~/.npm和/usr/local/lib/node_modules的属主就会混掉,后面每次不带 sudo 都会 EACCES。用版本管理器把 Node 装在用户目录下,全局包也落在用户目录,彻底没有 sudo 问题。

我用的是 nvm,安装脚本从它的官方仓库获取(版本号按该仓库 README 里的最新版替换),装完之后必须让环境变量生效:

export NVM_DIR="$HOME/.nvm" [ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh"

这两行一般会被安装脚本自动追加到~/.bashrc末尾,但当前这个终端不会自动生效,必须手动source ~/.bashrc或者重开一个终端。这是新手第一个高频卡点:装完 nvm 敲nvm提示 command not found,以为没装成功,其实是 shell 没重新加载。

3.2 装哪个版本,以及 npm 全局目录的归属

nvm install 22 nvm use 22 nvm alias default 22 node -v npm -v

第三条nvm alias default很关键,它把 22 设成新开终端时的默认版本。不做这一步,重启终端会回到系统版本,然后你会看到“昨天还好好的今天怎么又报错了”这种灵异现象。

接着确认 npm 全局包的落点:

npm config get prefix

正常情况下应该输出/home/你的用户名/.nvm/versions/node/v22.x.x这样的路径。如果输出的是/usr或/usr/local,说明你用的是系统 npm 而不是 nvm 带的,which npm和which node交叉确认一下,多半是 shell 缓存或者 PATH 顺序问题。

提示:绝对不要用sudo npm install -g。一旦某个全局包的属主变成 root,后续npm update就会因权限失败,而且报错信息是 EACCES 加一长串路径,很容易被误判成磁盘满或者文件损坏。真踩了,用sudo chown -R $USER:$USER ~/.npm修回来,别直接chmod 777。

3.3 顺手配一下 npm 镜像和缓存

国内网络环境下装包慢是常态,改 npm registry 到国内镜像是常规操作,npm config set registry <镜像地址>,改完npm config get registry确认。另外提一句缓存:npm 的缓存在~/.npm/_cacache,时间长了能吃掉好几个 G,npm cache verify可以清理失效条目。WSL2 的虚拟磁盘默认上限是 1TB,但它是只涨不缩的——删了文件,虚拟磁盘文件照样占着 Windows 的硬盘空间。这个后面第 9 节还会展开说。

4. 装 OpenClaw 本体:两种装法的取舍

4.1 全局安装与源码部署,选哪个

OpenClaw 一般有两种获取方式,差别不在“能不能跑”,而在“你要不要改它”。

方式命令形态优点适用场景
全局安装npm install -g openclaw一条命令,升级简单,路径干净只想用,不打算改代码
源码部署克隆仓库 + 安装依赖 + 构建可以改源码、可以跟主干、方便提 PR想二次开发或调试
容器化自行构建镜像隔离彻底,迁移方便有容器经验的用户

我第一轮用的是全局安装,理由很朴素:先跑通再谈优化。源码部署看着“更专业”,但它多了构建步骤、多了依赖锁文件的问题,一旦构建失败,你会在“是环境问题还是代码问题”之间反复横跳。全局安装跑通了,至少证明了 Node 版本、网络、权限这一整条链路是通的,后面再换源码部署,出错范围就小得多。

npm install -g openclaw openclaw --version

如果你的 npm 是 7 以上版本,-g安装会自动处理 peer 依赖;如果遇到ERESOLVE could not resolve报错,那是依赖树冲突,先用npm install -g openclaw --legacy-peer-deps过渡,但别长期这么干——这只是把冲突藏起来了。

4.2 首次初始化和配置目录的落点

装完先别急着当服务跑,手工执行一次初始化向导:

openclaw onboard

这一步会交互式地问你几件事:配置目录放哪、接哪个模型、要不要现在绑定消息渠道、要不要设开机自启。全部按回车用默认值也行,后面都能改。初始化完成后,配置和数据会落在用户主目录下的一个隐藏目录里(默认是~/.openclaw这类形式,具体名字以首次运行时的提示和--help输出为准)。

进去看一眼结构,大概长这样:

ls -la ~/.openclaw # config/ —— 配置文件 # logs/ —— 运行日志 # data/ —— 会话、记忆、缓存 # credentials/ —— 各种令牌

这里有个必做项:收紧权限。

chmod 700 ~/.openclaw chmod 600 ~/.openclaw/credentials/* 2>/dev/null

原因很简单,这个目录里躺的是 API Key 和渠道令牌,WSL 里虽然只有你一个用户,但如果你后面开了 SSH 端口转发或者装了别的服务,宽松权限就是敞开的门。有些程序会主动检查文件权限,发现是 644 就直接拒绝加载密钥并报 “permissions too open”,看到这个报错别去查网络,先ls -l看权限。

4.3 首次启动:端口、网关和那个 Web 控制台

手工前台启动一次:

openclaw gateway

(子命令名以openclaw --help为准,不同版本可能微调。)启动后终端会打印几行关键信息,你需要关注三个东西:监听地址(一般是127.0.0.1:某端口)、控制台地址(一个 http 链接)、初始化令牌(首次进入控制台要填)。

为什么强调监听地址是127.0.0.1而不是0.0.0.0:前者只允许本机访问,后者会把服务暴露到整个局域网。默认值给 127.0.0.1 是对的,别为了“手机上也能访问”随手改成 0.0.0.0,那等于把你机器的控制台开放给同网段所有人,而这类控制台通常只要一个令牌就能全权操作。

前台跑通之后 Ctrl+C 停掉,接下来做常驻。

5. 模型接入与渠道绑定:密钥该放哪

5.1 API Key 的三种放法,我只推荐一种

密钥的存放位置大致有三种选择:写进配置文件、放进环境变量、交给系统的密钥管理。三种都能工作,风险从高到低。

写进配置文件最省事,但也最容易泄漏——一旦你把这个文件同步到网盘、提交进 git、或者复制给别人排错,密钥就跟着走了。我见过最常见的事故是:为了在群里问一个问题,把整个配置目录打包发出去。环境变量稍好一点,至少不会跟着项目目录走,但它有个副作用:任何在你这个用户下运行的进程都能读到(/proc/<pid>/environ)。系统级密钥管理最安全,但配置起来麻烦,还要处理“服务启动时钥匙串没解锁”的问题。

我的实际做法是配置文件只写占位符,真实值走环境变量,并且把环境变量写在服务单元文件里(下一节会讲)。这样配置文件可以随便备份、随便发给人看,密钥只存在于两个地方:一个权限 600 的文件,和进程内存。

# 追加到 ~/.bashrc 只是方便手工调试,正式运行靠 systemd 的 Environment export OPENCLAW_MODEL_API_KEY="sk-xxxxxxxx"

配置里对应字段填${OPENCLAW_MODEL_API_KEY}这种引用形式,多数框架支持环境变量插值。填完跑一次openclaw doctor(如果有这个子命令)或者看启动日志,确认密钥被正确读到,别等到实际对话时才发现是空的。

5.2 接本地推理服务时的地址陷阱

如果你不想用云端 API,而是接一个跑在本机的推理服务,会碰到一个地址问题:WSL2 里的127.0.0.1指的是 WSL 自己的回环,不是 Windows 的回环。也就是说,如果你的推理服务跑在 Windows 侧,从 WSL 里访问http://127.0.0.1:11434是连不上的。

反过来,如果推理服务跑在 WSL 里,从 Windows 侧访问localhost反而是通的(WSL2 有 localhost 转发)。所以推荐的做法是把推理服务和 OpenClaw 都放在 WSL 里,两者互访走127.0.0.1,最干净。真要跨系统访问,WSL 里可以用$(ip route show default | awk '{print $3}')拿到 Windows 宿主机的地址,或者用host.docker.internal这类特殊域名(需要额外配置)。

还有一点:本地推理服务的上下文窗口通常比云端小很多,接进去之后要先在配置里把maxTokens之类参数调小,否则对话稍长就报超长错误,而错误信息往往只写“请求失败”,看不出是上下文溢出。

5.3 消息渠道绑定的两个注意点

很多人装这套东西的核心诉求是“在手机上给助手发消息”。绑定流程通常是在控制台里生成二维码或者填一个令牌,然后到对应客户端里确认。这个过程有两个坑。

第一个是账号风险。这类绑定本质上是把你的个人通讯账号接到一个自动化程序上,程序的行为(自动回复、批量发送、频繁拉取)可能触发平台的风控。所以绑定的第一个账号一定用小号,跑一周观察稳定了再考虑主力号。第二个是令牌有效期。部分渠道的绑定令牌会定期失效,失效后程序不会主动告诉你,只会在日志里刷“认证失败”。所以绑定完要做的事是:找一个固定时间点(比如每周一看一次日志),确认渠道还活着。

6. 让它常驻:systemd user 服务与开机自启

6.1 WSL 里的 systemd 是个开关,默认该打开

较新版本的 WSL 已经支持 systemd,但要在/etc/wsl.conf里显式启用。编辑这个文件(不要用 Windows 记事本,会写入 CRLF 和 BOM,导致 Linux 解析失败,用nano或vim):

sudo nano /etc/wsl.conf

写入:

[boot] systemd=true

保存退出后在 Windows 侧执行wsl.exe --shutdown,再重新进 WSL。进来看一眼:

systemctl list-units --type=service | head

能列出一堆服务就说明 systemd 起来了。如果报 “System has not been booted with systemd”,说明配置没生效,检查wsl.conf是不是写在了错误的小节里,或者 WSL 版本太老需要wsl --update。

6.2 一个能直接抄的 user unit 模板

不要用 root 跑这个服务,也不要写 system 级 unit,用--user级别的最合适:跟你的家目录权限一致,配置读取不用额外授权。

mkdir -p ~/.config/systemd/user nano ~/.config/systemd/user/openclaw.service

内容:

[Unit] Description=OpenClaw Gateway After=network-online.target [Service] Type=simple WorkingDirectory=%h Environment="OPENCLAW_MODEL_API_KEY=sk-xxxxxxxx" ExecStart=/home/你的用户名/.nvm/versions/node/v22.14.0/bin/openclaw gateway Restart=on-failure RestartSec=5 StandardOutput=journal StandardError=journal LimitNOFILE=65535 [Install] WantedBy=default.target

几个字段值得解释。ExecStart必须写绝对路径,因为 systemd 不读你的.bashrc,PATH 里没有 nvm 的目录,写openclaw gateway会直接status=203/EXEC失败。%h是家目录的占位符,比写死路径好。Restart=on-failure加RestartSec=5是保命的,程序因为网络抖动崩了,五秒后自动拉起来。LimitNOFILE是因为这类长连接服务很容易把文件描述符耗光,默认 1024 不够用,耗尽之后表现是“连不上但不报错”,极难排查。

写完之后:

systemctl --user daemon-reload systemctl --user enable --now openclaw systemctl --user status openclaw

6.3 linger:不登终端也能活着的关键一步

systemctl --user有个机制叫“用户会话”,默认情况下你关掉 WSL 终端,用户会话结束,所有 user 服务跟着被杀。表现出来就是:SSH 断开或者窗口一关,助手就失联了。

解决办法是开启 linger:

loginctl enable-linger $USER

验证:

loginctl show-user $USER | grep Linger

看到Linger=yes就对了。这一步我被坑过整整一个下午——服务是 active 的,status一切正常,但一关终端就断,查日志也没有崩溃记录,因为它是被正常 SIGTERM 掉的,restart 策略都来不及触发。

6.4 日志怎么看才有用

journalctl --user -u openclaw -f # 实时跟 journalctl --user -u openclaw --since "1 hour ago" -p err # 只看错误

-f跟实时日志是最常用的。如果日志量太大刷屏,加--no-pager配合grep过滤关键字。另外程序自己一般也会往~/.openclaw/logs/写一份带时间戳的日志文件,里面比 journal 详细得多,排查具体业务问题时看这个更有效。

7. Windows 侧访问与浏览器自动化

7.1 localhost 转发什么时候有效

WSL2 内置了 localhost 转发:只要服务在 WSL 里监听127.0.0.1或0.0.0.0,你在 Windows 浏览器里访问http://localhost:端口通常就能打开。这个特性在 Win10 21H2 之后和 Win11 上是默认开的。

如果打不开,按顺序排查:先确认服务真的在监听(ss -lntp | grep 端口);再确认服务不是只监听了 IPv6 的::1(有些 Node 服务默认双栈,但绑定参数写错就只剩 v6);然后检查 Windows 侧有没有别的程序占用了同一个端口(netstat -ano | findstr 端口)。最后才考虑netsh interface portproxy做手工转发——这一步一般用不上,一旦用上说明前面的自动转发被什么安全软件拦了。

如果需要从局域网其他设备访问,那必须让服务监听0.0.0.0,同时在 Windows 防火墙里给对应端口加入站规则,再加 portproxy 转发。这个组合我不太推荐用在控制台上,真需要远程访问,更稳妥的做法是走带认证的反向代理,而不是把管理面板直接摊开。

7.2 浏览器自动化缺的那几个系统库

OpenClaw 这类项目如果想让它“自己上网查东西”,通常需要浏览器自动化能力。这一步在 WSL 里最容易翻车,因为精简的 Ubuntu 没装 Chromium 依赖的那一堆共享库,程序启动浏览器时会报error while loading shared libraries: libnss3.so之类。

一条命令解决:

sudo apt install -y libnss3 libatk1.0-0 libatk-bridge2.0-0 libcups2 libdrm2 \ libxkbcommon0 libxcomposite1 libxdamage1 libxfixes3 libxrandr2 libgbm1 \ libpango-1.0-0 libcairo2 libasound2t64

提示:注意最后那个libasound2t64,Ubuntu 24.04 把 32 位兼容包改了名字,网上老教程里的libasound2在这个版本上会报“没有可安装候选”。版本对不上就apt search一下找对应包名。

装完再跑一次浏览器安装脚本(npx playwright install-deps或者项目自带的等价命令)。另外,WSL 里没有真正的显示服务器,所以浏览器必须跑headless模式,配置里那个“显示浏览器窗口”的选项一定关掉,开了会报Missing X server or $DISPLAY。

7.3 文件互通的正确姿势

需要在 Windows 和 WSL 之间传文件,三条路径:

  • Windows 访问 WSL:资源管理器地址栏输\\wsl$\Ubuntu-24.04\home\用户名,可以像普通文件夹一样操作。
  • WSL 访问 Windows:/mnt/c/Users/你的Windows用户名/。
  • 临时交换:在 WSL 里cp到/mnt/c/Users/xxx/Desktop/,最简单粗暴。

如果确实需要在 WSL 里频繁读写 Windows 侧的文件,可以在/etc/wsl.conf里加一段:

[automount] options = "metadata,umask=22,fmask=11"

这能让 Linux 侧的权限修改在 Windows 文件上生效,Windows 应用也能正常看到这些文件,比默认的 777 好很多。但性能问题依然存在,还是那句话:能放/home就放/home。

8. 出问题时的排查链路

8.1 安装阶段:先把错误分类

安装报错不要急着搜索完整报错文本,先分类。看错误开头:

错误特征大概率原因处理方向
EACCES用 sudo 装过全局包修~/.npm属主,别用 sudo
ERESOLVE依赖树冲突检查 Node 版本,谨慎用 legacy-peer-deps
node-gyp相关缺编译工具链装build-essential和python3
ETIMEDOUT/ECONNRESET网络问题换 npm 源,检查代理设置
ENOSPC磁盘满df -h看虚拟磁盘

我踩得最深的一个是ENOSPC:df -h显示还有空间,但npm install就是报磁盘满,原因其实是inotify 的 watch 数量上限,Linux 在监听句柄耗尽时报的错误码也是ENOSPC。解决办法:

cat /proc/sys/fs/inotify/max_user_watches echo "fs.inotify.max_user_watches=524288" | sudo tee -a /etc/sysctl.conf sudo sysctl -p

8.2 启动即退出:三步定位法

服务装了但status显示failed,或者启动三秒就退出,按这个顺序查:

第一步,看journalctl --user -u openclaw -n 100 --no-pager,找最后那几行真正的报错。systemd 的摘要信息很不友好,只有Main process exited, code=exited, status=1/FAILURE,真正原因在上面。

第二步,绕过 systemd 手工前台跑。cd ~ && /绝对路径/openclaw gateway,如果手工能跑起来、systemd 起不来,那就是环境差异——九成是 PATH 或者环境变量,systemd 不读.bashrc。

第三步,which和ls -l的绝对路径验证。ExecStart里写的路径必须真实存在且可执行,nvm 升级 Node 版本之后原来的路径就失效了,这个坑每次升级都会踩一次。

8.3 内存吃满和被 OOM 杀掉

WSL2 默认拿宿主内存的一半,free -h看得到。这个助手类程序吃内存的地方主要是浏览器实例和会话上下文缓存。表现是:跑了几小时突然失联,日志里没有任何异常,只在系统日志里留一句。

dmesg | grep -i "killed process"

看到类似Out of memory: Killed process 1234 (node)就是被内核 OOM killer 干掉了。临时缓解是加 swap,根本解决是在.wslconfig里限内存(见下一节),再配合配置里调小缓存上限。

8.4 时间不同步导致的各种玄学错误

WSL2 在宿主机休眠唤醒后,时钟可能跟真实时间偏差几十秒甚至几分钟。后果是:API 请求全部返回 401(签名过期),TLS 握手失败,日志时间戳错乱。表现非常隐蔽,因为报错信息完全指向别处。

date sudo hwclock -s

第二条把系统时间跟硬件时钟同步。或者干脆wsl.exe --shutdown重启一次,通常自动恢复。这个坑我在一次出差回来之后踩到过,折腾了两小时查 API Key 权限,最后发现是时间差了三分钟。

9. 稳定跑一段时间后的调优与维护

9.1 .wslconfig:给虚拟机划一条边界

WSL2 默认会贪心地占用内存,尤其是你宿主机内存大的时候。配置文件在 Windows 用户目录下:C:\Users\你的用户名\.wslconfig,没有就新建(这是 Windows 侧文件,用记事本编辑没问题,但保存时选 UTF-8 无 BOM):

[wsl2] memory=8GB processors=4 swap=4GB autoMemoryReclaim=gradual

memory给 8GB 是这台 16GB 机器的折中,太少会 OOM,太多会让 Windows 侧吃紧。autoMemoryReclaim=gradual是需要较新版本 WSL 才支持的选项,作用是让 WSL 在空闲时把内存还给 Windows——默认情况下 WSL 占的内存是只进不出的,你会看到任务管理器里Vmmem进程死死咬着几个 G 不放,就是这个原因。

改完必须wsl.exe --shutdown才生效。

9.2 备份:别等坏了才想起来

配置目录里全是你的心血:渠道令牌、会话历史、调好的提示词。备份两条路:

# 整机导出,几十 G,慢但完整 wsl.exe --export Ubuntu-24.04 D:\backup\ubuntu-20260301.tar

更轻的做法是在 WSL 里只打包配置目录:

tar -czf ~/openclaw-backup-$(date +%Y%m%d).tar.gz -C ~ .openclaw

然后把文件复制到/mnt/d/下。这个压缩包通常只有几十兆,可以定期做,甚至可以丢进私有仓库做版本管理(前提是里面的密钥已经走环境变量,不落在配置里)。

9.3 升级与回滚

npm outdated -g --depth=0 npm install -g openclaw@latest systemctl --user restart openclaw

升级前一定做两件事:备份配置目录、记下当前版本号。这类活跃迭代的项目偶尔会有破坏性变更,比如配置文件字段改名,升级之后启动会报“未知字段”。回滚就是npm install -g openclaw@上一个版本号,配置目录从备份恢复。

还有一个容易忽略的:WSL 虚拟磁盘只涨不缩。npm install装装删删几轮之后,ext4.vhdx可能已经涨到 30G 而实际只用了 5G。压缩方法:

wsl.exe --shutdown diskpart # 输入 select vdisk file="C:\Users\你的用户名\AppData\Local\Packages\...\ext4.vhdx" # 输入 compact vdisk

路径比较长,可以在资源管理器里搜ext4.vhdx找到它。这个操作不可逆但安全,几个月做一次就行。


整套流程走下来,真正花时间的从来不是那几条安装命令,而是每一个“为什么必须这样”的判断。我自己在前期最大的失误是试图在错误的层次上解决问题——遇到路径问题就改路径,遇到权限问题就chmod 777,遇到内存问题就加 swap,全是头痛医头。后来把“运行环境必须是 WSL2 里的 Linux、工作目录必须在/home、服务必须由 systemd 托管、密钥必须走环境变量”这四条作为硬约束定下来,剩下的问题排查范围一下子就收窄了。到现在这套东西在我笔记本上已经连续挂了四个月,中间只在两次跟随上游升级时重启过。真正的稳定不是装得多完美,而是每个环节都清楚它在干什么、坏了会以什么形式表现出来——这份“知道它会怎么坏”的预判,比任何一份安装教程都值钱。

返回列表