macOS 上 npm 安装报 SSL 证书错误?一次完整的排查与修复记录
“
核心问题:在 macOS 上运行
npm install时,出现UNABLE_TO_GET_ISSUER_CERT_LOCALLY或curl: (77) error setting certificate verify locations报错,该如何彻底解决?
答案是:根本原因是系统缺少 /etc/ssl/cert.pem 证书文件,需要重新生成它;同时 Node.js 有独立的证书验证机制,需要通过 NODE_EXTRA_CA_CERTS 环境变量单独修复。本文将完整还原整个排查过程,带你从最初的报错一路走到最终运行成功。
背景:一个看似简单的 npm 安装,为什么会卡这么久?
很多开发者在全新 Mac 上,或者系统大版本升级后,会突然发现 npm install 开始报奇怪的 SSL 错误。明明网络是通的,代理也开着,但就是装不上包。
这次排查起点是安装一个名为 openclaw 的工具:
npm i -g openclaw@2026.3.2
表面上看只是一个普通的全局包安装,结果引出了一连串问题:镜像源失效、SSL 证书缺失、Git SSH 权限、Node.js 证书隔离……每解决一个,下一个就浮出水面。
这正是 macOS 开发环境的典型特征——问题往往不是单点的,而是一层套一层。
第一关:npm 镜像源没有生效
这一段要回答的问题:为什么明明设置了国内镜像源,npm 还是去访问 registry.npmjs.org?
明明已经执行了:
npm config set registry https://registry.npmmirror.com
但安装时的报错日志显示,npm 依然在请求 https://registry.npmjs.org。
npm error request to https://registry.npmjs.org/openclaw failed
验证方法很简单:
npm config get registry
如果输出的是 https://registry.npmjs.org/,说明设置没有生效或被覆盖了。
修复步骤:
# 重新设置镜像源
npm config set registry https://registry.npmmirror.com
# 验证
npm config get registry
# 正确输出应为:https://registry.npmmirror.com
如果反复设置都不生效,可以直接编辑 npm 配置文件:
open ~/.npmrc
在文件中手动加入:
registry=https://registry.npmmirror.com
保存后重新验证。
反思: 这一步其实耽误了很多时间,因为初次设置后看起来”成功了”,但下次打开终端环境变量就被重置了。设置完一定要当场用 npm config get registry 确认,而不是默认”应该生效了”。
第二关:SSL 证书文件缺失——真正的根源
这一段要回答的问题:curl: (77) error setting certificate verify locations: CAfile: /etc/ssl/cert.pem 是什么意思,怎么修复?
这个错误的含义非常直接:curl 在尝试建立 HTTPS 连接时,找不到系统 CA 证书文件 /etc/ssl/cert.pem。没有这个文件,TLS 握手无法完成,所有 HTTPS 请求都会失败。
验证文件是否存在:
ls -la /etc/ssl/cert.pem
如果看到:
ls: /etc/ssl/cert.pem: No such file or directory
就是这个问题。
这种情况常见于:
- ▸
macOS 大版本升级后(如从 Ventura 升 Sonoma、Sequoia) - ▸
重装系统后未完整恢复开发环境 - ▸
某些系统优化工具误删了系统文件
修复方法:从 macOS 系统 Keychain 重新导出证书
# 创建目录(如果不存在)
sudo mkdir -p /etc/ssl
# 从系统 Keychain 导出根证书
sudo security find-certificate -a -p \
/System/Library/Keychains/SystemRootCertificates.keychain \
| sudo tee /etc/ssl/cert.pem
验证是否成功:
ls -la /etc/ssl/cert.pem
# 应该看到类似:-rw-r--r-- 1 root wheel 235703 ...
然后测试 curl 是否能正常访问 HTTPS:
curl https://dashscope.aliyuncs.com/compatible-mode/v1/models \
-H "Authorization: Bearer YOUR_API_KEY"
如果能返回正常的 JSON 数据,说明证书问题已修复。
场景说明: 这个修复步骤不仅对 curl 有效,对任何依赖系统 CA 证书的命令行工具都有效,包括 git、wget 等。
第三关:npm 自身的 SSL 验证
这一段要回答的问题:curl 已经能访问 HTTPS 了,为什么 npm 还是报 UNABLE_TO_GET_ISSUER_CERT_LOCALLY?
npm 使用 Node.js 的 TLS 实现,它有自己独立的证书验证逻辑,不完全依赖系统的 /etc/ssl/cert.pem。因此即使 curl 修好了,npm 仍可能失败。
临时方案:关闭 npm 的 SSL 验证
npm config set strict-ssl false
npm i -g openclaw@2026.3.2
# 安装完成后务必恢复
npm config set strict-ssl true
这个方案能让安装继续进行,但不推荐作为永久配置,因为它会跳过所有证书验证,存在中间人攻击风险。
推荐方案:让 npm 使用正确的证书文件
npm config set cafile /etc/ssl/cert.pem
这样 npm 会使用我们刚才修复好的系统证书,既安全又彻底。
第四关:Git 的 SSH 依赖问题
这一段要回答的问题:安装 npm 包时为什么会触发 Git SSH 错误?
关闭 SSL 验证后,安装继续执行,但很快又遇到了新报错:
npm error code 128
npm error command git --no-replace-objects ls-remote ssh://git@github.com/whiskeysockets/libsignal-node.git
npm error git@github.com: Permission denied (publickey).
这说明 openclaw 的某个依赖包(这里是 libsignal-node)在 package.json 中用 SSH 协议指向了 GitHub 仓库,而本机没有配置 GitHub 的 SSH 密钥,导致拉取失败。
修复方法:强制 Git 使用 HTTPS 替代 SSH
git config --global url."https://github.com/".insteadOf ssh://git@github.com/
这条命令告诉 Git:凡是遇到 ssh://git@github.com/ 开头的地址,自动替换为 https://github.com/,从而绕过 SSH 密钥需求。
但随之而来的是 Git 自身的证书问题:
fatal: unable to access 'https://github.com/...': error setting certificate verify locations:
CAfile: /etc/ssl/cert.pem CApath: none
Git 同样有自己的 SSL 验证,也需要单独处理:
# 临时关闭 Git 的 SSL 验证(用于完成安装)
git config --global http.sslVerify false
# 安装完成后恢复
git config --global http.sslVerify true
或者更优雅的方式,让 Git 使用修复后的证书:
git config --global http.sslCAInfo /etc/ssl/cert.pem
反思: 一个 npm 包的依赖里混用了 SSH 协议,这在开源项目中并不罕见,但对于网络环境复杂的国内开发者来说,往往是个隐形炸弹。遇到这类报错不要慌,按图索骥找到是哪个依赖在用 SSH,用 HTTPS 替代即可。
第五关:Node.js 的独立证书隔离
这一段要回答的问题:包装好了,但运行时 Node.js 程序还是报 LLM 超时,和证书还有关系吗?
openclaw 安装成功后,运行时持续报错:
LLM request timed out.
经过排查,程序使用的是阿里云百炼(DashScope)的 API,接口地址是:
https://dashscope.aliyuncs.com/compatible-mode/v1
用 -k 参数跳过证书验证的 curl 是通的,API Key 也有效(能正确返回模型列表)。问题出在 Node.js 进程本身的证书信任链。
Node.js 在运行时默认使用自己内置的 CA 证书列表,不自动继承系统证书。当系统证书被重置或缺失时,Node.js 程序在发起 HTTPS 请求时可能找不到信任的根证书,导致连接超时或失败。
修复方法:通过环境变量告诉 Node.js 使用哪个证书文件
export NODE_EXTRA_CA_CERTS=/etc/ssl/cert.pem
要永久生效,加入 ~/.zshrc:
echo 'export NODE_EXTRA_CA_CERTS=/etc/ssl/cert.pem' >> ~/.zshrc
source ~/.zshrc
之后重新启动 openclaw,请求不再超时。
NODE_EXTRA_CA_CERTS 的工作原理: 这个环境变量让 Node.js 在原有内置 CA 列表的基础上,追加指定文件中的证书,而不是替换。因此既保留了 Node.js 默认的信任根,又加入了系统自定义证书,是最安全也最兼容的做法。
完整修复清单(按顺序执行)
下面是整个排查过程提炼出的最终修复步骤,适用于在 macOS 上遇到类似 SSL/证书问题的开发者:
第一步:修复系统 CA 证书文件
sudo mkdir -p /etc/ssl
sudo security find-certificate -a -p \
/System/Library/Keychains/SystemRootCertificates.keychain \
| sudo tee /etc/ssl/cert.pem
# 验证
ls -la /etc/ssl/cert.pem
第二步:配置 npm 使用系统证书
npm config set cafile /etc/ssl/cert.pem
npm config set registry https://registry.npmmirror.com
第三步:配置 Git 使用 HTTPS 并指定证书
git config --global url."https://github.com/".insteadOf ssh://git@github.com/
git config --global http.sslCAInfo /etc/ssl/cert.pem
第四步:配置 Node.js 使用系统证书(永久生效)
echo 'export NODE_EXTRA_CA_CERTS=/etc/ssl/cert.pem' >> ~/.zshrc
source ~/.zshrc
第五步:测试
# 测试 curl
curl https://www.baidu.com
# 测试 npm
npm i -g openclaw@2026.3.2
# 测试 Node.js 程序
openclaw gateway
各工具证书配置对照表
| 工具 | 证书来源 | 修复方式 |
|---|---|---|
| curl | 系统 /etc/ssl/cert.pem |
重新生成该文件 |
| npm | 内置 + cafile 配置 |
npm config set cafile /etc/ssl/cert.pem |
| git | 系统 + http.sslCAInfo |
git config --global http.sslCAInfo /etc/ssl/cert.pem |
| Node.js | 内置列表 | NODE_EXTRA_CA_CERTS=/etc/ssl/cert.pem |
| Python requests | 系统 / certifi | pip install certifi 或 REQUESTS_CA_BUNDLE |
关于阿里云百炼(DashScope)的额外说明
这一段要回答的问题:使用国内 AI 接口时,需要注意哪些配置细节?
在这次排查中,openclaw 配置使用的是阿里云百炼(DashScope)的 OpenAI 兼容接口:
{
"baseUrl": "https://dashscope.aliyuncs.com/compatible-mode/v1",
"api": "openai-completions",
"models": [
{ "id": "qwen3.5-plus" },
{ "id": "qwen3-coder-next" }
]
}
几点值得注意:
-
接口地址是国内可直连的,不需要代理,但 SSL 证书必须完整。 -
模型名称要精确: qwen3.5-plus、qwen3-coder-next等都是真实存在于百炼平台的模型,可以通过/v1/models接口验证。 -
API Key 以 sk-开头,与 OpenAI 格式兼容,可直接用于支持 OpenAI 协议的客户端。
验证 API Key 是否有效的最简命令:
curl "https://dashscope.aliyuncs.com/compatible-mode/v1/models" \
-H "Authorization: Bearer YOUR_API_KEY"
如果返回模型列表 JSON,说明 Key 有效且网络畅通。
为什么 macOS 会出现证书文件缺失?
这一段要回答的问题:/etc/ssl/cert.pem 为什么会不见?
macOS 本身的 SSL 实现主要依赖 Security Framework 和 Keychain,并不强依赖 /etc/ssl/cert.pem 这个文件——这个路径是 Unix/Linux 传统,macOS 是为了兼容第三方工具(curl、openssl、Python 等)才会用到它。
常见的导致该文件缺失的场景:
- ▸
macOS 大版本升级:系统升级有时会重置 /etc/ssl/目录 - ▸
Homebrew 的 OpenSSL 版本切换:不同版本的 OpenSSL 对证书路径处理不同 - ▸
全新安装的 Mac:Xcode Command Line Tools 未安装或未完整配置 - ▸
系统精简/优化操作:误删了 /etc/ssl/目录下的文件
最稳妥的长期方案,是在 dotfiles(.zshrc、.bash_profile)中同时维护好 NODE_EXTRA_CA_CERTS,并定期检查 /etc/ssl/cert.pem 是否存在。
作者反思
这次排查最让我印象深刻的,是同一个根本原因(证书文件缺失)在不同工具里的表现方式完全不同:
- ▸
curl 报 (77) error setting certificate verify locations - ▸
npm 报 UNABLE_TO_GET_ISSUER_CERT_LOCALLY - ▸
git 报 fatal: unable to access ... error setting certificate verify locations - ▸
Node.js 程序 却表现为”请求超时”——完全没有提到证书
最后一个最坑:超时是个非常模糊的错误,很容易让人以为是网络问题、API 问题,甚至程序 Bug,而不会第一时间联想到证书。这说明在排查网络类错误时,当所有显而易见的原因都排除之后,证书链问题值得专门检查一遍。
另一个教训是:每修复一个工具,要立刻测试,不要等全部配好再统一验证。否则出现新问题时,很难快速定位是哪一步引入的。
实用摘要 / 操作清单
- ▸
[ ] 检查 /etc/ssl/cert.pem是否存在:ls -la /etc/ssl/cert.pem - ▸
[ ] 不存在则重新生成: sudo security find-certificate -a -p /System/Library/Keychains/SystemRootCertificates.keychain | sudo tee /etc/ssl/cert.pem - ▸
[ ] 设置 npm 证书: npm config set cafile /etc/ssl/cert.pem - ▸
[ ] 设置 npm 国内镜像: npm config set registry https://registry.npmmirror.com - ▸
[ ] 设置 Git 证书: git config --global http.sslCAInfo /etc/ssl/cert.pem - ▸
[ ] 将 SSH 替换为 HTTPS(如遇 SSH 报错): git config --global url."https://github.com/".insteadOf ssh://git@github.com/ - ▸
[ ] 设置 Node.js 证书环境变量(永久): echo 'export NODE_EXTRA_CA_CERTS=/etc/ssl/cert.pem' >> ~/.zshrc && source ~/.zshrc - ▸
[ ] 验证 curl 连通性: curl https://www.baidu.com - ▸
[ ] 验证 npm 安装: npm i -g <package>
一页速览(One-page Summary)
| 问题现象 | 根本原因 | 修复命令 |
|---|---|---|
curl: (77) error setting certificate verify locations |
/etc/ssl/cert.pem 不存在 |
sudo security find-certificate -a -p /System/Library/Keychains/SystemRootCertificates.keychain | sudo tee /etc/ssl/cert.pem |
npm error UNABLE_TO_GET_ISSUER_CERT_LOCALLY |
npm SSL 验证失败 | npm config set cafile /etc/ssl/cert.pem |
git: Permission denied (publickey) |
依赖包使用了 SSH 协议 | git config --global url."https://github.com/".insteadOf ssh://git@github.com/ |
git: error setting certificate verify locations |
git SSL 证书路径错误 | git config --global http.sslCAInfo /etc/ssl/cert.pem |
| Node.js 程序请求超时 | Node.js 证书隔离 | export NODE_EXTRA_CA_CERTS=/etc/ssl/cert.pem |
| npm 镜像源不生效 | 配置未持久化 | npm config set registry https://registry.npmmirror.com 并验证 |
FAQ
Q1:重新生成 /etc/ssl/cert.pem 后,需要重启终端吗?
不需要重启,立即生效。但如果 NODE_EXTRA_CA_CERTS 是在 .zshrc 里设置的,需要执行 source ~/.zshrc 或新开一个终端窗口。
Q2:npm config set strict-ssl false 安全吗?能永久开着吗?
不安全,不建议永久保持关闭状态。它会跳过所有证书验证,让 npm 的 HTTPS 请求暴露在中间人攻击风险中。只在临时排查时使用,用完立刻执行 npm config set strict-ssl true 恢复。
Q3:NODE_EXTRA_CA_CERTS 和 NODE_TLS_REJECT_UNAUTHORIZED=0 有什么区别?
前者是追加可信证书,安全;后者是完全禁用 TLS 验证,不安全,只用于调试,绝对不能在生产环境使用。
Q4:为什么 npm 有时自动走了 registry.npmjs.org 而不是设置的镜像?
可能原因:当前项目目录下有 .npmrc 文件覆盖了全局配置,或者 npm 版本 bug,或者环境变量 NPM_CONFIG_REGISTRY 设置了其他值。可以用 npm config list 查看所有配置来源。
Q5:macOS 升级后多久会出现这个问题?
不是每次升级都会发生,但大版本升级(如 .0 版本)概率更高。建议升级后第一时间运行 ls -la /etc/ssl/cert.pem 检查。
Q6:Homebrew 安装的 openssl 和系统的有什么关系?
Homebrew 的 openssl 是独立安装的,证书路径通常是 /opt/homebrew/etc/openssl@3/cert.pem(Apple Silicon)或 /usr/local/etc/openssl/cert.pem(Intel)。如果你的项目依赖 Homebrew openssl,也需要单独确认该路径下的证书文件完整。
Q7:这套修复方法对 Python 的 requests 库也有效吗?
Python 的 requests 库默认使用 certifi 包提供的证书,与系统证书路径无关。如果遇到 Python SSL 报错,需要执行 pip install --upgrade certifi,或设置环境变量 REQUESTS_CA_BUNDLE=/etc/ssl/cert.pem。
