Skip to main content

Command Palette

Search for a command to run...

πŸš€ Nginx Configuration for Node.js Apps (PM2 + Ubuntu)

Published
β€’3 min read
πŸš€ Nginx Configuration for Node.js Apps (PM2 + Ubuntu)
R

I am a Senior Software Engineer from India.

This article is a personal reference guide for configuring Nginx as a reverse proxy in front of a Node.js application managed by PM2 on Ubuntu.

It focuses on what actually matters in production.


🧠 Why Nginx?

Nginx sits between the internet and your Node app.

Responsibilities:

  • Accept public traffic (port 80 / 443)

  • Forward requests to Node (localhost)

  • Handle large payloads (PDFs, uploads)

  • Enable HTTPS

  • Improve security & stability

Node should not be directly exposed to the internet.


πŸ“¦ Install Nginx

sudo apt update
sudo apt install -y nginx

Verify:

systemctl status nginx

Test:

curl http://localhost

πŸ—‚ Nginx Directory Structure (Important)

/etc/nginx/
 β”œβ”€β”€ nginx.conf
 β”œβ”€β”€ sites-available/
 β”‚    └── my-app
 └── sites-enabled/
      └── my-app -> ../sites-available/my-app

Rule:

  • Write configs in sites-available

  • Enable them using a symlink in sites-enabled


πŸ”Ž Check Existing Configurations

ls /etc/nginx/sites-available
ls /etc/nginx/sites-enabled

View loaded configs:

sudo nginx -T

βš™οΈ Basic Reverse Proxy Configuration

Create a config file:

sudo nano /etc/nginx/sites-available/my-app
server {
    listen 80;
    server_name YOUR_DOMAIN_OR_IP;

    location / {
        proxy_pass http://127.0.0.1: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 the Site

sudo ln -s /etc/nginx/sites-available/my-app \
           /etc/nginx/sites-enabled/

Disable default site (recommended):

sudo rm /etc/nginx/sites-enabled/default

πŸ§ͺ Validate & Reload

sudo nginx -t
sudo systemctl reload nginx

🧠 Node.js Best Practice

Bind Node only to localhost:

app.listen(3000, "127.0.0.1");

This prevents direct external access.


πŸ“„ Handling Large Requests (PDFs, Uploads)

Add inside server {}:

client_max_body_size 50M;

proxy_connect_timeout 300;
proxy_send_timeout 300;
proxy_read_timeout 300;
send_timeout 300;

This avoids timeout failures for long-running tasks.


πŸ“Š Logs & Debugging

Nginx

sudo tail -f /var/log/nginx/access.log
sudo tail -f /var/log/nginx/error.log

Node (PM2)

pm2 logs my-app

πŸ” Enable HTTPS (Let’s Encrypt)

sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d yourdomain.com

Auto-renew test:

sudo certbot renew --dry-run

🧠 Production Checklist

βœ” Node running via PM2
βœ” App bound to localhost
βœ” Nginx reverse proxy enabled
βœ” Large payload support
βœ” HTTPS enabled
βœ” Auto-restart on reboot


🧯 Common Mistakes

  • ❌ Running Node on port 80

  • ❌ Exposing Node publicly

  • ❌ Installing OS packages via npm

  • ❌ Forgetting timeouts for long jobs

  • ❌ Editing nginx.conf directly


🏁 Final Thoughts

Nginx + PM2 is a battle-tested setup for Node.js apps.

Once configured properly:

  • Deployments are safer

  • Restarts are painless

  • Scaling is easier

  • Debugging is predictable

This setup has saved me hours during production incidents.