How to setup production level private NPM Registry using Verdaccio
This article helps you in understanding how verdaccio works and how you can make the most of it. This will help you the most if you also publish your own packages.
Registry
By default if you are downloading packages using npm, you’re using https://registry.npmjs.org/
which is the default registry where the packages that you see on npm
are published.
Now here comes verdaccio, it will act as a proxy server for you. Let’s say you want to publish your own packages, but only for your internal company wide use, you can use verdaccio instead of publishing them on npm.
These packages remain only on your server. The server also proxies calls over to npm’s server. If you want to download a public package, you will set registry to your own server and it will keep uplinks to npm’s registry as these packages won’t be available on your private verdaccio registry.
Understanding Verdaccio
A lightweight Node.js private proxy registry
This is how verdaccio describes itself. A private proxy as we learned above.
Verdaccio is a nodejs package in itself. You can create your own registry server just like npm using it and customise it for your own usage.
Installation
npm install verdaccio -g
# yarn
yarn global add verdaccio
Verify your installation using:
verdaccio -v
You are required to install verdaccio globally as it’s expected to be run as standalone server. In case you don’t prefer this method you can also use it through docker.
Starting server
Now all we need to do is run the command:
verdaccio
This will start the server by default on port 4873
.
You will see a log similar to this:
verdaccio ─╯
info --- config file - /Users/sameer/.config/verdaccio/config.yaml
info --- the "crypt" algorithm is deprecated consider switch to "bcrypt" in the configuration file. Read the documentation for additional details
info --- using htpasswd file: /Users/sameer/.config/verdaccio/htpasswd
info --- plugin successfully loaded: verdaccio-htpasswd
info --- plugin successfully loaded: verdaccio-audit
warn --- http address - <http://localhost:4873/> - verdaccio/5.27.0
This log is very helpful to understand what all files are used while running a bare minimum verdaccio server.
Architecture
You mainly are required to just edit the config.yaml
file. Which from the above example log you can see is loaded once you start the verdaccio server. It is located in a path like: /Users/{username}/.config/verdaccio/config.yaml
Open up the config file and let’s see what all we can do with it!
config.yaml
In this file you define all the configuration setup you want to configure.
# This is the default configuration file. It allows all users to do anything,
# please read carefully the documentation and best practices to
# improve security.
#
# Look here for more config file examples:
# <https://github.com/verdaccio/verdaccio/tree/5.x/conf>
#
# Read about the best practices
# <https://verdaccio.org/docs/best>
# path to a directory with all packages
storage: ./storage
# path to a directory with plugins to include
plugins: ./plugins
# <https://verdaccio.org/docs/webui>
web:
title: Verdaccio
# comment out to disable gravatar support
# gravatar: false
# by default packages are ordercer ascendant (asc|desc)
# sort_packages: asc
# convert your UI to the dark side
# darkMode: true
# html_cache: true
# by default all features are displayed
# login: true
# showInfo: true
# showSettings: true
# In combination with darkMode you can force specific theme
# showThemeSwitch: true
# showFooter: true
# showSearch: true
# showRaw: true
# showDownloadTarball: true
# HTML tags injected after manifest <scripts/>
# scriptsBodyAfter:
# - '<script type="text/javascript" src="<https://my.company.com/customJS.min.js>"></script>'
# HTML tags injected before ends </head>
# metaScripts:
# - '<script type="text/javascript" src="<https://code.jquery.com/jquery-3.5.1.slim.min.js>"></script>'
# - '<script type="text/javascript" src="<https://browser.sentry-cdn.com/5.15.5/bundle.min.js>"></script>'
# - '<meta name="robots" content="noindex" />'
# HTML tags injected first child at <body/>
# bodyBefore:
# - '<div id="myId">html before webpack scripts</div>'
# Public path for template manifest scripts (only manifest)
# publicPath: <http://somedomain.org/>
# <https://verdaccio.org/docs/configuration#authentication>
auth:
htpasswd:
file: ./htpasswd
# Maximum amount of users allowed to register, defaults to "+inf".
# You can set this to -1 to disable registration.
# max_users: 1000
# Hash algorithm, possible options are: "bcrypt", "md5", "sha1", "crypt".
# algorithm: bcrypt # by default is crypt, but is recommended use bcrypt for new installations
# Rounds number for "bcrypt", will be ignored for other algorithms.
# rounds: 10
# <https://verdaccio.org/docs/configuration#uplinks>
# a list of other known repositories we can talk to
uplinks:
npmjs:
url: <https://registry.npmjs.org/>
# Learn how to protect your packages
# <https://verdaccio.org/docs/protect-your-dependencies/>
# <https://verdaccio.org/docs/configuration#packages>
packages:
'@*/*':
# scoped packages
access: $all
publish: $authenticated
unpublish: $authenticated
proxy: npmjs
'**':
# allow all users (including non-authenticated users) to read and
# publish all packages
#
# you can specify usernames/groupnames (depending on your auth plugin)
# and three keywords: "$all", "$anonymous", "$authenticated"
access: $all
# allow all known users to publish/publish packages
# (anyone can register by default, remember?)
publish: $authenticated
unpublish: $authenticated
# if package is not available locally, proxy requests to 'npmjs' registry
proxy: npmjs
# To improve your security configuration and avoid dependency confusion
# consider removing the proxy property for private packages
# <https://verdaccio.org/docs/best#remove-proxy-to-increase-security-at-private-packages>
# <https://verdaccio.org/docs/configuration#server>
# You can specify HTTP/1.1 server keep alive timeout in seconds for incoming connections.
# A value of 0 makes the http server behave similarly to Node.js versions prior to 8.0.0, which did not have a keep-alive timeout.
# WORKAROUND: Through given configuration you can workaround following issue <https://github.com/verdaccio/verdaccio/issues/301>. Set to 0 in case 60 is not enough.
server:
keepAliveTimeout: 60
# Allow `req.ip` to resolve properly when Verdaccio is behind a proxy or load-balancer
# See: <https://expressjs.com/en/guide/behind-proxies.html>
# trustProxy: '127.0.0.1'
# <https://verdaccio.org/docs/configuration#offline-publish>
# publish:
# allow_offline: false
# <https://verdaccio.org/docs/configuration#url-prefix>
# url_prefix: /verdaccio/
# VERDACCIO_PUBLIC_URL='<https://somedomain.org>';
# url_prefix: '/my_prefix'
# // url -> <https://somedomain.org/my_prefix/>
# VERDACCIO_PUBLIC_URL='<https://somedomain.org>';
# url_prefix: '/'
# // url -> <https://somedomain.org/>
# VERDACCIO_PUBLIC_URL='<https://somedomain.org/first_prefix>';
# url_prefix: '/second_prefix'
# // url -> <https://somedomain.org/second_prefix/>'
# <https://verdaccio.org/docs/configuration#security>
# security:
# api:
# legacy: true
# jwt:
# sign:
# expiresIn: 29d
# verify:
# someProp: [value]
# web:
# sign:
# expiresIn: 1h # 1 hour by default
# verify:
# someProp: [value]
# <https://verdaccio.org/docs/configuration#user-rate-limit>
# userRateLimit:
# windowMs: 50000
# max: 1000
# <https://verdaccio.org/docs/configuration#max-body-size>
# max_body_size: 10mb
# <https://verdaccio.org/docs/configuration#listen-port>
# listen:
# - localhost:4873 # default value
# - <http://localhost:4873> # same thing
# - 0.0.0.0:4873 # listen on all addresses (INADDR_ANY)
# - <https://example.org:4873> # if you want to use https
# - "[::1]:4873" # ipv6
# - unix:/tmp/verdaccio.sock # unix socket
# The HTTPS configuration is useful if you do not consider use a HTTP Proxy
# <https://verdaccio.org/docs/configuration#https>
# https:
# key: ./path/verdaccio-key.pem
# cert: ./path/verdaccio-cert.pem
# ca: ./path/verdaccio-csr.pem
# <https://verdaccio.org/docs/configuration#proxy>
# http_proxy: <http://something.local/>
# https_proxy: <https://something.local/>
# <https://verdaccio.org/docs/configuration#notifications>
# notify:
# method: POST
# headers: [{ "Content-Type": "application/json" }]
# endpoint: <https://usagge.hipchat.com/v2/room/3729485/notification?auth_token=mySecretToken>
# content: '{"color":"green","message":"New package published: * {{ name }}*","notify":true,"message_format":"text"}'
middlewares:
audit:
enabled: true
# <https://verdaccio.org/docs/logger>
# log settings
log: { type: stdout, format: pretty, level: http }
#experiments:
# # support for npm token command
# token: false
# # disable writing body size to logs, read more on ticket 1912
# bytesin_off: false
# # enable tarball URL redirect for hosting tarball with a different server, the tarball_url_redirect can be a template string
# tarball_url_redirect: '<https://mycdn.com/verdaccio/${packageName}/${filename}>'
# # the tarball_url_redirect can be a function, takes packageName and filename and returns the url, when working with a js configuration file
# tarball_url_redirect(packageName, filename) {
# const signedUrl = // generate a signed url
# return signedUrl;
# }
# translate your registry, api i18n not available yet
# i18n:
# list of the available translations <https://github.com/verdaccio/verdaccio/blob/master/packages/plugins/ui-theme/src/i18n/ABOUT_TRANSLATIONS.md>
# web: en-US
Here I’ve pasted the entire default config file we get with verdaccio version 5.27.0
We will look into the most common configuration items in detail:
storage
This is the folder where all your packages are stored when you are using default configuration, that is storing all your packages on the machine itself.
If you are using a plugin such as verdaccio-aws-s3-storage. Your storage will be in your s3 bucket and this folder will not be used. In this case you can let the config item be as it is, i.e., storage: ./storage
as it won’t be used anyway.
Now with the latest versions, it is observed that using it as relative path: ./storage
, may cause issues. To resolve it, use absolute path instead. Find where verdaccio is installed globally and pick the storage path from there, ideally the path will be same as config file parent path.
What contents are in storage folder?
Storage folder consists of two main elements:
DB Json file: .verdaccio-db.json
Packages: all the packages are available at the root level of storage folder.
you published packages will contain this two files:
package.json test-publish-1.0.0.tgz
gzip compressed tar file of your code will be present.
plugins
default path is ./plugins
for your custom plugins. If you use third party plugins, the most common ones such as verdaccio-aws-s3-storage
provide you an option to configure it via config.yaml
itself.
web
Here you can specify configurations for your web interface of the registry. Specifying custom title url’s, name, dark mode and many such configurations can be done from here.
auth
Auth is where you specify login information required to access the registry. The recommended option is to use bcrypt
algorithm.
you can configure max number of user login info that the server should store for you.
the htpasswd file looks something like this:
sameer:3p8fkfpAWkCNQ:autocreated 2023-11-17T19:42:30.571Z
password hash used for above is via default crypt algo.
uplinks
uplinks section is what determines the where the server should make request if the package is not found in the storage folder. Generally you’ll link it to npm registry.
Once you download a specific package, say react
, the server will store info regarding it in the storage folder and cache it.
Next time for downloads for any user, it’ll be served from the storage itself. Which will contain uplink of tgz file.
packages
here you specify the info regarding your own private packages and and specify who can publish and unpublish.
For your private packages you can remove the proxy configuration as they will be served from the verdaccio server itself.
server
keepAliveTimeout
this is part of http1 spec, you can modify it. Generally it works with default configuration.
VERDACCIO_PUBLIC_URL
This is a very important configuration setup, when you deploy your server to some domain, you need to specify the domain: https://mydomainname.com
here.
and also set url_prefix
to /
by default. If you serve from a nested path then specify that instead.
security
# security:
# api:
# legacy: true
# jwt:
# sign:
# expiresIn: 29d
# verify:
# someProp: [value]
# web:
# sign:
# expiresIn: 1h # 1 hour by default
# verify:
# someProp: [value]
you can uncomment it in the yaml file and configure it. Default configurations work pretty well.
You can also specify notBefore
for sign options. An production level config may look like this:
security:
legacy: true
api:
jwt:
sign:
expiresIn: 10d
notBefore: 0
web:
sign:
expiresIn: 10d
notBefore: 0
rate limiting
npm install
is not rate limited. Other calls such as user based calls npm login
, npm addUser
, … and so are rate limited by default to 100 request peer 15 minutes. And if you browse on the web interface it has rate limit of 5000 requests peer 2 minutes.
you can configure it, but ideally the most important use case will be of installs as the server will be getting used in multiple environments of your build setup. Since it is not rate limited, hardly you’ll have to modify it.
The above information on contents of config.yaml
file has covered other parts of verdaccio server architecture that you need to be aware of: auth => htpasswd
, storage
etc.
Setting up a production grade verdaccio server
Let’s say you start from clean slate on an ec2 machine, you’ll need a decent enough disk storage to as your storage folder can become very big. On safe scale you can start the free tier of 30gb.
Next is installing nodejs on the server, verdaccio needs v12 at least to operate on the latest version.
Then you need to install verdaccio
globally. After you’re done with it, you can check by running verdaccio
command to check if your server is working as expected.
Then proceed with changes with the config.yaml
which is the most important part of the registry setup.
Private packages config
packages:
'@mycompany/*':
access: $all
publish: $authenticated
unpublish: $authenticated
'@*/*':
# scoped packages
access: $all
publish: $authenticated
unpublish: $authenticated
proxy: npmjs
'**':
access: $all
publish: $authenticated
unpublish: $authenticated
proxy: npmjs
Something like above will be your packages configuration which will allow for private packages to be looked on.
Next, very important configuration is setting up public url. If you do not set it, you may run into issues where on your deployed server, the server looks on a local ip to resolve incoming requests.
Publishing your private package will be available on the server which you can view in the web interface.
Issues you can run into
Proxy Issue:
error: tunneling socket could not be established, cause=Hostname/IP does not match certificate's altnames: Host: registry.npmjs.org. is not in the cert's altnames: DNS:*.domain.xyz EACCES: permission denied
This issue may come up if you have defined http_proxy
or https_proxy
config, once you define the public url, you should be good to go, this proxy will restrict you in resolving packages from uplinks such as npm registry. On hitting yarn install react
, the server will throw up the above error as you’ve not whitelisted the npm registry. Either you can remove the proxy config or you can whitelist the domain.
Access Issue:
When installing packages from uplinks or when publishing your own packages, you might run into access issue as you need to give read/write/execute permission to the storage folder. After giving the access the issue will resolve.
Third Party Plugin Issue:
verdaccio-aws-s3-storage
is the best example to look here. If you globally install this package and define all the configuration as per there readme, it won’t work.
You’ll need to add this package inside the node_modules of verdaccio package which is installed at the global path.
If you use nvm, you might have to look into the used node versions node_modules and then find verdaccio.
Verdaccio resolved the packages from that path, and once you paste the code there, it’ll start working.
Subscribe to my newsletter
Read articles from Sameer Utradhi directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
Sameer Utradhi
Sameer Utradhi
Hey there, out of all the smarties in the world you'd to stumble upon my blog. I feel you 🥹