SmallData | Blog | Setup a private npm registry

With the recent docker fiasco it has become more and more
imperative that we own our own build pipelines and vendor as much of 3rd party code as much as possible. In
this article we will look at setting up a production ready private npm registry using verdaccio, an open source npm registry.


While verdaccio can run locally, we would like to have something that is accessible over the internet, for example: To that effect
we would need host running ubuntu (or your flavor of linux) with root privileges and a webserver installed. This
tutorial provides instructions for setting up a reverse proxy to verdaccio via Nginx.


While verdaccio comes with a docker image, in this setup we will install verdaccio directly in order to reduce the
risk of docker itself. The first step then is to install the latest LTS node version via nvm.
Once Node.js installed, run npm install --location=global verdaccio. Test that verdaccio is working by
simply running it on the commandline: verdaccio. Note that this will create a default config file.

We will now setup the subdomain and test that we can access our registry. With verdaccio running, we use a different
session to create
/etc/nginx/sites-available/npm-registry as below (change to your

server {

  # add Strict-Transport-Security to prevent man in the middle attacks
  add_header Strict-Transport-Security "max-age=63072000; includeSubdomains; preload;";
  add_header X-Frame-Options DENY;
  add_header X-Content-Type-Options nosniff;

  access_log /var/log/nginx/;

  location / {
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-NginX-Proxy true;

    proxy_set_header Host            $host:$server_port;
    proxy_set_header X-Forwarded-For $remote_addr;
    proxy_set_header X-Forwarded-Proto $scheme;

    proxy_redirect off;

    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;

Enable the subdomain and setup https via certbot

sudo ln -s /etc/nginx/sites-available/npm-registry /etc/nginx/sites-enabled/npm-registry
sudo nginx -t
sudo service nginx restart
sudo certbot --nginx

If everything was successful then we should be able to head to and see
the verdaccio installation. In order to test that this works create a .npmrc file in your local node.js
project root with the following line in it: registry= This will tell npm
to fetch packages from the provided registry. Running npm config get registry should also confirm this.
Finally, executing npm install should now also populate the default storage
(~/.config/verdaccio/storage) with npm packages on the server. We will now customise the defaults, add
authentication and make the service persistent.

Secure the private registry

As it stands the registry is not very private as anyone with the url can start using it as a proxy. We will now
customise the defaults to secure our setup.

mkdir ~/verdaccio
mv ~/.config/verdaccio/config.yaml ~/verdaccio/config.yaml
rm ~/.config/verdaccio
mkdir ~/verdaccio/storage
mkdir ~/verdaccio/plugins

Assuming that your home directory is /home/user, we will update the following config settings:

# path to a directory with all packages
storage: /home/user/verdaccio/storage
# path to a directory with plugins to include
plugins: /home/user/verdaccio/plugins

    file: /home/user/verdaccio/htpasswd
    # Maximum amount of users allowed to register, defaults to "+inf".
    # You can set this to -1 to disable registration.
    max_users: -1
    # 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

# a list of other known repositories we can talk to

# Learn how to protect your packages
    # scoped packages
    access: $authenticated
    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: $authenticated

    # 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

    legacy: true
        expiresIn: 29d
        expiresIn: 1h # 1 hour by default

Note that by setting max_users to -1 we disallow anyone from
register themselves. We also set all access to $authenticated so that no unregistered user can use our
private repository. Finally we will create our single registered user via the following:

sudo apt install apache2-utils
htpasswd -c /home/user/verdaccio/htpasswd user
verdaccio --config /home/user/verdaccio/config.yaml

Once verdaccio is running, trying to npm install on the local machine should now result in a
code E401. It might be
prudent to npm cache clean --force; rm -rf node_modules to force installation from the registry. In order
to download packages from our private registry, we will authenticate our machine via:
npm login --registry --auth-type=legacy. Once authenticated,
npm i should work and packages should pop up on the provided storage location on the server as well.


In order to persist verdaccio across restarts we will use pm2.

npm i -g pm2
pm2 startup
pm2 start `which verdaccio` -- --config /home/user/verdaccio/config.yaml
pm2 save

Finally, we setup a cron job to flush pm2 log files in order to save space, crontab -e (change the node
version to match the pm2 installation):

# 04:0 on Friday - flush all log files
5 4 * * 5 /home/user/.nvm/versions/node/v16.15.0/bin/pm2 flush > /home/user/pm2-flush.log 2>&1

And that is about it, do not forget to add .npmrc to your .gitignore so that you do not
leak your registry information :).

HackerNews submission / discussion

Source link