This post contains affiliate links. If you purchase through our links, we may earn a commission at no extra cost to you.
Deploy Node.js on Vultr VPS: Step-by-Step Guide 2026
Most Node.js deployment guides you’ll find online target Ubuntu 20.04 with a Node version that was already outdated two years ago. This one doesn’t. I set this stack up on a fresh Vultr instance in June 2026 — Ubuntu 24.04 LTS, Node.js 22 LTS, nvm v0.40.4, PM2 in cluster mode, Nginx reverse proxy, and a free Let’s Encrypt SSL certificate. The whole process takes about 30 minutes. Here’s the exact sequence of commands that worked.

Why Vultr for Node.js Deployment
Not all $6/month VPS plans are the same. Vultr’s High Performance tier at that price gives you a 1 vCPU / 1 GB RAM / 25 GB NVMe SSD with 2 TB bandwidth — NVMe being the critical difference. In benchmarks, Vultr’s High Performance single-core Geekbench 6 score comes in at 1,926 versus DigitalOcean Basic’s 772. The disk IOPS comparison is similar: ~118,000 versus ~54,000 for DO at comparable pricing.
For a Node.js app, that disk speed matters more than it sounds. Every npm install, every app restart, every log write goes through that SSD. On a slow spinning disk or a low-IOPS SSD, those operations stack up in production.
Vultr New Vultr accounts currently get $100–$300 in promotional credits — enough to run the $6/month instance for months while you test and fine-tune your setup.
Which plan to pick:
| Plan | vCPU | RAM | Storage | Bandwidth | Monthly |
|---|---|---|---|---|---|
| Cloud Compute Regular | 1 | 1 GB | 25 GB SSD | 1 TB | $5/mo |
| High Performance (recommended) | 1 | 1 GB | 25 GB NVMe | 2 TB | $6/mo |
| High Performance | 1 | 2 GB | 55 GB NVMe | 2 TB | $12/mo |
| High Performance | 2 | 4 GB | 100 GB NVMe | 3 TB | $24/mo |
Prices last verified: June 2026. Source: Vultr via CostBench.
The $6/month High Performance plan handles a small to medium Node.js app comfortably. If you’re running a database (PostgreSQL, MongoDB) on the same server, jump to the $12/month 2 GB RAM plan — 1 GB gets tight fast when Node.js and a database are sharing memory.
Vultr isn’t the right pick if you want a managed database or a PaaS-style deployment experience. For that, DigitalOcean’s App Platform or their managed databases are cleaner. But if you want raw VPS control at a competitive price and you’re comfortable with the command line, Vultr wins on compute.
Step 1 — Create Your Vultr Server
Log into my.vultr.com and go to Products → Compute → Deploy Server.
Settings to choose:
- Server type: Cloud Compute or High Performance (choose High Performance for NVMe)
- Region: Closest to your target users — Vultr has 32 datacenters across the Americas, Europe, Asia, and Australia
- OS: Ubuntu 24.04 LTS — do NOT choose the Marketplace “Node.js” app; it ships with an outdated Node version
- Plan: $6/month (1 vCPU, 1 GB RAM, 25 GB NVMe)
- SSH key: Add your public key here — skip password login entirely
- IPv6: Enable it (no cost, useful for future-proofing)
Click Deploy Now. The server is ready in under 60 seconds.

Step 2 — Initial Server Setup
SSH in and create a non-root deploy user before touching anything else. Running your app as root is a security liability — if the process is ever compromised, the attacker has full system access.
# Connect as root
ssh root@YOUR_SERVER_IP
# Create a non-root user
adduser deploy
usermod -aG sudo deploy
# Switch to the deploy user
su - deploy
Now harden SSH while you still have root access. Edit /etc/ssh/sshd_config and set:
PermitRootLogin no
PasswordAuthentication no
Then restart SSH:
sudo systemctl restart sshd
Don’t skip this step. Password-based SSH on a public IP gets brute-forced within hours.
Step 3 — Install Node.js 22 LTS via nvm
Do not use the nodejs package from Ubuntu’s default apt repository. On Ubuntu 24.04, the apt version lags by multiple major versions. Use nvm instead — it lets you switch Node versions per-project and always pulls the latest LTS.
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.4/install.sh | bash
source ~/.bashrc
nvm install 22
nvm alias default 22
node --version # Expected: v22.x.x
npm --version # Expected: 10.x.x
If you need a system-wide Node.js install (for services that run outside the deploy user context), use the NodeSource repository instead:
sudo apt update && sudo apt install -y curl gnupg
curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash -
sudo apt install -y nodejs
node --version # v22.22.1
Both methods work on Ubuntu 24.04. I prefer nvm for personal deployments because it’s easier to upgrade later.
Step 4 — Deploy Your Application
Clone your repo and install dependencies. Using npm ci instead of npm install is the right call for production — it installs exactly what’s in package-lock.json and errors if there’s a mismatch, preventing version drift.
sudo apt install -y git
cd ~
git clone https://github.com/yourusername/your-app.git
cd your-app
# Install exact versions from lockfile (production only)
npm ci --production
# Set up environment variables
nano .env
# Add: NODE_ENV=production, PORT=3000, DATABASE_URL=..., etc.
Make sure .env is in your .gitignore. Never commit credentials to your repository.
Step 5 — Run Your App with PM2
PM2 is the standard process manager for Node.js in production. Two things make it essential: cluster mode (uses all CPU cores) and pm2 startup (keeps your app alive after a server reboot).
The production-grade way to configure PM2 is with an ecosystem.config.js file:
You can generate an ecosystem.config.js file for your exact setup (cluster/fork mode, env vars, memory limits) instead of writing it by hand.
npm install -g pm2
nano ecosystem.config.js
module.exports = {
apps: [{
name: "my-node-app",
script: "./src/index.js",
instances: "max", // uses all CPU cores
exec_mode: "cluster", // load balancing across instances
env: {
NODE_ENV: "production",
PORT: 3000
},
max_memory_restart: "500M",
log_date_format: "YYYY-MM-DD HH:mm:ss Z",
error_file: "./logs/error.log",
out_file: "./logs/output.log",
merge_logs: true,
watch: false,
autorestart: true,
max_restarts: 10,
restart_delay: 4000
}]
};
# Start your app
pm2 start ecosystem.config.js
# Set up auto-start on reboot
pm2 startup systemd
# Copy and run the command that PM2 outputs (it looks like: sudo env PATH=...)
pm2 save
# Verify everything is running
pm2 list
pm2 logs my-node-app
The instances: "max" setting puts cluster mode to work. On the $6/month plan with 1 vCPU, you get one instance — but if you later upgrade to a 2+ vCPU plan, PM2 automatically spins up additional workers without any config change.

Step 6 — Configure Nginx as a Reverse Proxy
Node.js on port 3000 shouldn’t face the internet directly. Nginx sits in front of it, handles SSL termination, serves static files efficiently, and adds security headers. This is the standard production pattern.
sudo apt install -y nginx
sudo nano /etc/nginx/sites-available/my-node-app
Paste this config (replace yourdomain.com with your actual domain):
upstream nodejs_backend {
server 127.0.0.1:3000;
keepalive 64;
}
server {
listen 80;
listen [::]:80;
server_name yourdomain.com www.yourdomain.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
server_name yourdomain.com www.yourdomain.com;
ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;
# Security headers
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
location / {
proxy_pass http://nodejs_backend;
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;
proxy_cache_bypass $http_upgrade;
}
# Serve static files directly (better performance)
location /static/ {
alias /home/deploy/your-app/public/static/;
expires 30d;
add_header Cache-Control "public, immutable";
}
}
💡 Tip: Want a head start on the config? Our free Nginx Config Generator builds a working server block you can adapt to your setup.
# Enable the site
sudo ln -s /etc/nginx/sites-available/my-node-app /etc/nginx/sites-enabled/
# Test the config before reloading
sudo nginx -t
# Reload Nginx
sudo systemctl reload nginx
The keepalive 64 in the upstream block keeps persistent connections between Nginx and your Node.js process, reducing connection overhead under load.
Step 7 — SSL Certificate with Certbot
Free SSL from Let’s Encrypt, automatically renewed. Certbot configures a systemd timer that handles renewal before the 90-day certificate expiry — you set it up once and forget it.
sudo apt install -y certbot python3-certbot-nginx
# Obtain certificate and auto-configure Nginx
sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com
# Test that auto-renewal works
sudo certbot renew --dry-run
Certbot edits your Nginx config to point to the certificate files automatically. If the --dry-run passes without errors, you’re set.
Note: Some guides use the snap version of Certbot (sudo snap install --classic certbot). Both work on Ubuntu 24.04. The apt version is simpler to install; the snap version always has the latest Certbot release directly from EFF. Either is fine.
Step 8 — Firewall Setup
Block everything except SSH, HTTP, and HTTPS. Critically, block port 3000 so Node.js is only accessible through Nginx — never directly from the internet.
sudo ufw default deny incoming
sudo ufw default allow outgoing
# Allow SSH before enabling UFW (or you'll lock yourself out)
sudo ufw allow ssh
# Allow web traffic
sudo ufw allow 'Nginx Full' # opens ports 80 and 443
# Block direct access to Node.js
sudo ufw deny 3000
# Enable and verify
sudo ufw enable
sudo ufw status
💡 Tip: Prefer a visual approach? You can build these rules with our free Firewall Rule Builder — it generates ufw and iptables commands right in your browser.
Vultr also has a cloud-level firewall (Firewall Groups in the dashboard) that filters traffic before it reaches your server. Using both layers gives you defense-in-depth — the cloud firewall blocks threats before they consume server resources.
Step 9 — Zero-Downtime Updates and Log Rotation
Two things you need to get right before you consider this setup production-ready.
Zero-downtime deploys: Use pm2 reload instead of pm2 restart. The difference is significant — restart kills all instances simultaneously (brief downtime), while reload cycles them one at a time with the new code, maintaining availability throughout.
cd ~/your-app
git pull origin main
npm ci --production
pm2 reload my-node-app
Log rotation: PM2 logs accumulate indefinitely. On a 25 GB SSD, that can become a problem. Install pm2-logrotate:
pm2 install pm2-logrotate
pm2 set pm2-logrotate:max_size 50M
pm2 set pm2-logrotate:retain 14
pm2 set pm2-logrotate:compress true
pm2 save
This keeps 14 days of logs, rotates at 50 MB, and compresses old files. A minor configuration step that prevents a painful “disk full” incident at 3am.

PM2 Command Reference
| Command | What it does |
|---|---|
pm2 list |
Show all running processes |
pm2 logs my-node-app |
Stream application logs |
pm2 monit |
Real-time monitoring dashboard |
pm2 reload my-node-app |
Zero-downtime reload (one instance at a time) |
pm2 restart my-node-app |
Hard restart (brief downtime) |
pm2 stop my-node-app |
Stop the process |
pm2 scale my-node-app 4 |
Change number of running instances |
pm2 save |
Persist current process list for reboot |
Alternatives to Vultr for Node.js Hosting
If Vultr doesn’t fit your situation, here are the honest alternatives:
| Provider | Entry Price | NVMe | Best For |
|---|---|---|---|
| Vultr | $6/mo | Yes | Performance, global reach, control |
| DigitalOcean | $6/mo | Yes | Managed databases, cleaner UI, App Platform |
| Hetzner | ~$4/mo | Yes | Europe-based workloads, extreme price/performance |
| Linode/Akamai | $5/mo | Yes | Established US presence, solid documentation |
| Hostinger VPS | $4.99/mo | Yes | Budget-conscious, beginner-friendly panel |
DigitalOcean is the better pick if you want managed PostgreSQL or MySQL without running a separate database server — their managed database add-on is genuinely convenient. Hetzner beats Vultr on raw price-per-resource, but their US region coverage is thinner. For US-primary workloads, Vultr’s footprint makes more sense.
FAQ
Can I run a Node.js app on Vultr’s $6/month plan?
Yes. The High Performance 1 vCPU / 1 GB RAM plan at $6/month handles small to medium Node.js apps well, especially in PM2 cluster mode. If you add a database on the same server, upgrade to the 2 GB RAM plan ($12/month) — the memory headroom makes a real difference.
Do I need Nginx if I’m just testing?
No. For local testing or a quick staging environment, you can hit your Node.js app directly on port 3000 (http://YOUR_IP:3000). But for any production setup with a domain and real users, Nginx handles SSL termination, security headers, and static file serving much more efficiently than Node.js alone.
What version of Node.js should I install on Ubuntu 24.04?
Node.js 22 LTS, installed via nvm (v0.40.4 as of June 2026) or the NodeSource repository. The default nodejs package in Ubuntu’s apt repository is often several major versions behind — in testing on Ubuntu 24.04 fresh installs, it can lag by 4+ major releases.
How does PM2 cluster mode work on a single-core VPS?
On a single vCPU plan, PM2 runs one instance (since there’s one core). The benefit is the autorestart behavior and pm2 startup integration — your app restarts automatically after crashes and survives server reboots. The multi-core benefits kick in when you upgrade to a 2+ vCPU plan, where PM2 spawns one worker per core.
Is Let’s Encrypt SSL free on Vultr?
Yes — SSL certificates from Let’s Encrypt are always free, regardless of host. Certbot is the tool that automates obtaining and renewing them. On Vultr you follow the same Certbot steps as on any Ubuntu server.
Final Verdict
The stack you’ve just built — nvm + Node.js 22 + PM2 cluster mode + Nginx + Certbot — is what most experienced Node.js developers run in production on budget VPS. It’s not over-engineered (no Docker, no Kubernetes), and it scales reasonably until you’re dealing with serious traffic that warrants something more complex.
Vultr Start on Vultr’s $6/month High Performance plan. If you’re deploying your first Node.js app to production, this setup gives you a solid foundation that’s been proven across thousands of deployments. New accounts get $100–$300 in free credits, so you can test and iterate without paying until you’re ready to commit.
When your app grows and you need a database layer, check out our Vultr setup guide for WordPress if you’re running multiple services on the same server — the Nginx multi-site configuration patterns carry over directly.
If you find yourself spending more time managing infrastructure than building features, DigitalOcean’s App Platform or Railway might be worth the price premium. But for a straightforward Node.js app where you want server-level control at a reasonable cost, this is the right setup.

