npm run build(webpack、Create React App、vue-cli、Angular など)が、次のエラーで突然落ちるようになったら、原因はほぼ確実に Node のバージョンを上げたことです。
Error: error:0308010C:digital envelope routines::unsupported
エラーの末尾には code: 'ERR_OSSL_EVP_UNSUPPORTED' が付きます。ビルドツール上では次のような表示になることもありますが、原因はすべて同じです。
Module build failed: Error: error:0308010C:digital envelope routines::unsupported
opensslErrorStack: [ 'error:03000086:digital envelope routines::initialization error' ]
急いでビルドを通したいだけなら、NODE_OPTIONS=--openssl-legacy-provider を付けるのが手っ取り早い対処です。ただしこれは一時しのぎで、常用すべきではありません。まずはなぜ出るのかを一目で確認してください。
まず node -v を確認する
このエラーは、あなたのコードが変わったから出るのではありません。Node に同梱される OpenSSL のメジャーバージョンが変わったから出ます。
| Node のバージョン | 同梱 OpenSSL | md4 などの旧アルゴリズム |
|---|---|---|
| Node 16 系 | OpenSSL 1.1.1 | 既定で使える(エラーにならない) |
| 17 以上(18 / 20 / 22 / 24 …) | OpenSSL 3.x | 既定で無効。使うと ERR_OSSL_EVP_UNSUPPORTED |
(境界は Node 17 で OpenSSL 3 に上がった点です。16 系までは OpenSSL 1.1.1 系でした。)
OpenSSL 3 では、md4・RC4・RIPEMD-160・DES といった古い暗号が 「legacy プロバイダ」に隔離され、既定では読み込まれなくなりました(md5 は default プロバイダに残るので、このエラーの原因にはなりません)。webpack などのビルドツールは、成果物のハッシュ計算に内部で md4 を使っています。そのため「コードは何も変えていないのに、Node を 17 以上に上げた瞬間ビルドが落ちる」という状況が起きます。
典型的なのは 「自分のPC(まだ Node 16)では通るのに、Node を上げた同僚や、新しいイメージの CI でだけ落ちる」 というパターンです。原因を追う前に、まず落ちている環境の node -v を見てください。
再現(最小構成)
ビルドツールを持ち出さなくても、md4 を呼ぶだけで同じエラーになります。
// index.cjs
const crypto = require('crypto');
const hash = crypto.createHash('md4');
hash.update('errfix');
console.log(hash.digest('hex'));
これを Node 18 で実行すると、次のように落ちます(終了コードは 1)。
Error: error:0308010C:digital envelope routines::unsupported
at new Hash (node:internal/crypto/hash:69:19)
...
library: 'digital envelope routines',
reason: 'unsupported',
code: 'ERR_OSSL_EVP_UNSUPPORTED'
}
createHash('md4') の行で、md4 を提供するはずのプロバイダが見つからずに失敗しています。
解決1:まず動かす(--openssl-legacy-provider)
いますぐビルドを通したいなら、legacy プロバイダを明示的に有効化します。コードは 1 行も変えません。
# macOS / Linux
export NODE_OPTIONS=--openssl-legacy-provider
npm run build
# Windows PowerShell
$env:NODE_OPTIONS="--openssl-legacy-provider"
npm run build
npm スクリプトに直接埋め込む形でも構いません。
{
"scripts": {
"build": "node --openssl-legacy-provider ./node_modules/.bin/webpack"
}
}
先ほどの再現コードも、node --openssl-legacy-provider index.cjs として実行すればエラーは消え、ハッシュ値が出力されて終了コードは 0 になります。コードは 1 文字も変えず、フラグを足しただけで通ります。
仕組み:OpenSSL 3 のプロバイダ
OpenSSL 3 は暗号アルゴリズムを「プロバイダ」という単位に分割しました。既定で読み込まれるのは default プロバイダで、そこには安全な現行アルゴリズムしか入っていません。md4 のような古いものは legacy プロバイダに移され、明示的に有効化しない限り使えません。
--openssl-legacy-provider は、この legacy プロバイダを起動時に読み込ませるフラグです。これで md4 が再び使えるようになり、ビルドツールのハッシュ計算が通ります。
解決2:恒久対応(フラグを外せる状態にする)
--openssl-legacy-provider は 無効化された古い暗号をわざわざ復活させるフラグです。md4 や RC4 が既定から外されたのは、それらが弱くて危険だからです。フラグを付けっぱなしにするのは、鍵の壊れた古い錠前をあえて使い続けるようなもの——動きはしますが、外せるなら外すべきです。恒久対応は次のどれかです。
- ビルドツールを Node 17+ 対応済みの版へ上げる。もっとも確実です。webpack 単体なら 5.61.0 以上(このバージョンでハッシュ計算を OpenSSL 非依存の実装に切り替え、Node 17+ で落ちなくなった)。Create React App なら
react-scriptsを v5 系へ(webpack^5.64.4を取り込む)。なお webpack v5 も既定のハッシュはmd4のままなので、「v5 にすれば無条件で直る」ではなく「Node 17+ 対応版に上げる」と捉えてください。必要ならoutput.hashFunction: 'xxhash64'を明示設定する手もあります。 - 自分のコードで
md4を使っている場合は、sha256など OpenSSL 3 の既定プロバイダにあるアルゴリズムへ置き換える。用途が「衝突耐性のいらない一意キー生成」なら置換して差し支えありませんが、ハッシュ値が変わる影響(値の長さが変わる/保存済みのID・ファイル名との互換/キャッシュが一度きり再生成される)だけは確認してください。 - どうしても Node を上げられない事情があるなら、Node 16 系(OpenSSL 1.1.1 同梱)に留まるのも短期的には有効です。ただし Node 16 はすでにサポート終了しており、これも先送りにすぎません。
順番としては、まず解決1でビルドを通し、その上で解決2でツールを上げてフラグを消す。フラグは「移行までの松葉杖」と割り切ってください。
切り分け(うまくいかないとき)
--openssl-legacy-providerを付けても変わらない:フラグが実際のビルドプロセスに渡っていないことが多い。package.jsonの別スクリプト経由や、ビルドを子プロセスで起動している場合は、そのプロセスにNODE_OPTIONSが引き継がれているか確認する。- webpack や CRA ではなく Vite / esbuild などで出た:原因は同じ(OpenSSL 3 で無効化された暗号を使っている)。まず解決1で動かし、そのツールのバージョンを上げてフラグを外す方針は変わらない。
- 手元では出ないのに CI でだけ出る:手元がまだ Node 16 で、CI が 17 以上のことがある。両方の
node -vをそろえて再現環境を合わせる。 - フラグは常設環境変数にしない:
NODE_OPTIONS=--openssl-legacy-providerを shell の常設プロファイル(.bashrcなど)に入れると、すべての Node プロセスで無効化された弱い暗号が復活します。そのビルドコマンドに限定して渡してください。