Verdaccio Private npm Registry Installation
Verdaccio is a lightweight private npm registry that proxies the public npm registry and caches packages locally, cutting download times and enabling offline workflows. This guide covers installing Verdaccio on Linux, configuring authentication and access control, publishing packages, Docker deployment, and CI/CD integration.
Prerequisites
- Ubuntu 20.04+/Debian 11+ or CentOS 8+/Rocky Linux 8+
- Node.js 18+ and npm installed
sudoor root access- Domain name (optional but recommended for production)
# Install Node.js 18 if needed
curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash -
sudo apt install -y nodejs
node --version
Installing Verdaccio
# Install Verdaccio globally
sudo npm install -g verdaccio
# Verify installation
verdaccio --version
# Run once to generate default config
verdaccio &
sleep 3
kill %1
ls ~/.config/verdaccio/
For a system-wide installation with a dedicated user:
sudo useradd -r -m -d /opt/verdaccio -s /bin/bash verdaccio
sudo -u verdaccio npm install -g verdaccio
Configuration
The main config file is at ~/.config/verdaccio/config.yaml:
cat > ~/.config/verdaccio/config.yaml << 'EOF'
# Storage path for cached/published packages
storage: /opt/verdaccio/storage
plugins: /opt/verdaccio/plugins
web:
title: My Private Registry
# logo: /path/to/logo.png
auth:
htpasswd:
file: /opt/verdaccio/htpasswd
max_users: 50 # -1 to disable new user registration
uplinks:
npmjs:
url: https://registry.npmjs.org/
timeout: 30s
max_fails: 5
fail_timeout: 5m
packages:
# Private packages (@mycompany scope)
'@mycompany/*':
access: $authenticated
publish: $authenticated
unpublish: $authenticated
# All other packages proxy to npm
'**':
access: $all
publish: $authenticated
unpublish: $authenticated
proxy: npmjs
server:
keepAliveTimeout: 60
middlewares:
audit:
enabled: true
logs:
- {type: stdout, format: pretty, level: http}
listen:
- 0.0.0.0:4873
EOF
sudo mkdir -p /opt/verdaccio/{storage,plugins}
sudo chown -R verdaccio:verdaccio /opt/verdaccio
Running as a Systemd Service
sudo tee /etc/systemd/system/verdaccio.service << 'EOF'
[Unit]
Description=Verdaccio Private npm Registry
After=network.target
[Service]
Type=simple
User=verdaccio
Environment=NODE_ENV=production
ExecStart=/usr/bin/verdaccio --config /opt/verdaccio/config.yaml --listen 0.0.0.0:4873
Restart=on-failure
RestartSec=10
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable --now verdaccio
sudo systemctl status verdaccio
journalctl -u verdaccio -f
Publishing and Using Packages
Add a user to the registry:
npm adduser --registry http://localhost:4873
# Enter username, password, and email when prompted
Configure your project to use the private registry:
# Option 1: Set registry per-project in .npmrc
echo "registry=https://registry.yourdomain.com" > .npmrc
# Option 2: Set for a specific scope only
echo "@mycompany:registry=https://registry.yourdomain.com" >> ~/.npmrc
# Option 3: Set globally
npm config set registry https://registry.yourdomain.com
Publish a package:
# In your package directory
npm publish --registry https://registry.yourdomain.com
# Install from your private registry
npm install @mycompany/my-package
Authentication and Access Control
Add users via the CLI (htpasswd-based auth):
# The first login via npm adduser creates the htpasswd file
# Or create it manually
sudo apt install -y apache2-utils
htpasswd -B /opt/verdaccio/htpasswd alice
htpasswd -B /opt/verdaccio/htpasswd bob
Advanced access control with scopes:
# In config.yaml
packages:
'@internal/*':
access: $authenticated
publish: alice bob # Only alice and bob can publish
unpublish: alice
'@public/*':
access: $all # Public read access
publish: $authenticated
'**':
access: $all
proxy: npmjs
Docker Deployment
mkdir -p /opt/verdaccio/{conf,storage,plugins}
chmod -R 777 /opt/verdaccio # Verdaccio runs as uid 10001 in Docker
cat > /opt/verdaccio/docker-compose.yml << 'EOF'
version: '3.8'
services:
verdaccio:
image: verdaccio/verdaccio:latest
container_name: verdaccio
ports:
- "127.0.0.1:4873:4873"
volumes:
- ./conf:/verdaccio/conf
- ./storage:/verdaccio/storage
- ./plugins:/verdaccio/plugins
environment:
- VERDACCIO_PORT=4873
restart: unless-stopped
EOF
# Copy config to the right place
cp ~/.config/verdaccio/config.yaml /opt/verdaccio/conf/config.yaml
docker compose up -d
docker compose logs -f verdaccio
Nginx Reverse Proxy
server {
listen 443 ssl;
server_name registry.yourdomain.com;
ssl_certificate /etc/letsencrypt/live/registry.yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/registry.yourdomain.com/privkey.pem;
# Allow large package uploads
client_max_body_size 100m;
location / {
proxy_pass http://127.0.0.1:4873/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-NginX-Proxy true;
}
}
sudo certbot --nginx -d registry.yourdomain.com
sudo nginx -t && sudo systemctl reload nginx
CI/CD Integration
GitHub Actions / Woodpecker CI example:
# .github/workflows/publish.yml
steps:
- uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: 18
registry-url: https://registry.yourdomain.com
- name: Install dependencies
run: npm ci
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
- name: Publish
run: npm publish
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
Generate a CI token (Bearer auth):
# Login and get the token from ~/.npmrc after login
npm login --registry https://registry.yourdomain.com
grep "//registry.yourdomain.com" ~/.npmrc
# Output: //registry.yourdomain.com/:_authToken=your_token_here
Troubleshooting
Package not found / falls through to npm incorrectly:
# Verify uplink is configured
# Check storage directory permissions
ls -la /opt/verdaccio/storage/
# Test uplink connectivity
curl https://registry.npmjs.org/lodash
Authentication fails:
# Check htpasswd file exists and is readable
ls -la /opt/verdaccio/htpasswd
# Re-generate token
npm logout --registry https://registry.yourdomain.com
npm login --registry https://registry.yourdomain.com
Large packages failing to upload:
Increase client_max_body_size in Nginx (see above) and check disk space on the storage volume.
Service won't start:
journalctl -u verdaccio -n 50
# Common cause: port already in use or config syntax error
verdaccio --config /opt/verdaccio/config.yaml # run manually to see errors
Conclusion
Verdaccio delivers a simple yet powerful private npm registry that reduces external network dependency and enables scoped package management for your organization. Its proxy and caching capabilities mean your CI/CD pipelines stay fast even during npm outages. For team use, pair it with Nginx SSL and htpasswd authentication for a production-ready setup.


