如果你和我一样,在公司电脑上装 OpenClaw 之前已经在自己笔记本上成功跑通过一次,那你大概率会觉得这次安装只是走个流程。结果刚到依赖安装环节就被 libsignal-node 卡住:npm 进度条停在同一个位置几分钟不动,最后直接报 ETIMEDOUT,把日志翻到 verbose 才看清楚,它一直在尝试从 GitHub 的 release 地址下载预编译文件,而公司的网络策略并没有放行这条下载链路。
这个现象非常典型,尤其是在企业统一管控的办公网络里。问题几乎不在 OpenClaw 本身,而是它依赖的原生模块默认从 GitHub Releases 拉二进制文件,公司出口安全策略往往只放行了部分域名,后半段下载链路不在白名单内。这篇文章把我从现象定位、日志分析到最终改用 git 源码编译的完整过程整理出来,重点解决 libsignal-node 的 GitHub 下载失败问题。如果你也卡在这一步,下面的内容可以直接照着操作。
1. 定位问题第一步:弄清 libsignal-node 安装时到底在哪里下载了什么
很多人一看到 npm install 卡住,第一反应是网络没连上或者 OpenClaw 安装包有问题,于是反复重试、重启电脑,甚至把 Node.js 卸载重装。这些操作基本没用,因为问题不在你的机器,也不在 npm 主源,而在依赖包安装脚本要去访问的那个外部地址。
libsignal-node 是 Signal 官方 libsignal 库的 Node 原生绑定,OpenClaw 的依赖树里带了这个模块,主要承担消息加密相关的底层能力。这类原生模块的发布方式和普通 npm 包不太一样:普通的 JavaScript 包直接把源码推到 npm registry,安装时下载下来就能用;而 libsignal-node 这种带编译产物的原生模块,为了照顾大多数人的安装体验,官方会预先编译好几个平台的二进制文件,把这些文件挂到 GitHub Releases 上,同时把一层很薄的 JS 包装代码发布到 npm。
也就是说,npm install 的时候分两步走:
- npm 首先从 registry 下载 libsignal-node 的 JS 包装包,这一步走的是 npm 官方源或者你配置的内部源,通常没问题。
- 包装包安装完成后,它的 postinstall 脚本会调用 prebuild-install,去 GitHub Releases 下载与你当前操作系统和 Node ABI 匹配的预编译文件,下载完成后放到指定目录,模块才能被 require 正常加载。
问题恰恰出在第二步。公司办公电脑的网络出口一般有统一管控,github.com 这个域名可能已经被放行,所以你在浏览器里打开 GitHub 页面没问题,甚至 git clone 也能用。但那些 release 资产并不真的存放在 github.com 上,而是会被重定向到 GitHub 使用的对象存储域名,比如 objects.githubusercontent.com 或 release-assets.githubusercontent.com。如果公司出口清单里只放行了 github.com,没有放行这些对象存储域名,终端里所有下载 release 资产的请求都会卡死或超时。
我当时遇到的完整报错大致是这样:
text复制gyp verb safe-publish > prebuild-install || node-gyp rebuild
prebuild-install warn install Failed to download prebuilt binary
prebuild-install info 前往 https://github.com/signalapp/libsignal/releases 手动下载
日志里会把确切要下载的 URL 打出来。看到那一长串以 https://github.com/signalapp/libsignal/releases/download/ 开头的地址时,基本就能断定:OpenClaw 本身没问题,是安装阶段要访问的 GitHub release 下载域名被网络策略拦住了。
这个阶段的判断很重要。只有先搞清楚到底是哪段链路不通,后面给 IT 提审批、或者自己走源码编译时才知道申请哪些域名、绕开哪些环节。否则盲改一通,大概率浪费一下午。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 用最小网络实验锁定被拦的是哪个域名,而不是拍脑袋重试
卡在下载阶段后,我建议大家先做一轮最小化网络实验。目的很简单:区分是 npm 主源不通、GitHub 主页不通、还是 GitHub 的 release 下载域名不通。这一步不需要什么专业工具,一个 curl 加一个日志文件就够了。
先到 OpenClaw 的项目目录里,把安装日志完整地导出来:
bash复制npm install --loglevel verbose > install.log 2>&1
跑完或者超时后,在 install.log 里搜索 http fetch 和 download 相关的行,特别留意卡住的那个地址。如果它指向 github.com/signalapp/libsignal/releases/download/,就说明 npm registry 下载阶段已经结束,现在卡在 prebuild 下载阶段。
接下来用 curl 分别测几个关键域名:
bash复制curl -I https://registry.npmjs.org
curl -I https://github.com
curl -I https://codeload.github.com
curl -I https://objects.githubusercontent.com
curl -I https://release-assets.githubusercontent.com
每一条命令都会返回一个 HTTP 状态码,或者直接卡住超时。分情况判断:
| 测试目标 | 结果 | 判断 |
|---|---|---|
| registry.npmjs.org | 200 OK | npm 主源正常,问题不在依赖下载 |
| github.com | 200 OK | GitHub 主站可用,git clone 页面访问不受影响 |
| objects.githubusercontent.com | 超时或连接失败 | release 资产下载链路被拦截,这就是 libsignal-node 下载失败的根因 |
| release-assets.githubusercontent.com | 超时或连接失败 | 同上,属于新版 GitHub release 资产使用的域名 |
如果你所在的内网 DNS 做了严格管控,域名解析阶段就可能出问题。可以先做一次解析测试:
powershell复制Resolve-DnsName github.com
Resolve-DnsName objects.githubusercontent.com
Resolve-DnsName release-assets.githubusercontent.com
如果对象存储域名解析出来的结果为空或者返回内网保留地址,说明内网 DNS 层面就没有放行。如果解析正常但 curl 超时,说明是连接层被出口网关拦了。
还有一种比较隐蔽的情况:github.com 能解析、能访问,但 git clone 一个仓库时中途失败。这种多半发生在仓库体积比较大、包含子模块的时候,因为 git 在 clone 过程中要去 objects.githubusercontent.com 拉取对象数据。这个域名和 release 下载用的可能是同一组对象存储,所以只要它不通,git clone 大仓库同样会卡住。
这一步做完后,你已经不是“装不上 OpenClaw”的状态,而是非常明确地知道:需要解决的是 GitHub 对象存储域名的访问问题,或者是想办法让安装过程不再依赖这个域名的二进制下载。
3. 公司内网的正路:让网络团队放行下载链路,或者把依赖收进内部制品库
公司电脑的环境和家里不一样,我不建议为了装一个开发工具去修改系统的网络链路或者做任何绕行操作。一方面这可能违反公司安全策略,另一方面很多办公电脑装了终端安全软件,绕过操作很快会被扫掉,而且会给后续维护留下隐患。
比较正规的做法是走以下两条路,它们不冲突,还可以并行推进。
第一条路是给网络团队提交一个访问申请,把编译和安装 OpenClaw 真正需要访问的域名列清楚。我在实际操作中申请的是这么几个:
text复制github.com
codeload.github.com
api.github.com
objects.githubusercontent.com
release-assets.githubusercontent.com
index.crates.io
static.crates.io
解释一下每个域名的用途:
- github.com:网页访问、git clone 主仓库。
- codeload.github.com:下载 GitHub 仓库的 tar.gz / zip 快照。
- api.github.com:查询 release 元数据,prebuild-install 拉取具体版本要先访问它获取下载地址。
- objects.githubusercontent.com 和 release-assets.githubusercontent.com:实际存放 release 资产和 git 对象的域名,libsignal-node 下载预编译文件最终访问的就是这里。
- index.crates.io 和 static.crates.io:走源码编译路线时,Rust 工具链要下载 crate 依赖,这两个域名属于 crates.io 的索引和文件存储。
如果你们公司内部有 Nexus 或 Artifactory 之类的制品库,第二条路更省心:让内部制品库作为统一的缓存层,把 npm 和 cargo 的公开仓库源都收到内网,开发机统一指向内部地址。这样做的好处是安全策略只需要给制品库服务器放行外部访问,研发人员自己的机器不需要开任何额外域名。
配好内部 npm 仓库后,你把 registry 指过去就行:
bash复制npm config set registry https://nexus.example.corp/repository/npm-group/
配好内部 cargo 仓库后,在用户目录下的 ~/.cargo/config.toml 里写入:
toml复制[source.crates-io]
replace-with = "company-nexus"
[source.company-nexus]
registry = "sparse+https://nexus.example.corp/repository/cargo-group/"
注意,制品库方案能解决 npm 包装包和大部分 crate 依赖的下载问题,但不一定能覆盖 GitHub release 资产这类动态下载。因为 libsignal-node 的 postinstall 脚本是直接拼一个固定的 GitHub release URL 去下载,内部制品库能不能缓存住这个地址,取决于你用的是 raw 类型的远程仓库还是单纯依赖 npm group。实际测试下来效果并不稳定,所以如果时间比较紧,不要只押在制品库一条路上,源码编译是更可控的兜底方案。
我当时的实际选择是:提交了访问域名申请,但没有干等审批,转手就开始走源码编译。因为源码编译只依赖 npm 包源码、Rust 工具链和 crate 依赖,不需要碰 GitHub release 的对象存储域名,等于把“下载别人编译好的二进制”换成“在自己机器上编译”,主动权完全拿回来了。
4. 源码编译:彻底不依赖 GitHub release 下载的可复现路径
源码编译听起来像老派做法,但在企业网络受限的场景下反而是最稳妥的。它的核心原理是:绝大多数原生模块在安装脚本里都预留了“不下载预编译文件、直接编译源码”的回退逻辑。你只要让 npm 知道这次要从源码构建,postinstall 脚本就会跳过 prebuild-install 下载,转而执行 node-gyp rebuild,或者调用包自带的构建脚本去编译。
4.1 Windows 办公电脑上的工具链准备
我在这台 Windows 11 办公机上编译 libsignal-node,用到的工具链是这四个:
- Git for Windows
- Python 3.12
- Visual Studio 2022 Build Tools,需要安装“使用 C++ 的桌面开发”工作负载
- Rust,通过 rustup 安装,toolchain 选择 stable-x86_64-pc-windows-msvc
如果你不想手动点安装包,用 winget 也可以:
bash复制winget install --id Git.Git
winget install --id Python.Python.3.12
winget install --id Microsoft.VisualStudio.2022.BuildTools --override "--quiet --add Microsoft.VisualStudio.Workload.VCTools --includeRecommended"
winget install --id Rustlang.Rustup
安装完成后做一次版本确认,确保所有命令都在 PATH 里:
bash复制node -v
npm -v
python --version
rustc -V
cargo -V
这里有两个容易踩的细节。第一,Rust 的 toolchain 一定要用 MSVC 版本,不要用 GNU 版本。如果你电脑上之前装过其他 Rust 环境,可以先强制切换:
bash复制rustup toolchain install stable-x86_64-pc-windows-msvc
rustup default stable-x86_64-pc-windows-msvc
第二,MSVC
