Node.js lets you run JavaScript on your server. It powers web apps and APIs built with frameworks such as Express, Next.js, Nuxt, NestJS and Fastify, as well as many popular tools. This guide installs Node.js, keeps your app running with PM2, and puts it on your domain with a free SSL certificate using Nginx.

It works on every operating system we offer: Ubuntu 22.04, 24.04 and 26.04, Debian 12 and 13, AlmaLinux 8, 9 and 10, and Rocky Linux 9 and 10.

Before you start

  • SSH access as root or as a user with sudo rights. If you're logged in as root, you can leave sudo off the commands.
  • A VPS with at least 1 GB of RAM. Building larger apps, such as Next.js sites, can need 2 GB or more.
  • A domain or subdomain with an A record pointing to your VPS IP address, if you want your app on its own domain (Step 6).

Which version should I install?

Use a Long Term Support (LTS) version for anything in production. This guide uses Node.js 24, the current LTS release. Check nodejs.org for the latest LTS version. To install a different one, change the number 24 in the commands below.

Step 1: Create a user for your app

For security, it's best to run your app as a normal user rather than root:

sudo useradd -m -s /bin/bash nodeapp

Step 2: Install Node.js

Choose one of these two options.

Option 1: NodeSource repository (recommended for servers)

This installs Node.js system-wide, for every user, and keeps it updated with your other packages. Run these as your admin user.

Ubuntu/Debian

sudo apt update
sudo apt install -y curl ca-certificates
curl -fsSL https://deb.nodesource.com/setup_24.x -o nodesource_setup.sh
sudo bash nodesource_setup.sh
sudo apt install -y nodejs

AlmaLinux/Rocky

curl -fsSL https://rpm.nodesource.com/setup_24.x -o nodesource_setup.sh
sudo bash nodesource_setup.sh
sudo dnf install -y nodejs

Then install PM2, which keeps your app running (see Step 5):

sudo npm install -g pm2

If the setup script says your operating system version isn't supported yet, use Option 2 instead.

Option 2: nvm (Node Version Manager)

nvm installs Node.js for a single user, and makes it easy to switch between versions. It's handy if different apps need different versions. Because it's per user, run these commands as the app user. Switch to it first:

sudo -iu nodeapp

Find the latest install command on the nvm project page. It looks like this:

curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash
source ~/.bashrc
nvm install --lts
npm install -g pm2

Type exit to go back to your admin user.

Check it worked (either option): switch to the app user with sudo -iu nodeapp, then run:

node -v
npm -v

Type exit to go back to your admin user.

Step 3 (optional): Install build tools

Some npm packages compile code when they're installed. If you see errors mentioning gyp, make or g++, install the build tools:

Ubuntu/Debian

sudo apt install -y build-essential

AlmaLinux/Rocky

sudo dnf install -y gcc-c++ make

Step 4: Run a test app

Switch to the app user and create a simple app:

sudo -iu nodeapp
mkdir ~/myapp && cd ~/myapp
npm init -y
npm install express
nano app.js

Paste in the following, then press Ctrl+O and Enter to save and Ctrl+X to exit:

const express = require('express');
const app = express();
const port = 3000;

app.get('/', (req, res) => {
  res.send('Hello from my Hoopla Hosting VPS!');
});

app.listen(port, '127.0.0.1', () => {
  console.log(`App listening on port ${port}`);
});

The app listens on 127.0.0.1, so it's only reachable from the server itself. Nginx will make it available to the world in Step 6. For your own app, upload your code instead, for example with Git or SFTP, and run npm install in its folder.

Step 5: Keep your app running with PM2

PM2 keeps your app running in the background, restarts it if it crashes, and starts it again when the server reboots. Still as the nodeapp user:

cd ~/myapp
pm2 start app.js --name myapp
pm2 save
pm2 startup

pm2 startup prints a command starting with sudo. Copy it, type exit to go back to your admin user, then paste and run it. This sets PM2 to start your app when the server boots.

Useful PM2 commands, run as the nodeapp user:

  • pm2 list: show running apps
  • pm2 logs myapp: follow your app's logs
  • pm2 restart myapp: restart after you change your code
  • pm2 monit: live CPU and memory use

Step 6: Put your app on your domain with Nginx and SSL

As your admin user, install Nginx and Certbot:

Ubuntu/Debian

sudo apt install -y nginx certbot python3-certbot-nginx

AlmaLinux/Rocky

sudo dnf install -y epel-release
sudo dnf install -y nginx certbot python3-certbot-nginx
sudo systemctl enable --now nginx
sudo setsebool -P httpd_can_network_connect 1

The last command lets Nginx connect to your app, which SELinux blocks by default.

Open the firewall for web traffic:

Ubuntu/Debian with UFW enabled:

sudo ufw allow 80/tcp
sudo ufw allow 443/tcp

AlmaLinux/Rocky with firewalld:

sudo firewall-cmd --permanent --add-service=http --add-service=https
sudo firewall-cmd --reload

Create the Nginx configuration:

  • Ubuntu/Debian: sudo nano /etc/nginx/sites-available/myapp
  • AlmaLinux/Rocky: sudo nano /etc/nginx/conf.d/myapp.conf

Paste in the following, replacing the domain with your own:

server {
    listen 80;
    server_name app.example.co.nz;

    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

Save and exit. On Ubuntu/Debian, enable the site:

sudo ln -s /etc/nginx/sites-available/myapp /etc/nginx/sites-enabled/

On all systems, test and reload Nginx, then get your SSL certificate:

sudo nginx -t
sudo systemctl reload nginx
sudo certbot --nginx -d app.example.co.nz

Open https://app.example.co.nz and you'll see your app. For more on SSL certificates, see Free SSL certificates with Let's Encrypt and Certbot.

Keeping it up to date

  • Node.js (Option 1): updates with your system, using sudo apt upgrade or sudo dnf upgrade. To move to a new major version, run the NodeSource setup script again with the new version number.
  • Node.js (Option 2): as the app user, run nvm install --lts, reinstall PM2 with npm install -g pm2, then run pm2 update and pm2 startup again.
  • Your app's packages: run npm outdated to see what's out of date, and npm audit to check for known security issues.

Troubleshooting

  • 502 Bad Gateway: Nginx can't reach your app. Check it's running with pm2 list (as the app user), that it listens on the port in your Nginx configuration, and on AlmaLinux/Rocky that you ran the setsebool command.
  • "node: command not found": if you used nvm, make sure you're logged in as the app user (sudo -iu nodeapp), and run source ~/.bashrc.
  • Your app stops after a reboot: make sure you ran the command printed by pm2 startup, and then pm2 save.
  • npm install fails with memory errors: the VPS may be short on RAM. Add swap space, or upgrade your VPS.

Need help?

Our Cloud VPS plans are self-managed, so you're responsible for installing, securing and maintaining the software on your server. If something on our side isn't working, such as the network, or your VPS won't boot, open a support ticket. New to your VPS? Start with our Cloud VPS Getting Started Guide.

Was this answer helpful? 0 Users Found This Useful (0 Votes)