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.