Hook: why this stack matters
If you’ve built a Node.js app and want it to run reliably in production, you need more than node app.js and crossed fingers. Using Linux + Nginx + PM2 is a pragmatic stack that gives you stability (Linux), performance and SSL termination (Nginx), and automatic process management with monitoring (PM2). This article walks you through the rationale and a concise, practical path to deploy a real app quickly.
Context: the problem most developers face
New apps fail in production for simple reasons: processes crash, ports are exposed, SSL is missing, or no one set up restarts for server reboots. You need a predictable deployment pattern that:
- Keeps the app running after crashes and reboots
- Hides internal ports from the public internet
- Handles HTTPS, static assets, and load spikes Nginx + PM2 on a Linux VPS solves all of these without heavy orchestration.
Solution overview
The high-level flow looks like this: Nginx listens on 80/443 and proxies to your Node process on an internal port (e.g., 3000). PM2 runs and monitors the Node process, restarts on failure, and can resurrect processes after reboot. Use a PM2 ecosystem file to version your process configuration. These are standard, well-supported tools and work on common distros such as Ubuntu and CentOS.
Quick checklist before you start
- Provision a Linux server (1–2 GB RAM is fine for small apps).
- SSH into the server and update packages.
- Install Node.js (NodeSource or nvm), Nginx, and PM2.
- Ensure DNS points your domain to the server before issuing SSL.
- Keep your code and ecosystem config in git.
Implementation: essential steps (short and actionable)
- Install Node.js (NodeSource or nvm) and verify node -v and npm -v are correct. If you plan multiple projects or versions, use nvm.
- Upload or git-clone your app to a dedicated folder (for example /home/youruser/my-app) and run npm install --production to install dependencies.
- Install PM2 globally and start your app with a friendly name: pm2 start app.js --name my-app. Then run pm2 startup and pm2 save so PM2 restarts on reboot.
- Install Nginx, create a server block that proxies requests to localhost:3000 (or whatever port your app uses), test nginx -t, and reload Nginx.
- Secure the site with Let’s Encrypt (certbot --nginx) to get free HTTPS and automatic renewals.
Notes: don’t expose your Node port to the public internet. Let Nginx handle incoming traffic and SSL.
PM2: make it repeatable
Use an ecosystem.config.js file to describe your app(s) and environment variables. With PM2 you can:
- Run multiple apps from one file
- Set NODE_ENV and PORT per environment
- Use clustering (instances: max) to use all CPU cores Start everything with pm2 start ecosystem.config.js --env production and save the state with pm2 save.
Best practice: avoid watch: true in production. Use CI to trigger restarts instead.
Nginx: reverse proxy basics and tips
Configure Nginx to proxy_pass to http://127.0.0.1:3000 and set common headers like X-Forwarded-For and Host. Keep these in mind:
- Test Nginx config with nginx -t before reloading.
- Use gzip and cache headers for static assets.
- Add basic security headers (X-Frame-Options, X-Content-Type-Options, X-XSS-Protection).
If you host multiple apps, create separate server blocks per domain and point each to its app’s internal port.
Security, monitoring and validation
- Firewall: enable UFW (Ubuntu) or firewalld (CentOS) and allow SSH and Nginx Full (ports 22, 80, 443).
- HTTPS: use certbot with the nginx plugin to automate cert issuance and renewal.
- Logs & monitoring: use pm2 logs and pm2 monit for quick checks. Install pm2-logrotate to avoid log growth.
- Load test lightly with ab or similar tools and watch pm2 monit, top/htop, and Nginx logs.
Quick best practices:
- Run Node under a non-root user.
- Never commit secrets; use environment variables or PM2 env blocks.
- Regularly run npm audit and keep dependencies updated.
Where to learn more and get help
If you want a ready reference and expanded explanations, check the full guide I used to base this concise workflow on at https://prateeksha.com/blog/deploy-nodejs-on-linux-server-nginx-pm2-beginner-guide. For company and services, see https://prateeksha.com and their blog at https://prateeksha.com/blog.
Conclusion
Deploying Node.js on Linux with Nginx and PM2 gives you a reliable, maintainable base without the complexity of Docker or orchestration. Start small: get Node + PM2 running, put Nginx in front, add HTTPS, and automate with an ecosystem file and CI later. That pattern will cover most production needs for indie projects, MVPs, and early-stage SaaS.
Top comments (0)