Blog
4 min read

How to Deploy a Node.js App to a VPS, Step by Step

From an empty Ubuntu server to your Node.js app running on your own domain with HTTPS: create a user, install Node, clone and build, keep it running with PM2 or systemd, put Caddy or Nginx in front, and set up redeploys.

A VPS gives you a whole Linux server for a few dollars a month. (What is a VPS?) Getting a Node.js app running on it properly takes about an hour the first time. Here's the whole path, from empty server to your app on https://yourdomain.com.

We'll assume Ubuntu, a Node app that starts with npm start and listens on a port, and a domain you control.

1. Secure the server first

Log in as root, create your own user, and set up SSH keys:

ssh root@YOUR_SERVER_IP
adduser deploy
usermod -aG sudo deploy
rsync --archive --chown=deploy:deploy ~/.ssh /home/deploy

Then log in as deploy, disable password logins, and turn on the firewall. Our guide to securing a new VPS covers each step; the short version for the firewall:

sudo ufw allow OpenSSH
sudo ufw allow 80,443/tcp
sudo ufw enable

(UFW firewall basics)

2. Install Node.js

Use the current LTS version, from NodeSource or a version manager rather than Ubuntu's often-outdated package:

curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo -E bash -
sudo apt install -y nodejs git
node -v

3. Get your code onto the server

git clone https://github.com/you/your-app.git ~/app
cd ~/app
npm ci
npm run build    # if your app has a build step

For private repos, add a deploy key or use gh auth login. (Permission denied (publickey))

4. Set environment variables

Create ~/app/.env with your production values (database URL, API keys), and make sure it's readable only by you:

chmod 600 .env

Your app needs to load it — node --env-file=.env or dotenv. (Environment variables explained)

Make the app listen on a port on localhost, e.g. 3000. The reverse proxy will be the only thing facing the internet.

5. Keep it running

If you run npm start and close the terminal, the app stops. You need a process manager that starts it on boot and restarts it on crashes. Two good options (PM2 vs systemd):

PM2:

sudo npm install -g pm2
pm2 start npm --name app -- start
pm2 save
pm2 startup   # follow the command it prints

systemd — create /etc/systemd/system/app.service:

[Unit]
Description=My app
After=network.target

[Service]
User=deploy
WorkingDirectory=/home/deploy/app
ExecStart=/usr/bin/node --env-file=.env dist/server.js
Restart=always
Environment=NODE_ENV=production

[Install]
WantedBy=multi-user.target
sudo systemctl enable --now app

Check it: curl http://127.0.0.1:3000.

6. Point your domain at the server

At your DNS provider, create an A record for yourdomain.com (and www) pointing at the server's IP. (DNS records explained)

7. Add a reverse proxy with HTTPS

Caddy is the shortest path, because it gets and renews certificates automatically:

sudo apt install -y caddy

/etc/caddy/Caddyfile:

yourdomain.com, www.yourdomain.com {
    reverse_proxy 127.0.0.1:3000
}
sudo systemctl reload caddy

Visit https://yourdomain.com. (Prefer Nginx? See what is Nginx? — you'll add certbot for certificates.)

8. Redeploying

A simple deploy script on the server:

#!/usr/bin/env bash
set -euo pipefail
cd ~/app
git pull --ff-only
npm ci
npm run build
pm2 reload app     # or: sudo systemctl restart app

(Bash scripting for beginners) Later you can trigger it automatically from GitHub Actions on every push. (Deploy to a VPS with GitHub Actions)

What you're now responsible for

This is the trade-off of a VPS: it's cheap and flexible, but you own the upkeep.

The summary

  • Secure first: your own user, SSH keys, firewall.
  • Install Node LTS, clone, install, build.
  • Keep it running with PM2 or systemd, listening on localhost.
  • Point DNS at the server; put Caddy (or Nginx) in front for HTTPS.
  • Script your redeploys, and plan for updates, backups and monitoring.

Rather skip the server chores? EasySpawn gives you a dedicated server where the OS, patching, SSL and backups are handled, and Claude Code can deploy your Node app for you. See how it works or join the waitlist.

Related: What Is a VPS? · VPS vs PaaS · PM2 vs systemd · Reverse Proxies Explained

Keep reading