
如果你是从上一篇顺着过来的应该已经把 Node.js、pnpm、Git 这些基础环境都准备好了。这篇直接聊 OpenClaw 安装的正题从执行 pnpm install 把依赖完整装进项目到 pnpm build 构建出可用的产物再到把服务真正跑起来、在浏览器里看到 OpenClaw 界面。这三段听起来就是三条命令的事但我实际装下来发现真正花时间的不是敲命令而是报错之后的排查。pnpm install 阶段会遇到 lockfile 版本冲突、原生模块编译失败、镜像源下载超时pnpm build 阶段又会撞上内存溢出、类型检查不过、产物目录对不上最后启动时还有端口占用、环境变量缺失这些拦路虎。下面按我自己的真实安装顺序写尽量把报错原文、排查路径、最终解法都交代清楚方便你照着少走弯路。1. 安装前的硬性准备版本、环境、网络这些事1.1 Node.js 与 pnpm 的版本匹配OpenClaw 是个典型的前后端一体项目依赖管理交给了 pnpm。很多安装失败并不是因为你操作错而是版本组合没对上。我这次用的环境是 Node.js 20.11.1 LTS 搭配 pnpm 9.6.0整个安装过程相对平稳。你可以在项目根目录的 package.json 里找到类似engines: { node: 18 22, pnpm: 9 }的声明这就是项目作者限定的运行环境范围。如果你用了 Node.js 22 或更新的版本某些依赖包的预编译二进制可能不匹配安装时会被迫走源码编译一步慢步步慢如果低于 18部分语法和 API 直接不支持可能连依赖解析阶段都会挂。判断当前版本很简单项目根目录执行node -v pnpm -v git --version如果 Node.js 版本不对建议先用 nvm 切换比如nvm use 20而不是直接去改系统的默认版本。pnpm 版本则建议跟着项目走最省事的方式是启用 Node.js 自带的 corepackcorepack enable corepack prepare pnpm9.6.0 --activatecorepack 会读取 package.json 里的packageManager字段自动切换到项目指定的 pnpm 版本。这一步能避免 pnpm 版本不同带来的 lockfile 格式不兼容问题后面我会详细说。1.2 拉取代码后先看懂工作区结构OpenClaw 用 pnpm workspace 管理多个子包这意味着你看到的不是一个扁平的 src 目录而是按功能拆分的多个包。拉代码的常规操作git clone 你的OpenClaw仓库地址 openclaw cd openclaw进来之后别急着跑 install先看一眼根目录的pnpm-workspace.yamlpackages: - apps/* - packages/*这个文件决定了 pnpm 会把哪些目录当作独立的 workspace 包。比如apps/web可能负责前端界面apps/server负责后端服务packages/core放公共逻辑。理解这类结构对后续定位问题很有帮助当你看到报错信息里有openclaw/web或openclaw/core这样的包名就知道问题出在哪个子包里而不是一脸懵。另外要注意后续所有pnpm install、pnpm build都必须在项目根目录执行不要在子目录里单独跑。这个看起来不起眼的细节实际能避免一半的找不到脚本报错。1.3 镜像源与二进制包下载的取舍第一次执行 pnpm install 时最容易卡住的是网络。npm 官方源在国内访问时快时慢大批量下载依赖时超时很常见。我的做法是在项目根目录放一个.npmrc内容如下registryhttps://registry.npmmirror.com auto-install-peerstrue shamefully-hoisttrue先说 registry换成国内常用镜像源能显著提升下载速度但要注意它只是官方 npm 源的只读镜像包的内容不会变不用担心换源导致依赖不一致。如果你的网络访问官方源很快也可以不设置这一步。再说auto-install-peerspnpm 对 peer 依赖的处理比 npm 严格开启后会自动安装 peer 依赖能减少一批UNMET PEER DEPENDENCY警告。最后是shamefully-hoisttrue的作用我放到后文依赖隔离的部分展开这里先不展开。还有一个容易忽略的问题像 sharp、esbuild 这类依赖安装时不止从 npm 拉包还会额外下载针对当前平台的二进制文件。大多数国内镜像对这类二进制下载地址也有缓存但如果你所在网络对某些下载域名有限制install 会卡在上传/下载 binary 的日志上。此时可以在.npmrc里针对具体包配置镜像下载地址网上都有对应的参数写法按需加就行。我的建议是先用基础 registry 装一次卡住了再对症下药不要一开始就堆一堆配置否则出了问题不容易定位。2. pnpm install 阶段最容易翻车的几个点2.1 lockfile 版本不匹配引发的失败我首次执行pnpm install时依赖解析阶段就报了这样一段错误ERR_PNPM_OUTDATED_LOCKFILE The lockfile is not up to date with the package.json files. Run pnpm install --no-frozen-lockfile to update it.原因很简单仓库里的pnpm-lock.yaml是维护者用特定 pnpm 版本生成的我用的是本地另一个 pnpm 版本两者对依赖解析结果的记录规则不同pnpm 会认为 lockfile 已过期。官方建议的pnpm install --no-frozen-lockfile确实能绕过它会忽略冻结条件重新计算并覆盖 lockfile。但问题来了如果你并不是项目维护者或者当前对依赖版本没有把握建议别轻易覆盖 lockfile因为你可能意外升级了某些间接依赖导致本地构建结果和项目预期不一致。更稳妥的方式是把 pnpm 版本切换到项目声明版本。刚才说的 corepack 就是干这个用的。如果你发现 corepack 启用后还是报同样的错再选择pnpm install --no-frozen-lockfile覆盖后立刻检查 git diff 里的 lockfile 变化范围。如果变化只集中在几个包问题不大如果大范围变动说明版本差得太多优先回头修 pnpm 版本。还要注意这种 lockfile 报错在不同 pnpm 大版本之间特别常见。pnpm 8 的 lockfile 版本是 6.0pnpm 9 是 9.0中间差异很大想靠--no-frozen-lockfile硬跨过去后续构建阶段会看到更多奇怪问题。2.2 原生模块编译失败node-gyp 与系统编译工具链比起网络问题更麻烦的是 install 过程中触发了源码编译。pnpm 在安装某些带原生代码的依赖时如果找不到匹配当前平台、当前 Node.js 版本的预编译二进制会自动尝试用 node-gyp 从源码编译。这时候你机器上如果没有完整的编译工具链就会看到一大段以gyp ERR!开头的报错。我在一台相对干净的 Ubuntu 机器上就遇到过gyp ERR! find Python gyp ERR! configure error gyp ERR! stack Error: Cant find Python executable python这个报错的本质是 node-gyp 需要 Python 3 和 C/C 编译器而机器上都没装。解决办法也直接Ubuntu/Debiansudo apt install python3 make gWindows安装 Visual Studio Build Tools勾选使用 C 的桌面开发工作负载并安装 PythonmacOS执行xcode-select --install装完工具链后重新执行pnpm install。如果 install 已经执行到一半失败不需要删整个 node_modules可以直接再跑一次pnpm 会从断点续盘。但如果你发现上次中断时锁文件已经写入建议先pnpm install --force重新解析一次。另外要提醒一下如果你的项目里用了 sharp、parcel watcher 这类包镜像源和二进制下载地址的问题比编译工具链更常见。最好的排查方法是看报错前最后的几行日志如果出现prebuild-install或node-pre-gyp相关的字样说明它在尝试下载预编译二进制而不是走 node-gyp此时优先检查网络和镜像配置而不是急着装编译工具链。2.3 pnpm 的依赖隔离机制与找不到模块问题pnpm 的 node_modules 结构跟 npm 最大的区别在于默认情况下pnpm 会把所有依赖放在node_modules/.pnpm这个虚拟目录里并在每个包自己的 node_modules 下创建符号链接只暴露 package.json 里显式声明的依赖。这样做的好处是磁盘空间更省、依赖关系更严格坏处也明显某些写得不太规范的项目代码会直接引用一个没有在 package.json 里声明的包。这种代码在 npm 扁平化的 node_modules 下能跑换到 pnpm 下就报Cannot find module some-package Require stack: - /path/to/openclaw/apps/web/index.js遇到这种情况先判断是 OpenClaw 自身的问题还是历史遗留问题。OpenClaw 这类比较新的项目一般已经把依赖声明齐了很少出现。但如果你安装的是某个老项目或者自己 fork 改过依赖遇到这种报错很正常。临时的解法是在.npmrc里加shamefully-hoisttrue我前面已经提到的就是这个参数。它会把 pnpm 的依赖尽量扁平化到根 node_modules行为接近 npm能快速让项目跑起来。长期的解法是定位到报错的那个包把它缺失的依赖显式加进对应的 package.json 里然后重新 install。这里我的建议是先加参数把环境跑通跑通之后再考虑要不要规范化不要在一开始就陷入依赖治理的泥潭。2.4 install 成功后的三个验证动作pnpm install结束时输出Done并不代表万事大吉我习惯在 build 之前先做三个快速验证。第一个验证是看依赖树顶层包是否完整pnpm ls --depth 0如果某些包旁边有invalid或missing标记说明 install 过程有残留问题最好重新安装。第二个验证是确认关键原生包能正常加载。比如项目里依赖 sharp可以单独测一下node -e require(sharp)能正常输出版本信息说明原生模块加载没问题如果报The specified module could not be found多半是二进制下载不完整需要重新安装对应包。第三个验证是检查node_modules/.bin下有没有需要的命令。很多构建脚本依赖turbo、tsc、vite这些命令行工具如果 install 中途断了这些软链可能缺失。看到脚本报command not found时不要急着全局安装先在项目根目录重新执行pnpm install修复本地的 bin 链接。3. pnpm build 的构建链路与踩坑实录3.1 先拆脚本build 阶段的真实执行顺序很多人一上来就pnpm build报错了也不知道哪一步出错。我建议先看根目录 package.json 里的 scripts{ scripts: { build: turbo run build, build:web: pnpm --filter openclaw/web build } }如果脚本是turbo run build那么它会递归执行所有 workspace 包里名为 build 的脚本并且计算任务依赖关系。第一次构建时因为没有任何缓存每个包都要完整跑一遍耗时会比较长属于正常现象。OpenClaw 这种 monorepobuild 过程基本遵循一条链路先对所有相关包做 TypeScript 类型检查然后打包前端资源最后编译后端服务。单独构建某个包子包的命令长这样pnpm --filter openclaw/web build但我不建议你一开始就这么干。因为子包之间可能存在构建顺序依赖比如apps/web依赖packages/core的产物单独构建 web 前必须保证 core 已经构建好。直接用根目录的pnpm build让 turbo 帮你排好顺序比手动按顺序构建要可靠得多。3.2 内存溢出调整 Node 堆内存与并发数build 过程中最常见的硬核报错是这行FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory看到它不用慌这不是项目坏了而是 Node.js 默认堆内存不够用。TypeScript 编译器在大项目上非常吃内存再加上打包器2GB 的默认堆很快就被占满。我当时的处理方式是给 Node.js 进程加大堆内存上限NODE_OPTIONS--max-old-space-size4096 pnpm buildWindows 用户要注意写法PowerShell 下这样写$env:NODE_OPTIONS--max-old-space-size4096 pnpm build如果加了 4GB 还爆可以再往上加但要注意机器物理内存大小别把整台机器拖死。另外turbo 支持限制并发数减少同时构建的包数量也能降低内存峰值pnpm build --concurrency2这个参数不是所有脚本都直接支持如果你的 build 脚本用turbo run build可以改成turbo run build --concurrency2来跑。我试过把并发从默认值降到 2内存峰值能明显下降构建速度慢一点但稳很多。3.3 构建期类型错误与产物目录对不上TypeScript 编译失败的报错各式各样但大体能分成两类。第一类是真类型错误比如代码里某个函数参数类型不匹配或者某个模块的声明文件找不到。这类问题需要回到源码修改才能解决。但如果你刚拉下代码、什么还没动就出现一堆类型错误先检查是不是依赖没装完整。特别是某个包的.d.ts文件缺失经常会导致TS2307: Cannot find module这类错误。此时退回上一步重新执行 pnpm install通常能解决。第二类是产物目录和 package.json 声明对不上。构建成功不等于启动成功我一个朋友遇到过 build 后日志显示成功但启动时报找不到服务入口ENOENT: no such file or directory, open /path/to/openclaw/apps/server/dist/index.js排查后发现这个子包的 package.json 里main字段指向dist/index.js但实际构建产物生成的是dist/index.mjs。这种不一致在 pnpm 的 monorepo 里尤其隐蔽因为根目录的启动脚本会把所有子包串起来某个包出了问题整体就起不来。解决办法有两种一是重新确认根目录pnpm build是否把所有子包都构建了一遍二是看具体报错的包名单独构建该子包检查它产出的文件到底叫什么名字。3.4 构建成功后的产物检查清单构建命令跑完看到Done之后我还会按下面这个表逐项检查确认这一关是真的过了检查项期望结果异常处理退出码0非 0 说明有失败步骤翻日志定位各子包 dist 目录存在且非空重新构建对应子包构建日志末尾列出所有参与构建的包名缺包说明依赖顺序没跑全关键二进制文件服务入口文件存在检查 main 字段与产物文件名是否一致检查时我习惯用一条命令看所有子包的产物大小find . -name dist -type d -maxdepth 4 -exec du -sh {} \;这条命令在 Linux 和 macOS 上都能直接用。如果某个 dist 目录只有几 KB说明该子包构建有问题大概率是只跑了类型检查没真正打包。4. 启动运行到进入 OpenClaw 界面的关键环节4.1 启动命令的选择start 还是 dev构建完成后启动 OpenClaw 有两种常见方式pnpm start和pnpm dev。两者的区别很简单dev模式走的是热更新开发服务器代码改动后页面自动刷新方便调试但占用的资源更多启动日志也更啰嗦start模式加载的是刚才 build 出来的产物启动更快行为也更接近生产环境。我第一次跑通界面时选的是start。原因有两个一是前面的 build 已经成功start能直接验证构建产物是否可用避免 dev 模式下代码能跑但产物有问题的假象二是start启动后日志更干净方便判断服务状态。如果你只想快速看界面不关心构建链路直接pnpm dev也可以。但要注意dev 模式首次冷启动会比 start 慢不少因为开发服务器要预编译很多东西。4.2 第一次启动时如何判断服务是否正常启动命令执行后不要急着打开浏览器先看终端日志。一次正常的启动日志里通常会出现类似这样的关键信息[web] Local: http://localhost:3000 [api] API server running on http://localhost:3001这里要提醒一个新手容易踩的误区看到第一行Local就以为万事大吉其实前端服务和后端服务是独立的很多页面需要同时依赖两者。正确做法是等所有子服务的监听日志都打出来并且最后几行没有Error、FATAL字样再访问页面。如果等了很久日志停在某个位置不动按Ctrl C停掉进程检查是不是有子服务启动失败。第一次跑通时强烈建议用前台模式运行不要用nohup或后台守护方式否则日志看不到出了问题只能盲猜。等确认界面能正常打开再考虑用什么方式长期运行。4.3 端口占用与浏览器打不开页面的排查启动阶段最经典的问题是端口被占用。报错长这样Error: listen EADDRINUSE: address already in use :::3000说明 3000 端口已经被别的进程占了。我在测试机器上经常碰到某个开发服务器没退出彻底占着端口不放。处理办法Linux / macOSlsof -i :3000找到 PID 后kill -9 PIDWindowsnetstat -ano | findstr :3000拿到 PID 后taskkill /PID PID /F如果你不想杀掉现有进程也可以让 OpenClaw 换端口。具体环境变量名要看项目文档比较常见的是PORT3002或者OPENCLAW_PORT3002启动前带上就行。改了端口之后页面访问地址也要跟着改。浏览器这边常见的拦路虎有三种。第一种是访问http://localhost:3000直接ERR_CONNECTION_REFUSED这是前端服务根本没起来第二种是页面能打开但发请求时报ERR_CONNECTION_REFUSED这是后端服务挂了第三种是页面白屏控制台有 401 或 400说明鉴权或接口基地址配置有问题这时候要往后端服务的日志里找线索而不是继续刷页面。5. 成功进入界面后的三个收尾动作5.1 设置管理员账号与修改默认密码浏览器第一次打开 OpenClaw 界面通常会跳到一个初始化页面要求设置管理员账号和密码。这一步别嫌麻烦直接搭一个自己记得住的强密码。有些版本为了第一次体验方便内置了默认账号如果你没有设置而直接登录进去之后第一件事应该是把默认密码改掉。我在一次实际使用中忽略了这一点以为本地服务无所谓结果过两天发现界面状态变得不正常排查了半天才想起是配置文件被人动过。从此我的习惯是任何自托管服务第一次进入后先把初始化向导走完再谈配置功能。5.2 保存环境变量配置并确认日志落盘进入界面只是第一步真正要长期使用环境变量不能只靠命令行临时传。OpenClaw 这类项目通常提供.env.example作为配置模板需要你复制一份并改名为.env.local或.env再按需填写cp .env.example .env.local初次只是为了看界面里面大部分配置留空都能启动但有两个建议现在做一是确认是否要接外部模型服务如果要接把对应的 API Key 填进去否则界面里相关功能会一直显示未连接二是确认日志输出方式。默认情况下日志打到终端想留底可以重定向到文件pnpm start openclaw.log 21这样即使终端关了也能通过日志文件排查问题。5.3 最小验证链路整个过程应该是什么样最后把我这台机器上完整跑通的链路整理成速查表方便你对照阶段命令成功标志版本准备node -v pnpm -vNode 20、pnpm 9依赖安装pnpm install输出 Done无报错构建产物pnpm build退出码 0服务启动pnpm start日志出现访问地址界面验证浏览器访问 localhost出现 OpenClaw 初始化页这套流程我反复跑了三遍才固定下来。第一遍倒在原生编译第二遍倒在内存溢出第三遍才顺利走到浏览器界面。回头看绝大多数问题都是环境层面的而不是 OpenClaw 本身的代码问题。如果你也准备装记住一个原则每跑一步就确认这一步的退出状态不要一口气连敲三条命令否则报错混在一起定位起来非常痛苦。装完界面只是开始接下来配置外部服务、调通数据存储、做局域网访问都是能把人逼疯的环节。后面我打算写一篇专门讲 OpenClaw 跑通之后怎么配置常用功能如果你也在摸索可以先把这篇的安装链路跑熟到时候直接照着配置篇来。