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
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.
Deploy on HeavenCloud
Discord bots, Lavalink nodes, and VPS, instant setup with NVMe and DDoS protection.