/var/www/tistory/Yongbaldae
yongmin@kali: ~/blog$ ls posts

NPM create-vite 실행 시 UNABLE_TO_VERIFY_LEAF_SIGNATURE 오류 해결기

회사 환경에서 npm create vite@latest 명령을 실행하다가
아래 오류와 함께 작업이 막혔다.

npm error code UNABLE_TO_VERIFY_LEAF_SIGNATURE
npm error request to https://registry.npmjs.org/create-vite failed, reason: unable to verify the first certificate

 

처음에는 “인터넷 문제인가?” 하는 정도로 가볍게 생각했지만,
문제 원인과 해결 과정이 생각보다 골 때렸다.
이 글에서는 문제 발생 원인 → 진단 과정 → 최종 해결 방법까지
실제 경험을 바탕으로 정리한다.

 

빠른 요약)Base-64 인코딩 X.509(.CER) 을 DER로 추출했었는데 , PEM으로 해야만 NPM이 인식을 할 수 있어서 문제가 발생했던 것이다. 내 전임자가 그 파일로 모든 설정을 다 해놨어서 문제였던 것.

 


1. 문제 상황

프론트엔드 템플릿을 만들기 위해 다음 명령을 실행했다.

npm create vite@latest . -- --template react
 

하지만 유독 내 PC에서만 아래 SSL 인증 관련 오류가 계속 반복되었다.

Error: unable to verify the first certificate
 

심지어 npm 뿐 아니라 Node.js로 테스트해도 동일한 SSL 검증 실패가 발생했다.

 
node -e "require('https').get('https://registry.npmjs.org', res => console.log(res.statusCode)).on('error', console.error)"

결과:

 
Error: unable to verify the first certificate

2. Chrome에서는 정상인데 npm만 안 되는 이유는?

놀랍게도 Chrome에서는 https://registry.npmjs.org 접속이 아무 문제 없었다.
SSL 인증서도 Google Trust Services(WE1)로 정상 표시되었다.

그런데 npm(Node.js)만 SSL 에러를 뿜었다.

이 이유는 Chrome과 Node.js의 SSL 검증 방식이 다르기 때문이다.

 

2-1. Chrome의 SSL 인증서 검증 방식

Chrome은 Windows OS의 인증서 저장소를 그대로 신뢰한다.

즉,

  • 회사에서 PC에 설치해 놓은 회사 전용 Root CA
  • 회사 보안장비가 발급한 중간 인증서

이런 것들을 Chrome은 자동으로 신뢰한다.

그래서 HTTPS 트래픽을 회사가 중간에서 검사하더라도
Chrome 입장에서는 정상 인증서처럼 보인다.


2-2. Node.js / npm의 SSL 인증서 검증 방식

반면 npm(Node.js)은 Windows 인증서 저장소를 사용하지 않는다.

  • Node.js는 자체 내장된 Root CA 목록만 신뢰한다.
  • 회사에서 설치한 CA는 Node가 기본적으로 모른다.

즉, 회사 네트워크가 HTTPS 트래픽을 검사하면서
회사 CA로 다시 서명한 인증서를 보내면,

Node.js는 그 CA를 모르기 때문에 다음과 같이 판단한다.

“이 인증서, 내 신뢰 목록에 없는데? → 위조된 인증서? → 검증 실패!”

그래서 npm은 계속
UNABLE_TO_VERIFY_LEAF_SIGNATURE
오류를 띄울 수밖에 없었다.


3. 문제를 악화시킨 원인: npm 설정의 cafile

조사 과정에서 다음 명령을 통해 npm의 설정을 확인했다.

npm config get cafile
출력: C:\Users\XXXXXX.cer

즉, npm은 회사에서 사용하던 XXXXXX.cer 파일을
“유일한 Root CA로 강제 사용” 하고 있던 상태였다.

문제는 두 가지:

① 회사 CA 파일은 npmjs.org의 인증서와 전혀 관련 없음

npmjs.org는 Google CA를 사용한다.
회사 내부 CA만 쓰면 npmjs.org 인증서가 절대 검증될 수 없다.

② 해당 파일이 Node.js가 읽을 수 없는 형식(DER) 가능성

Node.js는 PEM(Base-64) 형태만 읽을 수 있다.
DER(Binary) 형식의 .cer 파일을 넣어두면 Node는 인증서를 해석하지 못한다.

결과적으로 npm은 잘못된 CA 파일 하나만 보고 검증을 시도했고,
당연히 TLS가 실패할 수밖에 없었다.


 4. 해결 과정

4-1. 먼저 npm의 잘못된 CA 설정 삭제

 

npm config delete cafile

이걸로 npm이 다시 기본 CA 목록을 사용하도록 초기화한다.


4-2. 회사 Root CA를 Windows 인증서 저장소에서 정확히 추출

회사 네트워크가 사용하는 Root / Intermediate CA를
Windows 인증서 저장소(certmgr.msc)에서 직접 확인한다.

(윈도우키 + R 누른채로 certmgr.msc 입력)

추출 시 반드시 선택해야 할 옵션

Base-64 인코딩 X.509(.CER)

여기서 중요한 점:

확장자가 .cer 이라도 실제 내용은 두 종류이다.

  1. DER(Binary) : Node.js가 읽지 못함 → 문제 원인
  2. Base-64 X.509(텍스트, PEM) : Node.js 정상 인식 → 문제 해결

그래서 certmgr.msc에서 Base-64 X.509(.CER) 로 다시 내보내는 것이 핵심이었다.


4-3. Node.js에 회사 Root CA 적용

 
setx NODE_EXTRA_CA_CERTS "C:\certs\company-root.cer"

PowerShell 재시작 후 확인:

 
node -p "process.env.NODE_EXTRA_CA_CERTS"

4-4. 다시 HTTPS 테스트

 
node -e "require('https').get('https://registry.npmjs.org', res => console.log(res.statusCode)).on('error', console.error)"

이번에는 정상적으로 200 또는 301 코드가 출력되며
TLS 검증이 통과되었다.


4-5. create-vite 실행 성공

 
npm create vite@latest . -- --template react

드디어 정상 작동했다.

 


5. 여담

혹시나 아래 짓 하지마라.

회사 보안을 쌩까겠다는 건데 , 이게 되는 것도 문제이거니와 보안사고 터졌을 때 본인이 짊어져야 할 수도 있어서 문제 커진다.

npm config set strict-ssl false
npm config set registry http://registry.npmjs.org/
more_posts (recent 5)