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
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.
- Security updates — enable
unattended-upgrades. - Backups — of the database and uploaded files, stored off the server. (Backups for beginners)
- Monitoring — know when it's down. (Know when your app is down)
- Disk space — logs grow. (No space left on device)
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
What Is Nginx? The Web Server in Front of Half the Internet
Nginx ("engine-x") is a web server that serves files, forwards requests to your app, handles HTTPS and balances load. What it does, what a basic config looks like, where the files live, the commands you'll need, and whether you need it at all.
What Is a VPS? Virtual Private Servers Explained for Beginners
A VPS is your own slice of a physical server, with its own operating system and full control. What a VPS is, how it compares with shared hosting, PaaS and dedicated servers, what you're responsible for when you run one, and when a managed server is the better fit.