Skip to content

Instantly share code, notes, and snippets.

@elevenpassin
Created May 9, 2025 11:54
Show Gist options
  • Save elevenpassin/b12ee4455d5017cdd2460fcc4119b439 to your computer and use it in GitHub Desktop.
Save elevenpassin/b12ee4455d5017cdd2460fcc4119b439 to your computer and use it in GitHub Desktop.
Notes for deploying a NodeJS application on a VPS

Deployment

Instructions for deploying the a nodejs server to production.

Prepare the production server

Once a linux server has been created in your preferred cloud platform (I am using Hetzner here), we need to prepare the server for production usage.

root user

Generally speaking, you should get access to the root user when you create a server, which should allow you to ssh into the server using the command below:

$ ssh root@your_server_ip_addr

Once you have logged in, immediately the first thing to do is to set a password to the root account.

Use the command below to change password:

root $ passwd

Creating a user account for your application

Since working with root directly is generally discouraged for various security and safety reasons, we'll create a seperate user account with limited permissions who's job is to run the server.

Use the command below to create a new user account:

root $ adduser server_username

We can now provide our new user with admin privileges so we don't have to switch to root user every time we need to do an administrative task. This will allow the new user to do administrative tasks by prepending sudo to their commands.

root $ usermod -aG sudo server_username

Setting up a firewall

We can make use of ufw firewall to limit the extent of ports etc that general public can access. To do this, first make sure to install ufw on the server:

root $ apt install ufw

Now that we have ufw installed, it's time to configure it. You can try to run the following command to see if we can already start configuring various applications' access through firewall:

root $ ufw app list

We need to make sure that the firewall allows SSH connections so that we can log back in next time, we can allow these connections by typing:

root $ ufw allow OpenSSH

and then we enable the firewall itself:

root $ ufw enable

You can check the status of the firewall by typing in:

root $ ufw status

Setting up SSH login for the application user

For our application user that we created a few steps back, if you try to ssh using the command below:

$ ssh server_username@your_server_addr

You will be prompted to enter the user password to login, but since we already have our public SSH key on the server configured for the root user, we can just copy over the root user's .ssh/authorized_keys folder into our server user's home folder.

We can do this using rsync:

root $ rsync --archive --chown=server_username:server_username ~/.ssh /home/books-server/.ssh

Now you should be able to simply SSH into your server without typing in your password.

Setting up NodeJS

Starting now, let's use our newly created application user to setup NodeJS

So if you want to run the books-server, since it is written in NodeJS, we'll need to setup nodejs on the server. To install NodeJS, I'm going to simply follow the instructions from NodeSource as they provide binary distributions for most major versions of NodeJS.

Simply follow the installation instructions from their github page, as I am using a debian server, I'll be using the instructions for Debian:

Install curl

books-server $ sudo apt install -y curl

Download the setup script

books-server $ curl -fsSL https://deb.nodesource.com/setup_22.x -o nodesource_setup.sh

Run the setup script with sudo

books-server $ sudo -E bash nodesource_setup.sh

Install Node.js

books-server $ sudo apt-get install -y nodejs

Verify that node is installed

books-server $ node -v

Setting up NPM / Yarn

Generally speaking, NPM should come part of the Node.js package, so if you have nodejs installed, you should be able to also use Npm, you can verify that npm is installed by typing:

books-server $ npm -v

Installing build-essential package

For some NPM packages, we often need to locally compile the native binaries from source, for example in the case of node-gyp. To make it possible, we can install the build-essential package as it will install various tools like make, gcc etc on our system.

books-server $ sudo apt install build-essential

Setting up Yarn

Books server primarily uses yarn for it's package management, so let's install yarn:

books-server $ npm i -g yarn@latest     # installation
books-server $ yarn -v                  # verification

Copying over the server code

You can just copy over the books-app server from your local machine to the server by using scp. But before you do that, make sure that you make a production copy of your server folder and then remove any unwanted folders like .git, node_modules, .yarn etc.

Run this on your local machine to copy over the books-server:

$ scp -rp .\books-app-prod books-server@your_server_addr:/home/books-server/app

You might have to rename or move the server folder to an appropriate directory on the server once you have uploaded everything. I stored my server at /home/books-server/app.

Configuring the server

At this point, you should just be able to use node path/to/server.js or equivalent to run the server. Please note that the server will not be available to public yet as we currently only allow SSH connections through the ufw firewall.

Before we configure the firewall, we should first setup the server itself.

Env Variables

Make sure to update the env variables file in the server folder, specifically configure the server to run on port 80 (since we're only doing http for now) as well as any other env variables like the database URL etc.

At the end of this step you should be able to already start a production server, albiet without any daemon in place to handle automatic restarts etc.

Setting up PM2

PM2 is going to be our daemon controller, it will setup a daemon for our server so that any time our server has to restart, the daemon will make sure that books-app server is also restarted and up and running again.

To install PM2, just run:

books-server $ sudo npm install pm2@latest -g

Now you can instruct PM2 to start the books-server

books-server $ sudo pm2 start path/to/server.js

This will add books-app server to PM2's process list. Applications running on this process list will be automatically restarted if the app crashes or is killed. We can also take one additional step to make sure that the app is run on system startup:

books-server $ sudo pm2 startup systemd

This will ask you to run a specific command with sudo permissions in your terminal, once that is done, a systemd unit is created, that runs a pm2 process on boot for books-server user. This pm2 instance in turn will run the server itself.

Now that the server is up and running you should do one last thing before accessing the server and that is to allow http connections on port 80.

books-server $ sudo ufw allow 80 # alternative: sudo ufw allow http

You can verify that access to port 80 is allowed by typing in:

books-server $ sudo ufw status

Congratulations! You have accessfully setup a nodejs server for production!

You can now visit http://your_server_addr to checkout your newly setup server!

Resources

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment