한 줄 요약: Verdaccio 는 npmjs uplink 를 lazy 캐시로 묶어주는 사설 npm registry 임.
v6 는 Node.js 18+ 만 요구하고 설정은
config.yaml한 장에 모임. 캐시 용도로만 쓰는 환경이면 추가 인증 없이도 기본값으로 충분함.
개요
인터넷망에 직접 접근하지 못하는 장비들에게 외부 npm 패키지를 제공해야 하는 상황에서 Verdaccio 의 proxy 기능을 활용하게 됨. 내부망 장비가 npmjs.com 으로 직접 나가지 못하면 npm install 자체가 실패하므로, public 패키지를 한 번 끌어와 사내에서 캐시로 재사용하는 중계점이 필요함.
Verdaccio 는 그 중계점을 한 프로세스로 합친 사설 npm registry 임. 모든 public 패키지를 미리 미러링하지 않고 요청 시점에만 npmjs 에서 끌어와 로컬에 캐시하는 lazy 방식이라 디스크가 가벼움.
이 글은 v6 기준으로 아래 두 단계를 한 흐름으로 정리함.
- Docker 로 기동 (부팅 시 자동 재기동은
--restart정책에 위임) - 클라이언트(
.npmrc)에서 글로벌 설치까지 깨지지 않도록 registry 등록
| 항목 | 값 |
|---|---|
| 현재 메이저 | Verdaccio 6 (실측 6.5.2) |
| Node.js 요구사항 | v18 이상 (공식 권장 — Node 22 LTS) |
| 기본 listen | localhost:4873 — Docker 이미지는 0.0.0.0:4873 으로 띄움 |
| 설정 파일 | config.yaml 한 장 — Docker 이미지 기본 경로 /verdaccio/conf/config.yaml |
| Uplink | npmjs (URL https://registry.npmjs.org/) — 미캐시 요청만 lazy 프록시 |
| 로그 키 변경 | v5.22.0+ 부터 logs: → log: 로 키 이름 변경. v6 도 logs: 호환은 되지만 권장은 log: |
검증 환경: Verdaccio 6.5.2 (공식 이미지
verdaccio/verdaccio:latest, 내부 Node 22.22.1), 클라이언트는 호스트의 npm 11.6.2 / Node 24.12.0. 호스트 포트 14873 → 컨테이너 4873 매핑.
결론
어떤 형태로 굳힐 것인가 — 3가지 운영 결정
운영 환경에 적용하기 전에 먼저 정해두면 후속 설정이 단순해지는 결정 3가지.
| 결정 항목 | 권장값 | 이유 |
|---|---|---|
| 기동 방식 | Docker (verdaccio/verdaccio:6) + bind volume | 호스트 Node 버전과 분리되고, 업그레이드는 이미지 태그 교체로 끝남. --restart unless-stopped 한 줄로 lifecycle 위임 |
| Web UI | 외부망 접근이 가능한 환경이면 web.enabled: false | UI 가 켜져 있으면 패키지 메타·다운로드 통계가 비인증 사용자에게 노출됨 |
| Uplink 범위 | 사내 빌드에 필요한 단일 npmjs uplink 만 유지 | 여러 uplink 를 묶으면 캐시 충돌·메타 병합 비용이 커지고, 디버깅 시 어느 origin 인지 추적이 어려워짐 |
클라이언트 registry 등록 — npm set registry 의 함정
npm set registry http://... 만 쳐두면 사용자 수준 ~/.npmrc 에만 저장되어 sudo npm install -g <pkg> 시 root 의 npmrc 를 보느라 사설 registry 를 못 찾는 사고가 흔함.
글로벌 설치까지 사설 registry 를 타게 만들려면 시스템 단에 등록해야 함.
| 범위 | 파일 | 명령 또는 형식 |
|---|---|---|
| 명령어 1회 | (없음) | npm install --registry http://...:4873/ |
| 사용자 전역 | ~/.npmrc | npm set registry http://...:4873/ |
| 프로젝트 전용 | <repo>/.npmrc | npm set registry http://...:4873/ --location project |
| 시스템 전역 | /etc/npmrc (또는 globalconfig) | 직접 작성 — registry=http://...:4873/ |
npm config ls -l | grep ^globalconfig 로 그 시스템의 글로벌 npmrc 위치를 먼저 확인함 — 배포판마다 /etc/npmrc, /usr/local/etc/npmrc, /usr/etc/npmrc 로 갈림.
적용 절차
1단계 — Docker 로 기동
공식 이미지의 표준 마운트 경로 3개 — /verdaccio/conf (설정), /verdaccio/storage (캐시 데이터 보관), /verdaccio/plugins (확장).
컨테이너 내부 사용자는 UID 10001, GID 65533 이라 bind mount 디렉토리 권한을 미리 맞춤.
V_PATH=/srv/verdaccio
mkdir -p $V_PATH/{conf,storage,plugins}
sudo chown -R 10001:65533 $V_PATH
docker run -d --name verdaccio \
-p 4873:4873 \
-v $V_PATH/conf:/verdaccio/conf \
-v $V_PATH/storage:/verdaccio/storage \
-v $V_PATH/plugins:/verdaccio/plugins \
--restart unless-stopped \
verdaccio/verdaccio:6설정을 따로 마운트하지 않은 상태로 한 번 띄우면 컨테이너 내부에 기본 config.yaml 이 생김 — 이 파일을 호스트로 복사해 편집 후 다시 마운트하는 흐름이 안전함.
docker cp verdaccio:/verdaccio/conf/config.yaml $V_PATH/conf/config.yaml--restart unless-stopped 플래그가 부팅 시 자동 기동·crash 시 재시작을 모두 담당함. systemd unit 은 다른 서비스가 After=verdaccio.service 로 의존성 선언이 필요할 때만 추가하면 됨 — 단순 캐시 용도면 docker daemon 이 lifecycle 을 그대로 가져가도 충분함.
2단계 — config.yaml 운영 형태
기본 config 에서 3가지만 손보면 캐시 운영 형태가 됨 — listen 0.0.0.0, web 비활성, 로그 파일 출력.
# /verdaccio/conf/config.yaml — v6 권장 키 이름 기준
storage: /verdaccio/storage/data
plugins: /verdaccio/plugins
listen:
- 0.0.0.0:4873
web:
enabled: false
uplinks:
npmjs:
url: https://registry.npmjs.org/
packages:
'@*/*':
access: $all
proxy: npmjs
'**':
access: $all
proxy: npmjs
server:
keepAliveTimeout: 60
middlewares:
audit:
enabled: true
log:
type: file
path: /verdaccio/storage/verdaccio.log
format: pretty-timestamped
level: httpweb.enabled: false 는 v6 기준임 (v4 시절의 enable: 은 deprecated). log: 도 v5.22.0+ 에서 logs: 에서 변경된 키이므로 새 설정은 단수형으로 적음.
3단계 — 클라이언트 registry 등록
사용자별·프로젝트별·시스템별 세 단계 중 sudo npm install -g 까지 깨지지 않게 하려면 시스템 단(/etc/npmrc)에 등록하는 게 정공법.
# 시스템 글로벌 npmrc 위치 확인
npm config ls -l | grep "^globalconfig ="
# 위치 확인 후 그 경로에 작성
sudo tee /etc/npmrc >/dev/null <<'EOF'
registry=http://<host>:4873/
EOF이 한 줄만 등록해두면 npm install·sudo npm install -g 모두 사설 registry 를 거쳐 npmjs 로 lazy 프록시됨.
상세
Uplink 가 lazy 캐시인 이유
Verdaccio 가 미러링 도구가 아니라 lazy proxy 인 게 디스크 비용 측면에서 핵심임. 클라이언트가 lodash 를 요청하면 다음 순서로 동작함.
storage/lodash/package.json이 있는지 검사- 없으면
uplinks.npmjs의 URL 로 메타데이터 가져오기 - 요청된 버전의 tarball 만 받아 storage 에 저장
- 다음 동일 요청부터는 storage 에서 응답
따라서 공개된 npm 전체를 미리 받지 않고도 사내 빌드에 실제 쓰이는 패키지만 누적되는 형태가 됨. 이 동작은 packages.<glob>.proxy: npmjs 가 붙어 있을 때만 활성화됨.
Verdaccio 는 풀 미러(full mirror) 기능을 제공하지 않음 — npmjs 전체 패키지를 사전에 받아두는 옵션은 설계상 없음. 도입 시점의 요건이 “사내에서 실제 쓰이는 패키지만 사용 시점에 캐시” 였으므로 lazy 방식이 그대로 맞아떨어졌음.
log: 키 — v5.22.0+ 에서 이름이 바뀜
이 글의 config.yaml 예시가 단수형 log: 를 쓴 이유는 단순함. v5.22.0 부터 logger 속성명이 logs → log 로 바뀌었음.
v6 는 logs: 호환을 유지하지만 docs 가 권장하지 않는다고 명시함. 새로 작성하는 config 면 단수형 log: 만 쓰면 됨.
Since v5.22.0 the logger property is renamed from `logs` to `log`,
but still compatible with v6 but not recommended to use.레벨은 fatal·error·warn·info·http·debug·trace 7단계. http 는 요청 한 줄씩 찍히므로 운영 초기 디버그용으로 적당하고, 안정화된 후에는 info 로 내리는 패턴.
테스트
테스트 환경:
verdaccio/verdaccio:latest(Verdaccio 6.5.2, 내부 Node 22.22.1) 을 호스트 포트 14873 에 매핑해 기동. 클라이언트는 호스트의 npm 11.6.2.
1. 기동 직후 헬스체크
docker run -d --name blog-test-verdaccio -p 14873:4873 verdaccio/verdaccio:latest
until curl -fsS http://127.0.0.1:14873/-/ping >/dev/null; do sleep 1; done
curl -fsS http://127.0.0.1:14873/-/ping{}/-/ping 은 빈 객체를 반환하면 정상임 — npm CLI 도 같은 endpoint 로 헬스체크를 함.
2. uplink lazy 캐시 — npmjs 패키지 install
.npmrc 의 registry 를 verdaccio 로 두고 npmjs 의 패키지를 install 하면 verdaccio 가 npmjs 에서 한 번 끌어와 storage 에 캐시함.
mkdir -p /tmp/blog-test-verdaccio/consumer1 && cd $_
echo "registry=http://127.0.0.1:14873/" > .npmrc
npm install lodash@4.17.21 --no-fund --no-audit
docker exec blog-test-verdaccio ls /verdaccio/storage/data/added 1 package in 506ms
---
lodash3. 캐시 적중 — 두 번째 install 은 storage 에서
같은 패키지를 다른 디렉토리에서 다시 install 하면 verdaccio 가 이미 storage 에 있는 tarball 을 그대로 응답함. npm CLI 의 로컬 캐시(--cache)가 영향을 주지 않도록 consumer2 에 별도 캐시 디렉토리를 둠.
mkdir -p /tmp/blog-test-verdaccio/consumer2 && cd $_
echo "registry=http://127.0.0.1:14873/" > .npmrc
npm install lodash@4.17.21 --no-fund --no-audit --cache=$PWD/.npm-cacheadded 1 package in 415ms첫 install (506ms) 보다 두 번째 install (415ms) 이 짧음 — verdaccio 가 외부 npmjs 라운드트립을 건너뛰고 storage 의 tarball 을 즉시 응답하기 때문임. 단일 패키지 차이는 작아 보여도 사내 빌드처럼 수십~수백 개 의존성이 같이 install 될수록 격차가 누적됨.
참고
- Verdaccio Documentation — Installation — Node.js 18+ 요구사항,
npm i -g verdaccio/ Docker 기동 명령 - Verdaccio Documentation — Configuration File —
storage·uplinks·packages·web·server·middlewares섹션 정의와 기본값 - Verdaccio Documentation — Use with Docker — 공식 이미지
verdaccio/verdaccio의 볼륨 경로(/verdaccio/conf·/verdaccio/storage·/verdaccio/plugins) 와chown 10001:65533권장 - Verdaccio Documentation — Use with npm —
npm set registry범위(--location),publishConfig.registry - Verdaccio Documentation — Logger — v5.22.0+
logs→log키 변경,type·format·level옵션