Runtime
Production
Deploy Node.js Applications on a VPS
Production-ready Node.js deployment with PM2 process management, Nginx reverse proxy, SSL encryption, cluster mode, and git-based deployment workflows.
At a Glance
| Runtime | Node.js 22 LTS |
| Process Manager | PM2 |
| Recommended Plan | RamNode Cloud VPS 1 GB+ (2 GB for production) |
| OS | Ubuntu 22.04 or 24.04 LTS |
| Stack | Node.js, PM2, Nginx, Let's Encrypt |
| Estimated Setup Time | 20–30 minutes |
Prerequisites
- A RamNode VPS running Ubuntu 22.04 or 24.04 (1 GB RAM minimum; 2 GB recommended)
- Root or sudo access via SSH
- A registered domain name (optional, but required for SSL)
1
Initial Server Setup
Create a non-root user
adduser deploy
usermod -aG sudo deploy
rsync --archive --chown=deploy:deploy ~/.ssh /home/deployUpdate and configure firewall
sudo apt update && sudo apt upgrade -y
sudo ufw allow OpenSSH
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable2
Install Node.js
Option A: NodeSource (Recommended)
Install Node.js 22 LTS
curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash -
sudo apt install -y nodejs
node -v && npm -vOption B: nvm (Multi-Version)
Install via nvm
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash
source ~/.bashrc
nvm install 22
nvm use 22Install build tools
sudo apt install -y build-essential3
Deploy a Sample Application
Create an Express app
mkdir -p /home/deploy/apps/hello-api
cd /home/deploy/apps/hello-api
npm init -y
npm install expressapp.js
const express = require('express');
const app = express();
const PORT = process.env.PORT || 3000;
app.use(express.json());
app.get('/', (req, res) => {
res.json({ message: 'Hello from RamNode!', timestamp: new Date().toISOString() });
});
app.get('/health', (req, res) => {
res.json({ status: 'ok', uptime: process.uptime() });
});
app.listen(PORT, '127.0.0.1', () => {
console.log(`Server running on port ${PORT}`);
});Note: Binding to 127.0.0.1 prevents direct internet access — Nginx will proxy external traffic.
4
Process Management with PM2
Install and start
sudo npm install -g pm2
cd /home/deploy/apps/hello-api
pm2 start app.js --name hello-apiEssential PM2 commands
pm2 list # View running processes
pm2 monit # Monitor CPU/memory
pm2 logs hello-api # View app logs
pm2 restart hello-api # Restart appAuto-start on boot
pm2 startup systemd
# Copy and run the outputted command with sudo
pm2 saveEcosystem File for Multiple Apps
ecosystem.config.js
module.exports = {
apps: [
{
name: 'hello-api',
script: './hello-api/app.js',
cwd: '/home/deploy/apps',
instances: 1,
env: { NODE_ENV: 'production', PORT: 3000 }
},
{
name: 'task-api',
script: './task-api/app.js',
cwd: '/home/deploy/apps',
instances: 'max',
exec_mode: 'cluster',
env: { NODE_ENV: 'production', PORT: 3001 }
}
]
};5
Install and Configure Nginx
Install Nginx
sudo apt install -y nginx
sudo systemctl start nginx
sudo systemctl enable nginxReverse proxy config
server {
listen 80;
server_name yourdomain.com;
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;
proxy_cache_bypass $http_upgrade;
}
}Enable site
sudo ln -s /etc/nginx/sites-available/hello-api /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx6
SSL with Let's Encrypt
Install Certbot and get certificate
sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d yourdomain.comVerify auto-renewal
sudo systemctl status certbot.timer
sudo certbot renew --dry-run7
Nginx Performance Tuning
Gzip compression (nginx.conf http block)
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
gzip_min_length 256;Rate limiting (nginx.conf http block)
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s;Apply with limit_req zone=api_limit burst=20 nodelay; in your location block.
8
Git-Based Deployment Workflow
Set up bare repo on server
mkdir -p /home/deploy/repos/hello-api.git
cd /home/deploy/repos/hello-api.git
git init --barepost-receive hook
#!/bin/bash
APP_DIR=/home/deploy/apps/hello-api
GIT_DIR=/home/deploy/repos/hello-api.git
echo "Deploying hello-api..."
git --work-tree=$APP_DIR --git-dir=$GIT_DIR checkout -f
cd $APP_DIR
npm install --production
pm2 restart hello-api
echo "Deployment complete."Make executable and deploy
chmod +x /home/deploy/repos/hello-api.git/hooks/post-receive
# On your local machine:
git remote add production deploy@your-server-ip:/home/deploy/repos/hello-api.git
git push production main9
Monitoring and Logging
PM2 log rotation
pm2 install pm2-logrotate
pm2 set pm2-logrotate:max_size 10M
pm2 set pm2-logrotate:retain 7Nginx logs: /var/log/nginx/access.log and /var/log/nginx/error.log
10
Security Hardening
Disable root SSH and password auth
# /etc/ssh/sshd_config
PermitRootLogin no
PasswordAuthentication noInstall Fail2Ban and auto-updates
sudo systemctl restart sshd
sudo apt install -y fail2ban
sudo systemctl enable fail2ban
sudo systemctl start fail2ban
sudo apt install -y unattended-upgrades
sudo dpkg-reconfigure -plow unattended-upgradesTip: Add server_tokens off; to Nginx's http block to hide the version.
Troubleshooting
- App not responding after reboot: Run
pm2 resurrect - 502 Bad Gateway: Check
pm2 listand verify port matches Nginx proxy_pass - EADDRINUSE: Find the conflicting process with
sudo lsof -i :3000 - Certbot fails: Ensure DNS A record points to VPS IP and ports 80/443 are open
