Every CI run that does a fresh npm install or pip install is a round trip to a public registry you don't control. Rate limits, upstream outages, and per-seat pricing on hosted private registries all add friction that a self-hosted npm registry VPS quietly removes. This is our setup guide for running Verdaccio and devpi on a single VPS as a package mirror and private registry — cached public dependencies plus internally-published packages, no seat fees, no third-party dependency in your build path.
Why a Self-Hosted Package Mirror Pays Off
Two separate problems get solved by the same box. First, caching: a local mirror stores every package your builds have ever pulled, so the tenth CI run this week fetches from your VPS over your own network instead of crossing the public internet to registry.npmjs.org or pypi.org every single time. Second, private hosting: internal packages — shared component libraries, internal Python tooling, proprietary SDKs — need somewhere to live that isn't a public registry, and hosted private-registry SaaS products charge per seat or per package for exactly this.
Running both on your own VPS collapses those two needs into one process per language: Verdaccio in front of npm, devpi in front of PyPI. Neither is resource-hungry, and both proxy an upstream registry transparently, so nothing in your existing package.json or requirements.txt has to change beyond the registry URL.
Setting Up a Self-Hosted npm Registry VPS with Verdaccio
Verdaccio is a lightweight Node-based registry that proxies npm and caches what it fetches. On a fresh VPS with root access, the install is a handful of steps:
- Install Node.js/Bun and then Verdaccio globally, or run it under a process manager of your choice.
- Edit
config.yamlto define anuplinksentry pointing athttps://registry.npmjs.org, and a package rule (**) that proxies anything not published locally. - Set a persistent storage path outside the app directory so cached tarballs survive redeploys.
- Run Verdaccio under systemd so it restarts on crash or reboot.
- Put nginx in front of it as a reverse proxy on port 443 with a Let's Encrypt certificate, then point developer machines and CI runners at it with
npm config set registry https://your-mirror.example.com.
Publishing an internal package is just npm publish --registry https://your-mirror.example.com. Everything else resolves through the uplink automatically the first time it's requested, then serves from local disk on every request after.
devpi Setup for a Private PyPI Mirror
devpi is the equivalent tool on the Python side, and it's a common search for "private pypi mirror hosting" for good reason — pip has no built-in caching layer, so every clean virtualenv build re-downloads the same wheels unless something sits in between. A minimal devpi install looks like this:
- Install
devpi-serveranddevpi-web(for the browsable UI) via pip. - Initialize the server state with
devpi-server --init, then start it bound to localhost. - devpi's index model lets you create an internal index that inherits from the root
pypiindex — packages not found locally fall through to the real PyPI automatically, exactly like Verdaccio's uplink. - Reverse-proxy it through nginx the same way as Verdaccio, then point pip at it with a
pip.confentry pointing to your index URL.
Internal-only Python packages get uploaded to a separate devpi index that does not inherit from PyPI, keeping private code from ever mixing with public package resolution.
Sizing the VPS for a Package Mirror
A package mirror is disk-and-bandwidth bound, not CPU bound — the workload is mostly serving static tarballs and wheels from local storage. Local SSD storage keeps read latency low under concurrent CI jobs, and unmetered symmetric bandwidth (100–300 Mbps by plan) means a fleet of parallel build agents pulling from the mirror never runs into a transfer quota the way a metered plan would.
| Tier | Specs | Fits |
|---|---|---|
| VPS I | 2GB / 1vCPU / 20GB SSD | Small team, one or two languages, light cache |
| VPS II | 4GB / 2vCPU / 40GB SSD | Most Verdaccio + devpi setups running side by side |
| VPS III | 8GB / 2vCPU / 60GB SSD | Larger dependency trees, many concurrent CI runners |
Root SSH access on every tier means both registries install exactly as they would on any Linux box. Because billing is hourly, a mirror that only needs to be up during active build windows can be scripted to be created before the pipeline runs (restoring its cache from a backup) and deleted after, so you're not paying for idle hours on a box that only earns its keep a few hours a day.
Securing and Automating the Mirror
A few operational notes worth building in from day one, since we treat this like any other production service on the rack:
- TLS everywhere — terminate at nginx, never expose Verdaccio or devpi's default HTTP port directly to CI runners over the public internet.
- Auth on publish — both tools support htpasswd-style or token auth for publish operations; keep read access open to your CI network but lock down who can push packages.
- Storage growth — cached tarballs accumulate; a simple cron that prunes packages untouched for N days keeps disk usage bounded.
- DDoS exposure — a mirror reachable from CI runners across multiple networks is still a public-facing service; the 100 Gbps DDoS protection included on every product means a Layer 3/4 flood against it is mitigated rather than taking your build pipeline down with it.
CI/CD Integration
The whole point of the mirror is faster, more reliable builds, so wiring it into CI is where the payoff shows up. Most CI runners just need the registry URL and, for private packages, a token in an environment variable or secrets store — no plugin, no special runner image. If your CI runners live on the same network as the mirror, latency drops further since traffic never leaves your own infrastructure. Larger CI fleets that want the mirror reachable across their own announced IP space rather than shared infrastructure can look at our BGP and BYOIP options on dedicated servers.
How Noded Can Help
We run our own network on AS60982, so a package mirror hosted with us sits directly on that network rather than behind a reseller. Our VPS tiers give you root access to install Verdaccio and devpi as described above, SSD storage for fast cache reads, and unmetered bandwidth so concurrent CI pulls never hit a transfer quota. Billing by the hour means a mirror that only exists during build windows costs you only for those hours. If your dependency trees or team size outgrow a single VPS, our dedicated servers give you a full box to scale storage and throughput further. We don't manage the registry software for you — this is a self-hosted setup — but the box underneath it is ours to keep fast and available.
FAQ
Is Verdaccio a full replacement for npm's public registry?
No — Verdaccio proxies and caches the public registry rather than replacing it. Public packages still resolve through your configured uplink the first time they're requested; only internally published packages live exclusively on your mirror.
Can I run both Verdaccio and devpi on the same VPS?
Yes. Both are lightweight processes that mostly wait on disk I/O and network requests, so running them side by side on a single VPS with separate ports behind one nginx reverse proxy is a common and reasonable setup for small-to-mid-size teams.
Do I need to keep the mirror VPS running all the time?
Not necessarily. If the mirror is only used during scheduled CI windows, you can script it to be created before a build (restoring its cache from a backup) and deleted after, since hourly billing means you're only charged for the hours it exists.
How is this different from a hosted private registry SaaS?
A hosted SaaS registry charges per seat or per package and runs on infrastructure you don't control. A self-hosted npm registry VPS running Verdaccio or devpi gives you the same caching and private-hosting functionality on a server you fully control (full root on a KVM VPS), with no per-user pricing.
What happens if the mirror goes down during a build?
Depends on your CI configuration — if the registry URL is only set for the private index and public packages fall back to the real registry, builds can degrade gracefully. If your CI points exclusively at the mirror, treat it like any other single point of failure and plan backups or a standby instance accordingly.