Verdaccio решает проблему, которой у команды из трёх человек нет
Кто-то в чате разработки бросает ссылку на Verdaccio и фразу «а не поднять ли нам свой npm-реестр» — и через полчаса уже есть тикет на установку. Проблема в том, что за этим тикетом редко стоит настоящая боль: чаще это желание «сделать как в больших компаниях» или смутное ощущение, что npmjs.org — ненадёжная точка опоры. Разберём честно: кому Verdaccio закрывает реальную проблему, а кому добавляет сервис, который нужно поднимать, бэкапить, обновлять и держать живым — ради выгоды, которой в его случае просто нет.
Содержание
- Что такое Verdaccio и как он на самом деле работает
- Когда свой приватный npm-реестр решает настоящую проблему
- Установка и первый запуск: минимальный рабочий стенд
- Публикация приватных пакетов и настройка .npmrc
- Где Verdaccio — решение проблемы, которой у вас нет
- Что сделать вместо Verdaccio, если команда маленькая
Что такое Verdaccio и как он на самом деле работает
Verdaccio — это лёгкий self-hosted npm-совместимый реестр, написанный на Node.js. По сути это прокси-сервер, который умеет две вещи одновременно: отдавать пакеты, опубликованные вами напрямую в него (приватные пакеты), и проксировать запросы к npmjs.org для всего остального, кэшируя ответы на диске. С точки зрения npm, yarn или pnpm он выглядит как обычный registry — достаточно поменять URL в .npmrc, и клиент даже не заметит разницы.
Ключевая идея конфигурации Verdaccio — файл config.yaml, где для каждого пакетного скоупа задаётся, кто может читать, кто публиковать, и через какой uplink (внешний источник) пакет проксировать при отсутствии в локальном хранилище:
storage: ./storage
auth:
htpasswd:
file: ./htpasswd
max_users: 10
uplinks:
npmjs:
url: https://registry.npmjs.org/
packages:
'@myorg/*':
access: $all
publish: $authenticated
unpublish: $authenticated
'**':
access: $all
publish: $authenticated
proxy: npmjs
Хранилище по умолчанию — обычная файловая система на диске сервера, где крутится Verdaccio. Это важная деталь для дальнейшего разговора: никакой распределённости из коробки нет, масштабировать реестр горизонтально без общей файловой системы или плагина вроде verdaccio-s3-storage не получится. Для одного инстанса на VPS это не проблема, но если кто-то воображает Verdaccio как «наш маленький npmjs», сразу стоит понимать границы.
Когда свой приватный npm-реестр решает настоящую проблему
Есть три ситуации, где Verdaccio (или его более тяжёлые аналоги вроде Nexus и Artifactory) закрывают реальную боль, а не создают её.
Закрытые внутренние библиотеки, переиспользуемые между несколькими репозиториями. Если у вас есть, например, @myorg/ui-kit, @myorg/api-client и @myorg/logger, которые подключаются как зависимости в пять разных сервисов с разными циклами релиза, публиковать их куда-то нужно объективно. Варианты — git-зависимость ("ui-kit": "git+ssh://..."), локальные tarball-файлы через npm pack, или нормальный реестр с версионированием через semver. При росте количества таких пакетов и потребителей git-зависимости и ручные tarball быстро превращаются в боль: нет единого списка версий, npm outdated не работает, CI не может просто закэшировать зависимость. Тут приватный реестр — не роскошь, а рабочий инструмент.
Монорепозиторий, из которого пакеты реально публикуются наружу или в другие репозитории. Если у вас монорепо с внутренними пакетами, которые потребляются только внутри того же монорепо, реестр не нужен — об этом ниже. Но если часть пакетов монорепо публикуется для использования в отдельных, физически других репозиториях (например, у вас есть основной продукт и отдельный публичный SDK на его основе), без реестра снова не обойтись.
Контроль над кэшем публичных пакетов и цепочкой поставок. Когда в команде десятки разработчиков и CI гоняет сотни сборок в день, проксирующий кэш перед registry.npmjs.org снижает нагрузку на внешний реестр, ускоряет установку зависимостей (пакет один раз скачан — дальше отдаётся из локального кэша) и даёт точку, где можно физически заблокировать конкретную вредоносную версию пакета для всей организации, не дожидаясь, пока npm сам её отзовёт. Об одном из сценариев, где отсутствие такого контроля обернулось реальным инцидентом, мы разбирали в статье про пакет, который удалили из реестра и прод перестал собираться — но там счёт шёл на десятки сборок в сутки и множество сервисов, а не на один проект с редкими деплоями.
Во всех трёх случаях объединяющий признак один: пакетов, которые публикуются и переиспользуются, — много, а не ноль или один.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать VPSУстановка и первый запуск: минимальный рабочий стенд
Если решение принято осознанно, разворачивается Verdaccio быстро. Самый простой путь — Docker:
docker run -d --name verdaccio \
-p 4873:4873 \
-v /opt/verdaccio/storage:/verdaccio/storage \
-v /opt/verdaccio/conf:/verdaccio/conf \
-v /opt/verdaccio/plugins:/verdaccio/plugins \
verdaccio/verdaccio
Для продакшена нагляднее держать конфигурацию в docker-compose.yml, чтобы volume-мапинги и рестарт-политика не терялись при пересоздании контейнера:
services:
verdaccio:
image: verdaccio/verdaccio
restart: unless-stopped
ports:
- "4873:4873"
volumes:
- ./storage:/verdaccio/storage
- ./conf:/verdaccio/conf
По умолчанию Verdaccio слушает на 4873 без TLS — для рабочего использования порт нужно спрятать за reverse-proxy (nginx или Caddy) с HTTPS, иначе логины и токены пойдут открытым текстом. Базовая nginx-связка выглядит так же, как для любого другого upstream-сервиса:
location / {
proxy_pass http://127.0.0.1:4873/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
Первый пользователь создаётся прямо через npm-клиент — отдельной админ-панели с формой регистрации в Verdaccio нет, всё идёт через стандартный npm-протокол:
npm adduser --registry http://localhost:4873
Дальше htpasswd-файл с хэшами паролей пользователей лежит в volume и его стоит включить в бэкап наравне со storage — потеря этого файла означает, что все локальные пользователи теряют доступ на публикацию (проксированные публичные пакеты продолжат работать, потому что тянутся из uplink, а вот собственные приватные пакеты в storage без бэкапа теряются безвозвратно).
Публикация приватных пакетов и настройка .npmrc
Чтобы npm install и npm publish для вашего скоупа шли через Verdaccio, а всё остальное — как обычно, в .npmrc проекта (или глобальном ~/.npmrc) достаточно одной строки со скоупом, а не полной подмены реестра:
@myorg:registry=http://localhost:4873/
//localhost:4873/:_authToken=${VERDACCIO_TOKEN}
Это важная деталь: не нужно переопределять registry= глобально на весь npm — тогда все публичные пакеты тоже пойдут через ваш инстанс, и любой его простой останавливает вообще все установки, включая совершенно посторонние публичные зависимости. Скоуп-запись ограничивает область действия Verdaccio только вашими внутренними пакетами, а публичные продолжают идти напрямую в npmjs.org, если вы не настраивали uplink-проксирование намеренно.
Публикация пакета — обычный npm publish, только с указанием реестра, если он не прописан в package.json:
npm publish --registry http://localhost:4873
Для CI-раннера токен публикации передаётся переменной окружения, а не хранится в репозитории:
# .gitlab-ci.yml, фрагмент job
publish:
script:
- echo "//verdaccio.internal:4873/:_authToken=${VERDACCIO_TOKEN}" > .npmrc
- npm publish
variables:
VERDACCIO_TOKEN: $CI_VERDACCIO_TOKEN
Если внутренних пакетов десятки и версии меняются часто, отдельного внимания стоит semver-дисциплина: без строгого следования major.minor.patch и без npm version в релизном скрипте приватный реестр быстро зарастает несовместимыми breaking-изменениями под одним и тем же minor — та же проблема, что и с публичными пакетами, просто теперь ответственность полностью на вас.
Где Verdaccio — решение проблемы, которой у вас нет
А теперь — обещанная в заголовке честность. Возьмём типичный случай: команда из трёх человек, один монолитный репозиторий, никаких внутренних библиотек, которые нужно было бы переиспользовать между разными сервисами. У кого-то в такой команде мелькает мысль «а давайте поднимем Verdaccio, будет солиднее и надёжнее». Разберём, что на самом деле происходит, если это сделать.
Появляется сервис, у которого нет собственной пользы для вашего кейса. Если весь код лежит в одном репозитории и никакие пакеты никуда не публикуются, Verdaccio физически нечего проксировать сверх того, что и так тянется напрямую из npmjs.org. Приватных пакетов нет — значит, единственная функция, которая реально используется, — кэширующий прокси. А кэш публичных пакетов в CI для одного репозитория гораздо проще и надёжнее закрывается штатным кэшированием ~/.npm или node_modules средствами самого CI (cache: в GitLab CI, actions/cache в GitHub Actions) — без отдельного долгоживущего сервиса.
CI/CD получает новую точку отказа, которой раньше не было. До Verdaccio сборка зависела от одного внешнего фактора — доступности npmjs.org, у которого объективно выше SLA и больше инженеров, поддерживающих аптайм, чем у VPS, который команда из трёх человек настроила один раз и забыла. После добавления Verdaccio сборка зависит от двух вещей: от npmjs.org (потому что Verdaccio сам проксирует его же) и от того, что ваш собственный сервер жив, не кончилось место на диске под storage, не истёк сертификат на reverse-proxy и никто не забыл продлить его вручную. Вы не убрали зависимость — вы добавили ещё одну, последовательно, а не параллельно.
Кто-то должен его обслуживать, а этого «кого-то» в команде из трёх человек обычно нет. Обновления образа, бэкап storage и htpasswd, мониторинг диска, разбор, почему вдруг npm install в CI зависает на таймауте — всё это конкретные регулярные задачи, которые ложатся на и без того плотный график небольшой команды. Для сравнения: приватный Docker Registry на VPS тоже требует обслуживания, но там обычно есть чёткая причина — образы приватные по определению и хранить их в публичном Docker Hub часто прямо нельзя по контракту или лицензии. У npm-пакетов внутри одного монолитного репозитория такой причины нет: делиться там просто нечем.
Аргумент «на будущее, когда мы вырастем» тоже не работает так, как кажется. Поднять Verdaccio, когда реально появится вторая внутренняя библиотека, — вопрос часа работы, а не недели миграции. Ждущий сервис не экономит время в будущем, он тратит время уже сейчас: на настройку, на изучение конфигурации, на объяснение новым разработчикам, почему .npmrc в проекте выглядит нестандартно. Разница между «поставить заранее» и «поставить когда понадобится» здесь не в сложности внедрения, а в том, что во втором случае вы платите инфраструктурную цену только тогда, когда есть что этой инфраструктурой закрывать.
Что сделать вместо Verdaccio, если команда маленькая
Если после честной ревизии выяснилось, что приватных переиспользуемых пакетов нет и не предвидится, а мотивация была в основном «на случай, если npmjs упадёт», разумные альтернативы дешевле по совокупной стоимости владения.
Кэш зависимостей на уровне CI, без отдельного сервиса — самое дешёвое решение проблемы «сборка тормозит на установке пакетов»:
# GitLab CI
cache:
key:
files:
- package-lock.json
paths:
- .npm/
policy: pull-push
npm/pnpm/yarn workspaces для случая, когда код всё-таки хочется разбить на модули, но они используются только внутри одного монорепозитория и никогда не публикуются наружу. Workspaces дают локальные симлинки между пакетами без единой публикации в какой-либо реестр:
{
"name": "monorepo-root",
"workspaces": ["packages/*"]
}
Внутренний пакет packages/logger подключается в packages/api/package.json как обычная зависимость ("@myorg/logger": "workspace:*" для pnpm/yarn или просто версия для npm workspaces) — и никакого реестра для этого не требуется вообще.
Managed-реестр вместо self-hosted, если приватные пакеты всё же появились, но команда не хочет отвечать за инфраструктуру сама — GitHub Packages или GitLab Package Registry дают приватный npm-реестр как часть уже используемого git-хостинга, без отдельного сервера, бэкапов и обновлений образа. Это компромисс: меньше контроля и гибкости конфигурации, чем у собственного Verdaccio или Nexus, зато обслуживание сервиса не на вас. Если позже понадобится расширить прокси-кэш сразу на несколько экосистем — npm, PyPI, Maven — и появится причина держать его именно на своей инфраструктуре, стоит сравнить это с более тяжёлым, но и более функциональным вариантом — собственным Nexus для npm, PyPI и Maven, рассчитанным как раз на нагрузку и риски уровня бизнеса, а не одного небольшого проекта.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать VPSНужны сами нейросети для контента?
Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.
Частые вопросы
Чем Verdaccio отличается от Nexus и Artifactory?
Verdaccio — специализированный лёгкий инструмент только под npm-совместимые реестры (npm, yarn, pnpm), поднимается за минуты и не требует Java или отдельной базы данных. Nexus и Artifactory — универсальные менеджеры артефактов под npm, Maven, PyPI, Docker-образы и другие форматы одновременно, тяжелее в установке и администрировании, но нужны, когда реестров под разные экосистемы несколько и хочется свести их в одну точку.
Можно ли использовать Verdaccio только как кэширующий прокси, без публикации своих пакетов?
Да, это штатный сценарий — секция uplinks в config.yaml настраивается независимо от возможности публикации, можно оставить publish закрытым для всех и использовать реестр исключительно как кэш перед npmjs.org. Но для одного небольшого проекта эту же задачу обычно закрывает штатное кэширование зависимостей на уровне CI без отдельного сервиса.
Что будет, если Verdaccio-сервер ляжет во время сборки на CI?
Если в .npmrc для приватного скоупа указан только Verdaccio без резервного uplink, установка приватных пакетов упадёт с ошибкой соединения — публичные пакеты, если реестр не переопределён глобально, продолжат ставиться напрямую из npmjs.org. Поэтому reverse-proxy с TLS, регулярный бэкап storage/htpasswd и базовый мониторинг доступности — не опциональные детали, а обязательная часть внедрения, если вы решились на self-hosted реестр.
Нужен ли Verdaccio, если у нас монорепозиторий, но пакеты не публикуются наружу?
Обычно нет — для этого случая созданы workspaces (npm, pnpm, yarn), которые дают переиспользование модулей внутри одного репозитория без публикации в какой-либо реестр вообще, приватный или публичный.
Как перейти с Verdaccio на управляемый реестр (GitHub Packages, GitLab), если решили не поддерживать инфраструктуру самим?
Технически — переопубликовать текущие версии пакетов в новый реестр (npm publish с указанием нового registry в .npmrc) и обновить ссылку на реестр в .npmrc всех потребляющих проектов и CI-переменных. Историю версий из Verdaccio автоматически перенести некуда — если она важна, стоит заранее выгрузить список тегов и changelog вручную.
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →