How to Deploy a Node.js App on VPS

14 min readBy Manas, HeavenCloud

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

bash
sudo apt update && sudo apt upgrade -y

Install Node.js

bash
# 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

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

Step 2: Upload Your Application

Option A: Git Clone

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

Option B: SCP Upload

From your local machine:

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

Install Dependencies

bash
cd ~/your-app
npm install --production

Step 3: Environment Configuration

Create Environment File

bash
nano .env

Add your environment variables:

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

Secure the File

bash
chmod 600 .env

Step 4: Process Management with PM2

PM2 keeps your app running and restarts it on crashes.

Install PM2

bash
sudo npm install -g pm2

Start Your Application

bash
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:

javascript
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:

bash
pm2 start ecosystem.config.js --env production

Auto-Start on Reboot

bash
pm2 startup
pm2 save

Useful PM2 Commands

bash
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

bash
sudo apt install nginx

Configure Nginx

Create configuration file:

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

Add configuration:

nginx
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

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

Configure Firewall

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

Step 6: SSL Certificate with Let's Encrypt

Install Certbot

bash
sudo apt install certbot python3-certbot-nginx

Obtain Certificate

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

Auto-Renewal

Certbot sets up auto-renewal automatically. Test it:

bash
sudo certbot renew --dry-run

Step 7: Optimize for Production

Nginx Optimizations

Add to /etc/nginx/nginx.conf:

nginx
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:

javascript
// 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

bash
pm2 monit

Application Logs

bash
pm2 logs my-app --lines 100

System Resources

bash
htop

Step 9: Deployment Workflow

Manual Deployment

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

Deployment Script

Create deploy.sh:

bash
#!/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:

bash
chmod +x deploy.sh

Troubleshooting

App Not Starting

Check PM2 logs:

bash
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.

  • Free 24/7 bot hosting
  • No credit card needed
  • Deploy in minutes
  • 12-hour money-back guarantee
  • DDoS protection included
  • Paid plans from ₹20/mo

Ready to host on the fastest cloud?

Launch a Discord bot, Lavalink node, game server or VPS in minutes. Start with free 24/7 bot hosting, no credit card needed. Questions? Our team answers 24/7 on Discord.