Tutorials

How to Deploy a Node.js App on VPS

February 19, 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.

Start building your community

Deploy high-performance Discord bots, Lavalink nodes, and VPS servers with instant setup on HeavenCloud.