Appearance
企業環境 Node.js SSL 憑證錯誤修復
在 Zscaler 等 TLS inspection 環境下,透過
NODE_EXTRA_CA_CERTS讓 Node.js 信任企業自簽 CA,修復UNABLE_TO_GET_ISSUER_CERT_LOCALLY錯誤。
概述
企業網路通常會在 HTTPS 連線上注入自訂 CA(Zscaler、Palo Alto、Fortinet 等),對所有 TLS 流量進行解密再重新加密(TLS inspection)。瀏覽器和作業系統通常已預先信任這些企業 CA,但 Node.js 使用自己內建的 CA bundle,不讀取系統憑證庫,因此會出現以下錯誤:
SSL certificate error (UNABLE_TO_GET_ISSUER_CERT_LOCALLY)解決方式是透過環境變數 NODE_EXTRA_CA_CERTS 指向企業根 CA 憑證,讓 Node.js 的 TLS 驗證補入這份額外信任。此方式適用於 npm、npx、Claude Code、以及所有使用 Node.js https module 的工具。
核心內容
識別 TLS Inspection 環境
開啟任意 HTTPS 網站,查看憑證鏈頂端的根 CA:若根憑證是公司名稱或防火牆廠商(Zscaler、Palo Alto、Fortinet、Cisco Umbrella 等)而非公開 CA(DigiCert、Let's Encrypt、GlobalSign),即為 TLS inspection 環境。
NODE_EXTRA_CA_CERTS 機制
Node.js 提供 NODE_EXTRA_CA_CERTS 環境變數作為追加信任的標準做法。設定後,Node.js 在建立 TLS 連線時會同時信任內建 CA bundle 與此環境變數指向的憑證檔。憑證內容必須為 PEM 格式(-----BEGIN CERTIFICATE----- 開頭),副檔名不限(.pem、.crt、.cer 皆可)。
WSL 系統層級信任
若需要讓 curl、Python requests、系統套件管理等非 Node.js 工具也信任企業 CA,需將憑證安裝至 WSL Ubuntu 的系統 CA 庫。注意:update-ca-certificates 只讀取 /usr/local/share/ca-certificates/ 下的 .crt 副檔名,副檔名錯誤會靜默略過。
常見踩坑:檔名含空白
NODE_EXTRA_CA_CERTS 載入失敗最常見原因是檔名含空白(例如 Zscaler Root CA.crt),Node.js 會輸出 ignoring extra certs from ..., load failed 並靜默略過。務必確保憑證檔名無空白。
關鍵要點
- Node.js 不讀取 Windows 或 Linux 系統憑證庫,需手動設定
NODE_EXTRA_CA_CERTS - 憑證檔名不能含空白,否則 Node.js 靜默略過不報錯
NODE_EXTRA_CA_CERTS副檔名不限,內容必須是 PEM 格式- WSL 中
update-ca-certificates要求副檔名必須是.crt - Root CA 通常有效 10–20 年,不需頻繁更新
實際應用
此問題最常出現在:
- Claude Code / npm 在企業環境首次安裝或更新時
- CI/CD pipeline 在 corporate proxy 後執行
npm install - WSL 開發環境存取公司內網 HTTPS API
部署設定參考
以下為實際設定步驟,供查詢與複製使用。
步驟一:取得企業 CA 憑證(Windows)
- Chrome 開啟任意 HTTPS 網站(如
https://google.com) - 點網址列鎖頭 →「連線是安全的」→「憑證有效」
- 切到「憑證路徑」分頁,找到最頂層的根憑證(如
Zscaler Root CA) - 點選 →「檢視憑證」→「詳細資料」→「複製到檔案」
- 匯出格式選 Base-64 編碼 X.509 (.CER)
環境參數
| 項目 | 值 |
|---|---|
| 憑證存放路徑(Windows) | D:\cert\zscaler-root-ca.crt |
| 憑證存放路徑(WSL) | ~/.local/share/certs/zscaler-root-ca.crt |
| 環境變數名稱 | NODE_EXTRA_CA_CERTS |
| 憑證格式 | PEM(-----BEGIN CERTIFICATE-----) |
update-ca-certificates 存放路徑 | /usr/local/share/ca-certificates/ |
操作指令
Windows PowerShell 設定:
powershell
# 臨時生效(本 Session)
$env:NODE_EXTRA_CA_CERTS = "D:\cert\zscaler-root-ca.crt"
# 永久設定(User 層級環境變數)
[Environment]::SetEnvironmentVariable("NODE_EXTRA_CA_CERTS", "D:\cert\zscaler-root-ca.crt", "User")WSL 設定:
bash
# 建立憑證目錄並複製憑證(從 Windows 複製過來)
mkdir -p ~/.local/share/certs
cp /mnt/c/certs/zscaler-root-ca.crt ~/.local/share/certs/zscaler-root-ca.crt
# 在 ~/.zshrc 或 ~/.bashrc 加入
export NODE_EXTRA_CA_CERTS="$HOME/.local/share/certs/zscaler-root-ca.crt"
# 生效
source ~/.zshrc(可選)WSL 系統層級信任(curl、Python 等工具同時受益):
bash
sudo cp ~/.local/share/certs/zscaler-root-ca.crt /usr/local/share/ca-certificates/zscaler-root-ca.crt
sudo update-ca-certificates修正檔名含空白問題:
bash
mv ~/.local/share/certs/"Zscaler Root CA.crt" ~/.local/share/certs/zscaler-root-ca.crt
export NODE_EXTRA_CA_CERTS="$HOME/.local/share/certs/zscaler-root-ca.crt"驗證:
bash
# 測試 Node.js TLS
node -e "require('https').get('https://registry.npmjs.org', r => { console.log('OK', r.statusCode); r.resume(); })"
# 測試系統層級
curl -v https://registry.npmjs.org
# 查看憑證有效期
openssl x509 -in ~/.local/share/certs/zscaler-root-ca.crt -noout -dates副檔名對照
| 工具 | 副檔名要求 | 內容格式 |
|---|---|---|
NODE_EXTRA_CA_CERTS | 不限(.pem、.crt、.cer 皆可) | PEM |
update-ca-certificates | 必須 .crt | PEM |
相關概念
- PowerShell HTTPS Proxy 設定 — 企業環境同類問題:Proxy 設定
- WSL 環境設定進階技巧 — WSL DNS、PATH 等環境整合問題
- OpenSSL 自簽憑證產生 — CA 憑證概念基礎