This guide covers how to:
- Set up a private NPM registry using Verdaccio and Docker
- Log in to your private NPM registry
- Publish a package
- Download a package
- Grant download access to specific users
- Restrict anonymous registrations and manually manage users
- Point scoped packages to your private NPM registry
1. Setting Up Verdaccio with Docker
Project Structure
Create a directory named private-npm-registry or a name you prefer:
private-npm-registry/
conf/
config.yaml
storage/
docker-compose.yml
config.yaml: Verdaccio configuration filestorage/: Holds published packagesdocker-compose.yml: Docker configuration used to launch Verdaccio
Configuring Verdaccio
Create conf/config.yaml with the following:
storage: /verdaccio/storage
auth:
htpasswd:
file: ./htpasswd
algorithm: bcrypt
packages:
"@my-scope/*":
access: $all
publish: $authenticated
log:
type: stdout
format: pretty
level: http
Notes:
$allallows anyone to download packages.$authenticatedallows only logged-in users to publish.- The registry hosts only packages under the
@my-scope/*namespace unless you change the rule.
Caution: Verdaccio requires
config.yaml, notconfig.yml. See the Verdaccio configuration docs for more options.
Docker Compose Configuration
Create docker-compose.yml:
version: "3.8"
services:
verdaccio:
image: verdaccio/verdaccio:latest
ports:
- 4873:4873
volumes:
- ./conf:/verdaccio/conf
- ./storage:/verdaccio/storage
This setup:
- Uses the latest Verdaccio Docker image
- Exposes port
4873 - Persists data using mounted volumes
Starting Your Registry
From the project root:
docker compose up
Your private NPM registry will be available at http://localhost:4873.
2. Logging In
Log in to your registry:
npm login --registry http://localhost:4873
- You will be prompted for a username and password.
- The first login automatically registers a new account.
- Credentials are stored in your
~/.npmrcfile.
Helpful commands:
npm whoami --registry http://localhost:4873
npm logout --registry http://localhost:4873
3. Publishing a Package
To test publishing, create a sample package.
- Create and enter a folder.
mkdir hello-world && cd hello-world
- Initialize the project.
npm init
Name the package @my-scope/hello-world.
- Add an
index.jsfile.
module.exports = function () {
console.log("Hello World! From @my-scope/hello-world");
};
- Publish your package.
npm publish --registry http://localhost:4873
4. Downloading a Package
Install from your registry:
npm install @my-scope/hello-world --registry http://localhost:4873
By default, $all users can download this package. To restrict access, update the configuration as shown below.
5. Granting Access to Specific Users
Update conf/config.yaml with a package-specific rule:
packages:
"@my-scope/private-*":
access: admin user-a user-b
publish: admin
admincan publish and download.user-aanduser-bcan download only.- Others have no access.
Built-in groups:
| Group | Description |
|---|---|
$all | Anyone, including anonymous users |
$authenticated | Logged-in users only |
Verdaccio does not support custom groups. Users must be listed explicitly. See this Stack Overflow reference for more detail.
6. Restricting Anonymous Registrations
To disable public signups and manage accounts manually, update the auth section of config.yaml:
auth:
htpasswd:
file: ./htpasswd
algorithm: bcrypt
max_users: -1
Then manually create users by generating encrypted credentials with a tool such as the HTPasswd Generator, and copy the generated output into conf/htpasswd.
7. Scoped Packages Configuration
To make the NPM client automatically use your registry for scoped packages, add this to your ~/.npmrc:
@my-scope:registry = http://localhost:4873
That lets you run:
npm install @my-scope/hello-world
without passing --registry each time.
8. Next Steps
Future improvements may include:
- Running the registry behind a reverse proxy
- Using HTTPS with a domain such as
https://npm-registry.my-company.com