できない.dev

Node.js で fetch が「self-signed certificate in certificate chain」で接続できない

Node.js 組み込み fetch は OpenSSL の信頼ストアで TLS チェーンを検証するため、社内 CA や自己署名証明書を挟んだ環境では接続できません。NODE_EXTRA_CA_CERTS で追加 CA を読み込ませるのが安全な対処で、NODE_TLS_REJECT_UNAUTHORIZED=0 は検証を完全に切ってしまうため本番では使いません。

公開: 更新:

要約

Node.js 組み込み fetch は OpenSSL の信頼ストアで TLS チェーンを検証するため、社内プロキシや MITM 装置で挿入された自己署名 CA を信頼していない環境では self-signed certificate in certificate chain で接続できません。NODE_EXTRA_CA_CERTS で追加 CA を読み込ませるのが安全な対処で、NODE_TLS_REJECT_UNAUTHORIZED=0 は検証を完全に切ってしまうため本番では使いません。

よくある原因

  1. 社内プロキシや MITM 装置が挿入する自己署名 CA が Node.js の信頼ストアに入っていない
  2. サーバが中間 CA を返しておらず、不完全なチェーンになっている
  3. Node.js は独自の CA バンドルを内蔵し、OS の信頼ストアを自動では参照しない
  4. Docker / CI で /etc/ssl/certs をマウントしていない、または ca-certificates が古い

解決策

1. CA を環境変数で追加する(推奨)

社内 CA の PEM ファイルを NODE_EXTRA_CA_CERTS で指定すると、Node 内蔵バンドルに 追加 して信頼します(公式ドキュメント(新しいタブで開く))。

export NODE_EXTRA_CA_CERTS=/etc/ssl/private/corp-root-ca.pem
node app.js

複数 CA が必要なら同じ PEM ファイル内に連結します。

2. OS の信頼ストアを使う

Node.js 22 以降では --use-system-ca で OS の信頼ストアを参照できます。
社員 PC に CA が配布されている環境ではこちらが楽です。

node --use-system-ca app.js
# あるいは
NODE_OPTIONS="--use-system-ca" node app.js

3. undici Agent で CA を渡す

特定のリクエストだけ別 CA を使いたい場合は undiciAgent を組み立てて fetch に渡します。

import { Agent, fetch } from "undici";
import { readFileSync } from "node:fs";
 
const agent = new Agent({
  connect: { ca: readFileSync("./corp-ca.pem") },
});
 
const res = await fetch("https://internal.example.com/", { dispatcher: agent });

4. 開発検証時のみ検証を切る

NODE_TLS_REJECT_UNAUTHORIZED=0 node debug.js

このフラグはプロセス全体で TLS 検証を無効化するため、CI / 本番では使わないでください。process.env への直接代入も避け、コマンドラインから一時的に渡します。

実行例

実際に上記の手順を node:20(Debian GNU/Linux 12 bookworm / Node.js v20.20.2 / OpenSSL 3.0.19)環境で動かすと、CA を追加しない素の fetch では本記事のエラーメッセージ self-signed certificate in certificate chain に対応するエラーコード SELF_SIGNED_CERT_IN_CHAINerr.cause.code)が発生し、NODE_EXTRA_CA_CERTS を指定した場合は HTTP 200 が返ることが確認できます。

$ node -v
v20.20.2
$ openssl version
OpenSSL 3.0.19 27 Jan 2026 (Library: OpenSSL 3.0.19 27 Jan 2026)
CA 作成の終了コード: 0
署名の終了コード: 0
$ node server.js
HTTPS サーバ起動: https://localhost:8443
$ node client.js
失敗: SELF_SIGNED_CERT_IN_CHAIN
終了コード: 0
$ NODE_EXTRA_CA_CERTS=./ca-cert.pem node client.js
status: 200 body: ok
終了コード: 0
$ NODE_TLS_REJECT_UNAUTHORIZED=0 node client.js
(node:98) Warning: Setting the NODE_TLS_REJECT_UNAUTHORIZED environment variable to '0' makes TLS connections and HTTPS requests insecure by disabling certificate verification.
(Use `node --trace-warnings ...` to show where the warning was created)
status: 200 body: ok
終了コード: 0

— 2026-08-02 時点の出力

この記事は役立ちましたか?