Tutorials

How to Deploy a Node.js App on VPS

February 18, 2026
14 min read read
M
Manas

Deploying a Node.js application to production requires more than just running node app.js. This guide covers everything from initial setup to a production-ready deployment with process management, reverse proxy, and SSL.

Prerequisites

  • VPS with Ubuntu 22.04
  • Domain name (optional but recommended)
  • Basic Linux command line knowledge
  • Node.js application ready to deploy

Step 1: Server Setup

Update System

sudo apt update && sudo apt upgrade -y

Install Node.js

# Install Node.js 20.x LTS
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt install -y nodejs

# Verify installation
node --version
npm --version

Create Deploy User

sudo adduser deploy
sudo usermod -aG sudo deploy
su - deploy

Step 2: Upload Your Application

Option A: Git Clone

cd ~
git clone https://github.com/yourusername/your-app.git
cd your-app

Option B: SCP Upload

From your local machine:

scp -r ./your-app deploy@your_server_ip:~/

Install Dependencies

cd ~/your-app
npm install --production

Step 3: Environment Configuration

Create Environment File

nano .env

Add your environment variables:

NODE_ENV=production
PORT=3000
DATABASE_URL=your_database_url
SECRET_KEY=your_secret_key

Secure the File

chmod 600 .env

Step 4: Process Management with PM2

PM2 keeps your app running and restarts it on crashes.

Install PM2

sudo npm install -g pm2

Start Your Application

pm2 start app.js --name "my-app"

# Or with npm script
pm2 start npm --name "my-app" -- start

PM2 Configuration File

Create ecosystem.config.js:

module.exports = {
  apps: [{
    name: 'my-app',
    script: 'app.js',
    instances: 'max',
    exec_mode: 'cluster',
    env: {
      NODE_ENV: 'development'
    },
    env_production: {
      NODE_ENV: 'production'
    }
  }]
};

Start with config:

pm2 start ecosystem.config.js --env production

Auto-Start on Reboot

pm2 startup
pm2 save

Useful PM2 Commands

pm2 list              # List all processes
pm2 logs my-app       # View logs
pm2 monit             # Monitor resources
pm2 restart my-app    # Restart app
pm2 stop my-app       # Stop app
pm2 delete my-app     # Remove from PM2

Step 5: Nginx Reverse Proxy

Nginx handles incoming requests and forwards them to your Node.js app.

Install Nginx

sudo apt install nginx

Configure Nginx

Create configuration file:

sudo nano /etc/nginx/sites-available/my-app

Add configuration:

server {
    listen 80;
    server_name yourdomain.com www.yourdomain.com;

    location / {
        proxy_pass http://localhost: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 Configuration

sudo ln -s /etc/nginx/sites-available/my-app /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl restart nginx

Configure Firewall

sudo ufw allow 'Nginx Full'
sudo ufw delete allow 'Nginx HTTP'  # After SSL setup

Step 6: SSL Certificate with Let's Encrypt

Install Certbot

sudo apt install certbot python3-certbot-nginx

Obtain Certificate

sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com

Auto-Renewal

Certbot sets up auto-renewal automatically. Test it:

sudo certbot renew --dry-run

Step 7: Optimize for Production

Nginx Optimizations

Add to /etc/nginx/nginx.conf:

http {
    # Gzip compression
    gzip on;
    gzip_vary on;
    gzip_min_length 1024;
    gzip_types text/plain text/css application/json application/javascript text/xml application/xml;

    # Connection settings
    keepalive_timeout 65;
    client_max_body_size 10M;
}

Node.js Optimizations

In your app, ensure:

// Trust proxy for correct IP detection
app.set('trust proxy', 1);

// Helmet for security headers
const helmet = require('helmet');
app.use(helmet());

// Compression
const compression = require('compression');
app.use(compression());

Step 8: Monitoring

PM2 Monitoring

pm2 monit

Application Logs

pm2 logs my-app --lines 100

System Resources

htop

Step 9: Deployment Workflow

Manual Deployment

cd ~/your-app
git pull origin main
npm install --production
pm2 restart my-app

Deployment Script

Create deploy.sh:

#!/bin/bash
cd ~/your-app
git pull origin main
npm install --production
npm run build  # If you have a build step
pm2 restart my-app
echo "Deployment complete!"

Make executable:

chmod +x deploy.sh

Troubleshooting

App Not Starting

Check PM2 logs:

pm2 logs my-app --err

502 Bad Gateway

  • Check if Node.js app is running: pm2 list
  • Check Nginx error logs: sudo tail -f /var/log/nginx/error.log
  • Verify port configuration matches

High Memory Usage

  • Check for memory leaks
  • Consider using PM2 cluster mode
  • Implement proper garbage collection

SSL Issues

  • Verify certificate: sudo certbot certificates
  • Check Nginx SSL config
  • Ensure firewall allows HTTPS

Security Checklist

  • [ ] Environment variables secured
  • [ ] Non-root user for app
  • [ ] Firewall configured
  • [ ] SSL enabled
  • [ ] Security headers set
  • [ ] Rate limiting configured
  • [ ] Input validation in app

Conclusion

Your Node.js application is now running in production with:

  • PM2 for process management
  • Nginx as reverse proxy
  • SSL for secure connections
  • Auto-restart on crashes and reboots

HeavenCloud VPS provides the perfect infrastructure for Node.js deployments with fast NVMe storage, reliable uptime, and easy scaling options.

Need Lavalink for production?

Managed v4 on HeavenCloud — multi-region nodes, 24h trial, live audio test on this site.