Setting Up Verdaccio as a Private Proxy Registry
You want internal packages hosted privately while public dependencies still resolve, without paying for a hosted registry. This page shows how to run Verdaccio as a private, caching proxy and point your workspace at it safely.
Exact symptoms and error messages
Before Verdaccio, internal packages have nowhere private to live, so teams resort to git URLs or publishing proprietary code publicly:
npm error 402 Payment Required - publishing a private package requires a paid plan
You need a host you control that serves your scope and proxies everything else.
Root cause analysis
A proxy registry sits between your clients and the public registry: it serves packages it hosts, and for anything it does not, it fetches from upstream and caches the tarball. That single host can therefore satisfy both @acme/* and public dependencies, with integrity still verified against your lockfile.
A proxy registry works because npm's protocol is uniform: whether a package is yours or public, the client asks the configured registry for a manifest and a tarball. Verdaccio answers for packages it hosts and, for anything it does not, fetches from an upstream and caches the result. That single indirection is what lets one host serve both @acme/* and the entire public dependency graph, with integrity still verified against your lockfile.
The caching behavior also hardens your builds against upstream outages and package removals. Once Verdaccio has cached a public tarball, installs that need it succeed even if the public registry is unreachable or the version is later unpublished — a meaningful availability benefit for teams whose CI would otherwise fail on an upstream hiccup.
Resolution and configuration patch
Run Verdaccio and configure an uplink to the public registry plus access rules for your scope:
# config.yaml
uplinks:
npmjs:
url: https://registry.npmjs.org/
packages:
'@acme/*':
access: $authenticated
publish: $authenticated
proxy: npmjs
'**':
access: $all
proxy: npmjs
docker run -d -p 4873:4873 -v $PWD/config.yaml:/verdaccio/conf/config.yaml verdaccio/verdaccio
Lock down who can publish before you expose the registry to anyone. Verdaccio ships with open registration by default, which is fine locally but dangerous shared:
auth:
htpasswd:
file: ./htpasswd
max_users: -1 # -1 disables self-registration; add users manually
packages:
'@acme/*':
access: $authenticated
publish: $authenticated
unpublish: $authenticated
With max_users: -1, new accounts are created deliberately rather than by anyone who finds the URL, and requiring $authenticated for publish keeps the private scope from being overwritten by an anonymous client.
CLI validation and debug commands
# Point only your scope at Verdaccio
npm config set @acme:registry http://localhost:4873
# Create a user and publish a scoped package
npm adduser --registry http://localhost:4873
npm publish --registry http://localhost:4873
# Confirm a public dep proxies through and caches
npm install lodash --registry http://localhost:4873
Prevention and CI guardrails
- Require authentication for both
accessandpublishon your private scope. - Restrict who can publish with Verdaccio's htpasswd or an auth plugin, not open registration.
- Keep uplink proxying so public dependencies resolve and cache through one host.
- Back up the Verdaccio storage volume — it holds the only copy of your private tarballs.
Hardening Verdaccio for shared use
A Verdaccio instance that is safe on localhost is not automatically safe as a team registry. Three things change when you share it: it needs TLS so tokens are not sent in the clear, it needs authentication that is not open self-registration, and it needs its storage volume backed up because it now holds the only copy of your private tarballs.
Put it behind a reverse proxy that terminates HTTPS, disable anonymous publish on your private scope, and treat the storage directory as production data with a backup schedule. A common mistake is running the container with an ephemeral volume — a restart then wipes every private package you published. The mental model is that a shared Verdaccio is infrastructure, not a dev convenience: it earns the same TLS, auth, and backup rigor you would give any service that holds code you cannot re-download from anywhere else.
Verdaccio versus a hosted registry
Self-hosting buys control and costs operations. Verdaccio gives you full control over storage, auth, and the resolution path, and it proxies the public registry so one host serves everything — but you own its uptime, TLS, backups, and upgrades. A hosted option (GitHub Packages, an npm org, a cloud artifact registry) removes that operational burden at the cost of some control and, sometimes, money.
The decision usually comes down to team size and requirements. A team that needs an air-gapped or strictly-controlled resolution path, or that wants to cache the public registry for availability, is well served by Verdaccio despite the ops overhead. A team that just needs private scoped packages with minimal fuss is usually better off on a hosted registry. The access-control model — scoped tokens, restricted access, provenance — applies either way; only who runs the server changes.
Frequently Asked Questions
Does Verdaccio replace the public npm registry?
No — it proxies it. Verdaccio serves your private packages and forwards requests for public packages upstream, caching the results, so one host covers both.
Is Verdaccio safe to expose to the internet?
Only behind authentication and TLS. Restrict publish to authenticated users, put it behind a reverse proxy with HTTPS, and never allow anonymous publish on your private scope.
Is Verdaccio safe to expose beyond localhost?
Only with TLS, real authentication, and disabled self-registration. Put it behind an HTTPS reverse proxy, create users deliberately, and require authentication to publish on your private scope before any shared use.
What happens to my private packages if Verdaccio restarts?
They live in its storage volume. If that volume is ephemeral, a restart wipes them — Verdaccio holds the only copy of private tarballs. Use a persistent, backed-up volume and treat it as production data.
Verdaccio or a hosted registry — how do I choose?
Choose Verdaccio for full control, an air-gapped resolution path, or public-registry caching, accepting the ops burden. Choose a hosted registry when you just need private scoped packages with minimal maintenance.
Related
- Private Registries and Access Control — the overview for private distribution and access control.