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
sudooff 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 appspm2 logs myapp: follow your app's logspm2 restart myapp: restart after you change your codepm2 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 upgradeorsudo 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 withnpm install -g pm2, then runpm2 updateandpm2 startupagain. - Your app's packages: run
npm outdatedto see what's out of date, andnpm auditto 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 thesetseboolcommand. - "node: command not found": if you used nvm, make sure you're logged in as the app user (
sudo -iu nodeapp), and runsource ~/.bashrc. - Your app stops after a reboot: make sure you ran the command printed by
pm2 startup, and thenpm2 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.







