Skip to content

Instantly share code, notes, and snippets.

@sepsol
Last active November 18, 2021 21:34
Show Gist options
  • Save sepsol/1ae4f98ab79a2b88a6fd27b7f86f96a3 to your computer and use it in GitHub Desktop.
Save sepsol/1ae4f98ab79a2b88a6fd27b7f86f96a3 to your computer and use it in GitHub Desktop.
How to create a private npm package registry for users in your network for FREE using verdaccio

Introduction

To resolve packages by name and version, npm talks to a registry website that implements the JavaScript CommonJS Package Registry specification for reading package info like software and metadata. Additionally, npm's package registry implementation supports several write APIs as well, to allow for publishing packages and managing user account information. Open source developers and developers at companies use the npm registry to contribute packages to the entire community or members of their organizations, and download packages to use in their own projects. The official public npm registry is at https://registry.npmjs.org/. It is powered by a CouchDB database, of which there is a public mirror at https://skimdb.npmjs.com/registry. The code for the couchapp is available here.

If you try to publish your own packages, by default npm will publish them the public registry. This can be overridden by specifying a different default registry or using a scope in the name of the package in package.json. To share your code with a limited set of users or teams, you can publish private user-scoped or organization-scoped packages to the npm registry. Now the drawback here are that in order to be able to publish your private user-scoped npm packages, you must sign up for a paid npm user account. Additionally, to publish private organization-scoped packages, you must create an npm user account, then create a paid npm organization.

To get around that, in this tutorial we want to start hosting our own free npm package registry which doubles as an npm proxy using the package verdaccio which is a fork of sinopia. We're going to install this registry on a Linux virtual machine that's going to act as a separate server on our local area network. This will allow other developers in our LAN to interact with the packages as well. In the end, to deploy our projects that use packages from this local registry on the internet, we're going to create a temporary tunnel by using ngrok to have access to our registry over the internet for a brief period of time.

Prerequisites

Initial Setup

Step 1: Create a virtual machine

In order to create a VM within VirtualBox, click on the blue "New" button at the top. On the dialog box that shows up, choose a memorable name for your VM, like "Package Server" and set the type and version to "Linux" and "Ubuntu (64-bit)" respectively as shown in the screenshot below: image On the next screen, allocate at least 1GB of RAM to your VM. I'm going to accept the default 1024MB and click continue. image For the hard disk, I'm going to create a virtual disk so that I can have a better performance later on. image Now here for the hard disk file type, I'm going to change the default selection from VDI to VHD since I'm not 100% sure for how long I'm going to keep hosting this server on my computer inside a VM. Choosing VHD gives me the option of migrating this VM to a cloud provider like Azure or AWS later on. image Next for the storage on physical hard disk, I'm going to select "Dynamically allocated". Although that might be a little bit slower than a "Fixed size" disk, I find it convinient for my setup which is on a laptop. Read the description in the wizard for more information. image On the final screen for file location and size, I'm going to keep the default location and select at least 10GB of maximum storage size for the VM. I'm going to stick with the defaults. image

Step 2: Mount your Linux image

Now that you've created your VM, it's time to install Linux on it using the image you've downloaded earlier. Before starting your VM, select it from the sidebar and click on the orange cogwheel at the top labeled "Settings". From here, navigate to the "Storage" tab and click on a drive that has the icon of a CD. Then from the options that appear on the right, for "Optical Drive", click on the CD icon and then select "Choose a disk file...". Finally from there you'll find your image file and select it. image

Step 3: Configure your Network

Now this is the important part for making sure you can share access to this server for people working in your LAN. Make sure your computer is connected to the internet using ethernet cable and then from the VM settings dialog box, go to the "Network" tab. Here keep the "Adapter 1" as "NAT" and make sure it is enabled for fallback, in case you move your laptop to an environment where your computer cannot be connected to the switch using an ethernet cable. image Then go to the second tab for "Adapter 2" and enable it. After that, for the "Attached to" select "Bridged Adapter" from the list and for the "Name" of your adapter, try to find and select the adapter that corresponds to your host machine's ethernet port. This varies from computer to computer and it's something that you have to figure out by googling for your situation. image Now you can confirm the changes and close the VM settings.

Step 4: Booting the VM and installing Linux

Now for this step, select your VM and click on the green arrow labeled "Start" from the top bar in VirtualBox. Don't worry about any errors that you might get, just wait for it to boot you into the installation page. Now proceed with the installation by choosing your language and keyboard layout. After those, you should see a screen where it tells you the name of different network adapters we attached to this client and the ip addresses that were assigned to each of those. If everything is set up correctly, you should see at least 2 of those. image We don't want to change anything here yet, so just confirm that you see 2 network adapters and continue. On the next screen you can configure your proxy settings. If you don't know what that is, just leave it empty. Then confirm the default mirror address for Ubuntu archive. On the final screen, I'll stick with the default storage options shown below and confirm. image Now you'll see a screen for "profile setup". Here I'm going with the settings below for my setup: image On the next screen, we're going to tick the box for "Install SSH server" so that we have SSH capability on the server and we can use our host operating system's terminal / command prompt instead the terminal provided inside VirtualBox. I'm not going to import any SSH identity files just yet though. image Finally, you can select any additional packages that you want the installer to install. I'm not going to select anything and proceed with the installation. Now we have to wait for the installation to finish installing Linux Server. After the installation is completed, it'd also automatically go to the internet and try to download any additional necessary updates. You'll see a screen like below after the installation is finished where you can select "Reboot Now". image And you're done! After the reboot you might see a screen like this: image Don't worry, this is because the VM is trying to eject the installation disk. You can press ENTER to continue. After the boot is completed, if you see your terminal being stuck, press ctrl + c and it'll start to ask for the credentials you specified earlier, enter them and you'll be in!

It's a good idea to make sure that you're running the latest version of the operating system and that all your packages are up-to-date. For this, you can run the following snippet:

sudo apt update && sudo apt upgrade -y

Step 5: Set up a static IP

In order for all the clients in your network to comminucate reliably with your server, it needs to have a static IP assigned to it. Follow the instruction below to assign a static IP to your server. You can check your current network settings by running the following in your client's terminal:

ip address show

or just:

ip a

This should give you a result similar to the following: image

  • The first network adapter is called lo, short for "loopback". This appears on every computer and points to a special IP address of 127.0.0.1 or localhost. All this does is that it routes the signals and streams back to their source without any processing or modification which as you probably know is helpful for development and testing.
  • The second network adapter in this list is called enp0s3 in my case. This is attached to the host via NAT that we specified on step 3 and is meant to provide a fallback connection to the internet for the client, in case the bridged network (next adapter) fails for any reason, i.e. issues with the ethernet cable.
  • The final network adapter in my case is enp0s8. This is attached via bridge to the ethernet network adapter of the host and the ip address that you see for this adapter on your VM, follows the subnet rules of the gateway that your physical host is connected to. Make note of the name of the adapter, the IP address, and the subnet mask value for this one.

Now run the following command to figure out the address of the default gateway for your network:

ip route show

or just:

ip r

The output would look something like this: image Here, look for the IP address that is assigned to the third network adapter from before and make note of it, which is enp0s8 in my case. The IP address of its default gateway for me is 192.168.150.5, yours will probably be different.

So far we've collected the following information and we can proceed to assigning a static IP to our VM:

  • Name of our client's network adapter which is attached via bridge to our host's ethernet adapter (enp03)
  • IP address of the client with that adapter (192.158.150.102)
  • The network subnet mask for that adapter (ip-address/24 which means 255.255.255.0 in my case)
  • The IP of the default gateway associate to that adapter (192.168.150.5)

Now we'll have to go the following directory:

cd /etc/netplan

Here if we run ls we'll be able to see a default 00- ..... .yaml config file. The way netplan works, is that we can have as many config files as we want in this folder. The only rule is that their name should start with a two-digit number and end with the .yaml extension. Also whatever comes at the end, will always override the previous configs. To create and open a new config file, run the following in the /etc/netplan directory:

sudo nano 01-static-ip-over-bridge.yaml

And enter the following information in it:

# /etc/netplan/01-static-ip-over-bridge.yaml @ package-server

network:
  version: 2
  ethernets:
    YOUR_NETWORK_ADAPTER:
      dhcp4: no
      addresses: [YOUR_DESIRED_STATIC_IP_WITH_MASK_IN_CIDR_NOTATION]
      gateway4: IP_OF_YOUR_DEFAULT_GATEWAY
      nameservers:
          addresses: [8.8.8.8]

Here, you have to enter the information you wrote down from above. Keep in mind the the IP address you assign to your VM, has to be in the IP space of your subnet. Otherwise it would not be able to communicate with any devices in your network. Also I'm using google's DNS server as my nameserver which is at 8.8.8.8. But you can feel free to change it if you want.

In the end, your file should look something like this: image

Now press ctrl + x to close the file, then hit y to save the changes, and ENTER to override the changes on the existing file. Finally, in order to try and apply these changes for your network settings, run the following command:

sudo netplan try

Here, you might get an error message that says:

An error occured: 'NetplanApply' object has no attribute 'state'

In that case, you can run this instead:

sudo netplan try --state /etc/netplan

It's going to show you a message like the one below. Just hit ENTER to confirm the changes. image

In case you know you've entered the correct settings and want to apply your changes immediately, run:

sudo netplan apply

Now confirm that you've been assigned the correct IP address by running ip a again. Congratulations! You've successfully assigned yourself a static IP!

Bonus: In case you're like me and you work on your laptop that runs the server accross different office networks with your colleagues, you might want to make yourself a helper script that you can execute whenver you switch from one network to the other. First create and edit the script like so:

sudo nano /usr/local/bin/network

Then copy a script like the following in there (NOTE: be sure to add the #!/bin/bash shebang to the very beginning of the file):

# /usr/local/bin/network @ package-server

#!/bin/bash

# This script updates the network adapter settings for netplan
# You can customize it and run it whenever your server moves to a new network environment

# Parameters
confpath="/etc/netplan"
confname="01-static-ip-over-bridge.yaml"
network="work"
adapter="enp0s8"
ipcidr="192.168.150.105/24"
gateway="192.168.150.1"
dns="8.8.8.8"

# Check user permissions
if [ "$EUID" -ne 0 ];
then
  echo "Error: This command has to be run as root"
  exit
fi

# Check for commandline arguments
if [ ! $1 ];
then
  read -p "Switch network [home | work]: " network
else
  network=$1
fi

# Change parameters based on network
if [ $network == "home" ];
then
  gateway="192.168.150.1"
elif [ $network == "work" ];
then
  gateway="192.168.150.5"
fi

# Create a netplan config file
cat >$confpath/$confname <<EOL
# ${network^^}

network:
  version: 2
  ethernets:
    $adapter:
      dhcp4: no
      addresses: [$ipcidr]
      gateway4: $gateway
      nameservers:
          addresses: [$dns]

EOL

# Apply the config and exit appropriately
sudo netplan apply
if [ $? -eq 0 ];
then
  echo "Successfully switched to $network network"
else
  echo $?
fi

# Exit gracefully
exit

Now make the file executable by running:

sudo chmod +x /usr/local/bin/network

Now whenever you change networks, you just have to run:

sudo network home

or:

sudo network work

At this point as a best practice, it's a good idea to go onto the host machine of yourself and any other users on your network and set an environment variable for your registry's endpoint. For Windows users, this can be done using the commandline as explained this guide.

For macOS and Linux:

export PACKAGE_SERVER_PROTOCOL="http"
export PACKAGE_SERVER_IP="192.168.150.105"
export PACKAGE_SERVER_PORT="4873"
export PACKAGE_SERVER_SOCKET="$PACKAGE_SERVER_IP:$PACKAGE_SERVER_PORT"
export PACKAGE_SERVER_ENDPOINT="$PACKAGE_SERVER_PROTOCOL://$PACKAGE_SERVER_SOCKET"

or for Windows Command Prompt:

setx PACKAGE_SERVER_PROTOCOL "http"
setx PACKAGE_SERVER_IP "192.168.150.105"
setx PACKAGE_SERVER_PORT "4873"
setx PACKAGE_SERVER_SOCKET "%PACKAGE_SERVER_IP%:%PACKAGE_SERVER_PORT%"
setx PACKAGE_SERVER_ENDPOINT "%PACKAGE_SERVER_PROTOCOL%://%PACKAGE_SERVER_SOCKET%"

To confirm that your changes are applied, for macOS and Linux run:

cat $PACKAGE_SERVER_ENDPOINT

For Windows, open a new Command Prompt and run:

echo %PACKAGE_SERVER_ENDPOINT%

From now on, we should use $PACKAGE_SERVER_ENDPOINT / %PACKAGE_SERVER_ENDPOINT in shell or cmd whenever we want to refer to our server.

Step 6: Set up SSH

By now you might feel frustrated by how ugly and clunky the default terminal inside VirtualBox is. The solution to that would be not to use it! In this step, we're going to create an SSH key pair on our host machine, so that we can connect to our client's shell, through our host's shell using SSH. Now this will slightly be different for Windows, so we'll cover that first.

A Prerequisite for Windows

For Windows 10 and later, you might need to go into "Settings" and then "Apps & features" and from there open "Optional features" like so:

image

And then if "OpenSSH Client" is not listed, click on the "+ Add a feature" button at the top and find it and click install. Your optional features should look something like this at the end:

image

You might also want to either use the terminal from Windows Subsystem for Linux (WSL) or git bash for this part.

Now with that out of the way, cd ~/.ssh and then run the following command in your host machine's shell to generate your private and public SSH keys:

ssh-keygen -t ed25519 -C USER@COMPUTER_AS_COMMENT

or if you're using a legacy system that doesn't support the ed25519 algorithm, use:

ssh-keygen -t rsa -C USER@COMPUTER_AS_COMMENT

Then follow the instruction to create your key pair. I recommand entering the host's user and computer names as the comment and the server's computer name as the name of the file where the key is going to be stored in. The generated SSH keys will be stored in ~/.ssh by default. Use the following command on your host to copy over your public key to your VM:

ssh-copy-id -i ~/.ssh/YOUR_PUBLIC_KEY SERVER_USERNAME@SERVER_IP

which translates to the following in my case:

ssh-copy-id -i ~/.ssh/package-server.pub administrator@$PACKAGE_SERVER_IP

Now if you navigate to ~/.ssh on your VM, you should be able to see a new file called authorized_keys that contains your host's public key. You can repeat this step for as many computers that should be able to SSH into your VM as you want.

Finally to test and see whether this works, run:

ssh -i ~/.ssh/YOUR_PRIVATE_KEY SERVER_USERNAME@SERVER_IP

which in my case is:

ssh -i ~/.ssh/package-server administrator@$PACKAGE_SERVER_IP

It will ask for whether to save the fingerprint which you'll say "Yes" to, and then you'll be connected. In the end it might ask for the password of the user you specified earlier. Finally you should be able to connect to your VM using your host's terminal. You can confirm this by looking at the command prompt and checking the user and computer name. To get out of the VM's shell just run exit.

Now we can improve our SSH experience by modifying our SSH config file which is located at ~/.ssh/config. To do that, run the following command from your host's shell:

nano ~/.ssh/config

And add the following lines to it:

# ~/.ssh/config @ host-computer

Host CUSTOM_CONNECTION_ALIAS
	User SERVER_USER
	HostName SERVER_IP
	IdentityFile PRIVATE_SSH_KEY

The final config file should look like this: image

Now save the file by hitting ctrl + x, y, and ENTER consecutively. From now on, instead of the long command above, you can SSH using the following memorable command:

ssh CUSTOM_CONNECTION_ALIAS

or in my case:

ssh package-server

That's it! Now we're all set up and we can get to the juicy part to install the actual package server and configure it to be used accross our local network and occasionally the internet.

Creating the Private Package Registry

Step 7: Install NVM

First, we want to SSH into our server using our host's terminal. Then as a best practice the first thing we do, is to install nvm for managing different node installations. To do so, run the following command in your shell:

curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash

This will run a install script and as a result, clones the nvm repository on github, to ~/.nvm, and then attemps to add a few lines containing a new NVM_DIR environment variable, to the bash source file, namingly ~/.bashrc profile config file. In the end, we should either close our shell and open a new one for the changes to be applied, or we can alternatively reload our shell session like so:

source ~/.bashrc

At this point, to verify the installation you can either run nvm or command -v nvm (instead of which nvm) and nvm -v to see the version currently installed.

Step 8: Install Node.js

Now that we have nvm installed, node can be installed with just a single command:

nvm install --lts

This will install the long-term support (LTS) version of node and also installs npm on the side. To verify installations simply run:

node -v
npm -v

You can also run the following command to make sure that you're running the latest version of npm:

npm install --global npm@latest

or just:

npm i -g npm@latest

Step 9: Install and configure Verdaccio

Now to the juicy part! To install the verdaccio package, simply run:

npm i -g verdaccio

Note that it must be installed globally to work correctly. Once it has been installed, run cd to change to the user's home directory and then make sure to execute the CLI command at least once for it to generate its config file:

verdaccio

and the output will look something like this: image Notice the config directory specified in the first line. If this was running on a device that had internet browser, we could visit http://localhost:4873 and see verdaccio's GUI web app. Once configured, this app will allow our users to search our registry for packages and docs, just like how they would on npm's official website

To stop the process, simply press ctrl + c. You can then attempt to change verdaccio's default configuration by running this:

nano ~/verdaccio/config.yaml

Fix the path of directories

By default, every time you run verdaccio, it creates a new storage directory within the directory you're currently in. To avoid such issues, we have to change the paths to storage, plugins, and htpasswd from relative to absolute like so:

# ~/verdaccio/config.yaml @ package-server

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

# ...

auth:
  htpasswd:
    file: /home/administrator/verdaccio/htpasswd
    # ...
# ...

Listen to requests from all addresses in your LAN

By default, verdaccio will only listen for npm requests coming at it from the same computer that it's running on, i.e. localhost. In order for it to listen to requests from all the computers located in its network, you have to add the following to the top of your config file, after specifying the storage and plugins paths and before specifying web configuration:

# ~/verdaccio/config.yaml @ package-server

# ...
# You can specify listen address (or simply a port).
# If you add multiple values, verdaccio will listen on all of them.
#
# Examples:
#
#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
listen:
  0.0.0.0:4873
# ...

What this essentially does, is that it changes the value of listen directive from the default localhost:4873 to 0.0.0.0:4873. Note that 0.0.0.0 is a special meta IP address that is used for devices that want to listen to broadcasts on a network. You can read more about this on Wikipedia.

To confirm that this works, you can open a web browser on your host, and try to visit the port 4873 of your VM. So in my case that is:

http://192.168.150.105:4873

or if on macOS, type this in your terminal:

open $PACKAGE_SERVER_ENDPOINT

If everything is set up correctly, you should see a page like this: image

Create a scope for your company

All npm packages have a name which is specified in their package.json. Some package names also have a scope. A scope follows the usual rules for package names (URL-safe characters, lowercase letters, no leading dots or underscores). When used in package names, scopes are preceded by an @ symbol and followed by a slash /, e.g.

@somescope/somepackagename

Scopes are a way of grouping related packages together, and also affect a few things about the way npm treats the package.

Scoped packages can be published and installed as of npm@2 and are supported by the primary npm registry. Unscoped packages can depend on scoped packages and vice versa. The npm client is backwards-compatible with unscoped registries, so it can be used to work with scoped and unscoped registries at the same time. You can read more about scopes on npm's official docs.

If you're configuring verdaccio for a company, under packages in your config file, create a new scope for your organization / department by doing so:

# ~/verdaccio/config.yaml @ package-server

# ...
packages:
  '@MY_COMPANY/*':
    # company's packages
    access: $authenticated
    publish: $authenticated
    unpublish: $authenticated
    # ...
# ...

Note that we didn't provide a proxy directive for this scope, this is so that if the scoped package is not available on the server, we don't send proxy requests to the default npmjs registry. Also instead of $authenticated, we could use $all or $anonymous based on our use case. For more information regarding how to configure access to scoped packages, take a look at verdaccio's official docs.

Restrict registry access and create users

To prevent users from signing up on our registry by themselves, we'll set the max_users: -1 like so:

# ~/verdaccio/config.yaml @ package-server

# ...
auth:
  htpasswd:
    # ...
    max_users: -1
# ...

Now, this is the message the user gets if they try to register on your registry: image

Since we restricted our users from signing up, we can create their accounts by generating an htpasswd file. The htpasswd file contains rows corresponding to a pair of username and password separated with a colon character. The password is encrypted using the UNIX system's crypt method and may use MD5 or SHA1. To generate username:password combinations, we need to open up this link and fill it out and click on the blue button that says "Create .htpasswd file". It'll generate a username:password at the top for you. This is how it look like: image

Now, all we have to do is to copy the username:password combination it generated for us and SSH into our server. Then if we don't already have a htpasswd file, we create it at the path specified above in the config file. Finally we open the file and paste what we copied there on a new line:

nano ~/verdaccio/htpasswd

And here's how the file will look like after we paste our combo: image

That's it! You're all set. Now your users can login to your registry from their machines. Here's an example of how your they'll be able to do it using scopes: image

And in case they wanted to logout and remove the registry, all they have to do is this: image

More on this towards the end of this article.

Here are some links to official verdaccio documentation, if you're interested to learn more about this topic:


After configuring your verdaccio to your liking, I'd recommand that you run verdaccio one more time so that it grabs all the new settings and applies them.

Step 10: Install pm2 to manage verdaccio

pm2 is a production process manager for Node.js applications with a built-in load balancer. It allows you to keep applications alive forever, to reload them without downtime and to facilitate common system admin tasks.

To install pm2, stop verdaccio on the server and run:

npm i -g pm2

We can use this package to start any application (Node.js, Python, Ruby, binaries in $PATH...) like this:

pm2 start app.js

But for verdaccio, we need to run it slightly differently for the first time:

pm2 start `which verdaccio`

Once applications are started we can manage them easily. Our app is now daemonized, monitored and kept alive forever. Here are some useful commands that can be used after the first run:

# List all running applications
pm2 list
pm2 status

# Get more details on a specific application
pm2 describe verdaccio

# View latest logs
pm2 logs

# Monitor logs, custom metrics, and application information
pm2 monit

# Manage applications
pm2 stop verdaccio
pm2 start verdaccio
pm2 restart verdaccio
pm2 delete verdaccio

# Hot reload applications without downtime
pm2 reload verdaccio

# Freeze your process list across server restart for automatic respawn
pm2 save

# Generate / remove startup script
pm2 startup
pm2 unstartup

To learn more, visit the documentation section of the official website.

Here's an example of what I did for my instance: image

Now simply run sudo shutdown -r to restart your system and then run pm2 status to see if the verdaccio process starts automatically by itself.

Using the Private Registry

Now that you have everything set up, it's time to configure your clients to point their registry URLs to your server in their npm runtime config file, namely .npmrc. To edit this config file, we have to run the following command in our host environment:

npm config edit

If we want to replace the default npm registry with our own registry everywhere on our host environment, we have to add the following lines to the config file:

; ~/.npmrc
registry=$PACKAGE_SERVER_ENDPOINT

or if you prefer to use npm CLI, you can run:

npm config set registry $PACKAGE_SERVER_ENDPOINT

If the server is set up in a way that it only allows authenticated users to see its packages, we can login after setting the registry using:

npm login

Alternatively, we could instead use the following command to login and set the registry URL at the same time from the beginning:

npm login --registry=$PACKAGE_SERVER_ENDPOINT

If you are allowed to create an account for yourself, you can run:

npm adduser --registry=$PACKAGE_SERVER_ENDPOINT

The downside to this method where we override the default registry with our own server, is that your server has to always be up and running and respond to requests. Otherwise whenever its down, all of the requests from your clients will time out. In order to avoid this, we can use scopes we created earlier for our company and change the registry we use only for that scope by adding the following line to the config file:

; ~/.npmrc
@MY_SCOPE:registry=$PACKAGE_SERVER_ENDPOINT

Alternatively we could use the CLI command:

npm config set @MY_SCOPE:registry $PACKAGE_SERVER_ENDPOINT

Also if the access is only granted to authorized users, we can login using:

npm login --scope=@MY_SCOPE --registry=$PACKAGE_SERVER_ENDPOINT

If you were allowed to create an account for yourself, you could also run:

npm adduser --scope=@MY_SCOPE --registry=$PACKAGE_SERVER_ENDPOINT

To see whether we're logged in to our desired registry, we can run:

npm whoami --registry=$PACKAGE_SERVER_ENDPOINT

To see your profile, run:

npm profile get --registry=$PACKAGE_SERVER_ENDPOINT

To reset your password where allowed, run:

npm profile set password --registry=$PACKAGE_SERVER_ENDPOINT

To logout of our registry, we can run:

npm logout --registry=$PACKAGE_SERVER_ENDPOINT

And to remove our registry altogether, we can run:

npm config delete registry

or for scoped registries:

npm config delete @MY_SCOPE:registry

It's a good idea to ask your colleagues to include their names and information in any package they publish. Also if you're publishing packages to your own scope most of the time, you probably want to set the value of your default scope to be something. To do these, run the following:

npm config set init-author-name "Sepehr Soltanieh"
npm config set init-author-email sepehr@email.com
npm config set init-author-url https://github.com/sepsol
npm config set scope MY_SCOPE

Now, anytime you create a new npm project using npm init, your default values will be inserted into its package.json.


After you've configured your registry endpoint, you can use commands like the ones below:

npm install @scoped/package
npm publish
npm unpublish --force

To clear all the changes and revert back to the default .npmrc file, simply delete it. The next time you interact with npm config, it'll automatically generate a new one from the default template:

rm ~/.npmrc

If you're interested in learning more, here are some useful links from the official documentation for npm:

Bonus Tip: Expose Your Registry to the Internet

To expose our npm registry to the internet, we're going to make use of a package called ngrok. To this, you'll need to have node and npm on your host environment. After that, you can install this package like so:

npm i -g ngrok

Now to use it with our server, you only need to run:

ngrok http $PACKAGE_SERVER_ENDPOINT

Running this, will give you a random URL that's going to be valid for a limited amount of time and after that it expires and you have to run the command again to generate a new one. image You can also monitor the incoming and outgoing requests to your ngrok endpoint, by going to http://localhost:4040.

This https://*.ngrok.io URL would be useful for scenarios where you want to deploy your changes to a remote server or for when you have a colleague that works remotely from you.

Tip: In case you were not able to fetch packages from the URL provided by ngrok, just go on your server and run:

pm2 reload verdaccio

This will hot reload verdaccio's process and hopefully your URL will work again afterwards.


Bonus: If you do this too often, you'll find yourself adding a lot of registries to the .npmrc file on your server and it gets pretty dirty. To avoid this and to clean after ourselves each time we change the URL of our package server, you can create the following shell command. First create the file like so:

sudo nano /usr/local/bin/package-server

Then after adding the shebang #!/bin/bash, copy the following to the file:

# /usr/local/bin/package-server @ production-server

#!/bin/bash

# This script resets the npm config for the user and tries to update the scoped registry
# You can customize the behavior of this script and use it on any scope you'd like

# Parameters
confpath=$HOME
confname=".npmrc"
scope="MY_SCOPE"
registry=""

# Read the commandline arguments
if [ ! $1 ];
then
  read -p "Package server url (https): " registry
else
  registry=$1
fi

# Remove old config file
rm $confpath/$confname
if [ $? -eq 0 ];
then
  echo "Removed old npm config"
else
  echo $?
fi

# Add the new registry
npm config set @$scope:registry $registry
if [ $? -eq 0 ];
then
  echo "Added the new registry for scope @$scope"
else
  echo $?
fi

# Log in to the new registry
npm login --scope=@$scope --registry=$registry
if [ $? -eq 0 ];
then
  echo "You're all set!"
else
  echo $?
fi

# Exit gracefully
exit

Now make the file executable by running:

sudo chmod +x /usr/local/bin/package-server

That's it! Next time you can set your registry like so:

package-server https://*.ngrok.io
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment