How to Deploy a Node.js App on VPS
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
bashsudo 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
bashsudo adduser deploy sudo usermod -aG sudo deploy su - deploy
Step 2: Upload Your Application
Option A: Git Clone
bashcd ~ git clone https://github.com/yourusername/your-app.git cd your-app
Option B: SCP Upload
From your local machine:
bashscp -r ./your-app deploy@your_server_ip:~/
Install Dependencies
bashcd ~/your-app npm install --production
Step 3: Environment Configuration
Create Environment File
bashnano .env
Add your environment variables:
textNODE_ENV=production PORT=3000 DATABASE_URL=your_database_url SECRET_KEY=your_secret_key
Secure the File
bashchmod 600 .env
Step 4: Process Management with PM2
PM2 keeps your app running and restarts it on crashes.
Install PM2
bashsudo npm install -g pm2
Start Your Application
bashpm2 start app.js --name "my-app" # Or with npm script pm2 start npm --name "my-app" -- start
PM2 Configuration File
Create ecosystem.config.js:
javascriptmodule.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:
bashpm2 start ecosystem.config.js --env production
Auto-Start on Reboot
bashpm2 startup pm2 save
Useful PM2 Commands
bashpm2 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
bashsudo apt install nginx
Configure Nginx
Create configuration file:
bashsudo nano /etc/nginx/sites-available/my-app
Add configuration:
nginxserver { 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
bashsudo ln -s /etc/nginx/sites-available/my-app /etc/nginx/sites-enabled/ sudo nginx -t sudo systemctl restart nginx
Configure Firewall
bashsudo ufw allow 'Nginx Full' sudo ufw delete allow 'Nginx HTTP' # After SSL setup
Step 6: SSL Certificate with Let's Encrypt
Install Certbot
bashsudo apt install certbot python3-certbot-nginx
Obtain Certificate
bashsudo certbot --nginx -d yourdomain.com -d www.yourdomain.com
Auto-Renewal
Certbot sets up auto-renewal automatically. Test it:
bashsudo certbot renew --dry-run
Step 7: Optimize for Production
Nginx Optimizations
Add to /etc/nginx/nginx.conf:
nginxhttp { # 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
bashpm2 monit
Application Logs
bashpm2 logs my-app --lines 100
System Resources
bashhtop
Step 9: Deployment Workflow
Manual Deployment
bashcd ~/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:
bashchmod +x deploy.sh
Troubleshooting
App Not Starting
Check PM2 logs:
bashpm2 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.
Deploy on HeavenCloud
Discord bots, Lavalink nodes, and VPS, instant setup with NVMe and DDoS protection.