How To Run Node Js Server Nginx

Configure a production-ready reverse proxy for your Node.js application with Nginx, PM2, and SSL encryption.

Running a Node.js application directly in production exposes it to unnecessary risks and performance limitations. A reverse proxy like Nginx sits between your application and the internet, handling critical tasks that Node.js wasn't designed to manage alone.

This guide walks through the complete setup from Node.js process management with PM2 to production-ready Nginx configuration with HTTPS. For teams looking to build scalable web applications from the ground up, our web development services team can help architect production-ready infrastructure.

Why Use a Reverse Proxy with Node.js

Node.js excels at running application logic and handling asynchronous I/O operations, but it wasn't built to be a full-featured web server facing the public internet. A reverse proxy addresses this architectural gap by handling traffic management, security, and performance optimization separately from your application code.

Performance Benefits

Nginx provides significant performance improvements through several mechanisms:

  • Static file serving - Nginx serves images, CSS, and JavaScript far more efficiently than Node.js
  • SSL/TLS offloading - Encryption at the proxy level reduces CPU load on your Node.js application
  • Content caching and compression - Gzip/Brotli compression reduces bandwidth and speeds up delivery

Security Benefits

The reverse proxy architecture fundamentally improves security:

  • Infrastructure hiding - Your Node.js server's IP address remains hidden from direct exposure
  • Centralized security - Single hardened entry point for security rules and headers
  • Threat mitigation - Built-in rate limiting and malicious traffic blocking

Scalability Benefits

Scalability becomes straightforward with a reverse proxy:

  • Load balancing - Distribute traffic across multiple Node.js instances
  • Zero-downtime deployments - Update servers sequentially without service interruption
  • Automatic failover - Traffic routes to healthy instances when others fail
What You'll Learn

PM2 Setup

Configure PM2 process manager for production Node.js deployment with auto-restart capabilities

Nginx Installation

Install and configure Nginx as a reverse proxy with proper server blocks

SSL Certificates

Obtain free HTTPS certificates from Let's Encrypt with automatic renewal

Performance Tuning

Enable gzip compression, static file caching, and connection optimization

Load Balancing

Distribute traffic across multiple Node.js instances for scalability

Security Hardening

Implement rate limiting, security headers, and DDoS protection

Prerequisites and Initial Setup

Before installing any software, ensure your server environment meets the basic requirements:

  • Linux server - Ubuntu 22.04 recommended for stability
  • Domain name - With DNS A record pointing to your server's IP
  • Firewall configuration - Ports 22 (SSH), 80 (HTTP), and 443 (HTTPS) open

Server Requirements

# Verify your server has at least 1GB RAM and 1 CPU core
# Check available ports aren't blocked
sudo ufw status

Preparing Your Node.js Application

Your Node.js application should listen on localhost only, not exposed directly to the internet:

// Example: Basic Express server configured for reverse proxy
const app = express();
const server = app.listen(3000, '127.0.0.1', () => {
 console.log('Node.js app running on localhost:3000');
});

Important: The key configuration is binding to 127.0.0.1 instead of 0.0.0.0, ensuring your application is only accessible through the reverse proxy.

Managing Node.js with PM2

PM2 is a production-grade process manager for Node.js applications. It handles process supervision, automatic restarts on crashes, and log management.

Installing PM2

# Install PM2 globally
sudo npm install -g pm2

# Start your application with PM2
pm2 start app.js --name "my-node-app"

# Save the process list for automatic restart on reboot
pm2 save

# Setup PM2 startup script
pm2 startup

Essential PM2 Commands

# Check application status
pm2 status

# View application logs
pm2 logs my-node-app

# Restart application
pm2 restart my-node-app

# Stop application
pm2 stop my-node-app

# Monitor in real-time
pm2 monit

PM2 keeps your application running continuously, automatically restarting it if it crashes or if the server reboots. This is essential for production deployments.

Installing and Configuring Nginx

Installing Nginx

# Update package lists and install Nginx
sudo apt update
sudo apt install nginx

# Start and enable Nginx
sudo systemctl start nginx
sudo systemctl enable nginx

# Verify installation by accessing your server IP
# You should see the default Nginx welcome page

Creating Server Block Configuration

Create a configuration file for your Node.js application:

# /etc/nginx/sites-available/your-domain.com

server {
 listen 80;
 server_name your-domain.com www.your-domain.com;

 location / {
 proxy_pass http://127.0.0.1:3000;
 proxy_http_version 1.1;
 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;
 }
}

Key Configuration Directives

  • proxy_pass - Forwards requests to your Node.js application
  • proxy_set_header - Preserves original request headers
  • proxy_http_version 1.1 - Required for proper connection handling

Enabling the Configuration

# Test configuration for syntax errors
sudo nginx -t

# Enable the site by creating symbolic link
sudo ln -s /etc/nginx/sites-available/your-domain.com /etc/nginx/sites-enabled/

# Remove default site (optional but recommended)
sudo rm /etc/nginx/sites-enabled/default

# Reload Nginx to apply changes
sudo systemctl reload nginx

Handling Static Files Efficiently

Configure Nginx to serve static assets directly, bypassing Node.js entirely for better performance:

server {
 listen 80;
 server_name your-domain.com www.your-domain.com;

 # Static assets - served directly by Nginx
 location /static/ {
 alias /path/to/your/static/files/;
 expires 30d;
 add_header Cache-Control "public, immutable";
 }

 # API requests - forwarded to Node.js
 location /api/ {
 proxy_pass http://127.0.0.1:3000;
 proxy_http_version 1.1;
 proxy_set_header Host $host;
 proxy_set_header X-Real-IP $remote_addr;
 }

 # Everything else - forwarded to Node.js
 location / {
 proxy_pass http://127.0.0.1:3000;
 proxy_http_version 1.1;
 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;
 }
}

Static File Configuration Benefits

  • Performance: Nginx serves files from disk much faster than Node.js
  • Caching: Browser caching reduces repeated downloads
  • Bandwidth savings: Less traffic reaches your Node.js application

Securing with HTTPS (Let's Encrypt)

Why HTTPS Matters

HTTPS is essential for production applications. Modern browsers warn users about insecure connections, search engines penalize non-HTTPS sites, and encryption protects sensitive data transmission. Proper HTTPS implementation is a fundamental ranking factor for any professional web application.

Installing Certbot and Obtaining Certificates

# Install Certbot
sudo apt install certbot python3-certbot-nginx

# Obtain and configure SSL certificate
sudo certbot --nginx -d your-domain.com -d www.your-domain.com

Certbot automatically modifies your Nginx configuration to:

  • Serve HTTPS on port 443
  • Redirect HTTP to HTTPS
  • Configure strong SSL settings
  • Set up automatic certificate renewal

Automatic Renewal

# Verify Certbot timer is enabled
sudo systemctl status certbot.timer

# Test automatic renewal (dry run)
sudo certbot renew --dry-run

Let's Encrypt certificates are valid for 90 days. The Certbot timer ensures automatic renewal before expiration.

Performance Optimization

Gzip Compression

Add this to your Nginx configuration's http block:

gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_proxied any;
gzip_types text/plain text/css text/xml application/javascript
 application/json application/xml application/rss+xml;

Connection and Buffer Settings

# In nginx.conf - adjust based on your server resources
worker_processes auto;
worker_connections 1024;
keepalive_timeout 65;

# Client request settings
client_max_body_size 16M;
client_body_buffer_size 128k;

Rate Limiting

Protect your application from abuse:

# Define rate limit zone
limit_req_zone $binary_remote_addr zone=mylimit:10m rate=10r/s;

# Apply to location
location / {
 limit_req zone=mylimit burst=20;
 proxy_pass http://127.0.0.1:3000;
}

This allows 10 requests per second with a burst capacity of 20, blocking excessive requests.

Advanced: Load Balancing Multiple Node.js Instances

For high-traffic applications, distribute load across multiple Node.js instances:

# Define upstream with multiple Node.js servers
upstream nodejs_backends {
 least_conn; # Routes to server with fewest connections
 server 127.0.0.1:3000;
 server 127.0.0.1:3001;
 server 127.0.0.1:3002;
}

server {
 listen 80;
 server_name your-domain.com;

 location / {
 proxy_pass http://nodejs_backends;
 proxy_http_version 1.1;
 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;
 }
}

Load Balancing Methods

  • round-robin (default) - Distributes requests evenly
  • least_conn - Routes to server with fewest active connections
  • ip-hash - Same user always reaches same server (for WebSockets)

Starting Multiple PM2 Instances

# Start app on port 3000
pm2 start app.js --name "node-app-1" -- 3000

# Start app on port 3001
pm2 start app.js --name "node-app-2" -- 3001

# Start app on port 3002
pm2 start app.js --name "node-app-3" -- 3002

Common Issues and Troubleshooting

502 Bad Gateway Error

This indicates Nginx cannot connect to Node.js. Check that your Node.js app is running (pm2 status), verify the proxy_pass port matches your application port, and ensure the firewall allows connections between Nginx and Node.js.

Static Files Return 404

Check the alias path in your static file location block ends with a slash when referencing a directory. Verify file permissions allow Nginx to read the files (chmod 755 on directories, 644 on files).

SSL Certificate Renewal Failed

Verify DNS A records point to the correct IP address. Check that ports 80 and 443 are open. Run 'sudo certbot renew --dry-run' to diagnose issues before attempting actual renewal.

WebSocket Connections Fail

WebSockets require special headers. Include these directives in your location block: proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_http_version 1.1;

Testing and Verification

Checking Configuration

# Always test before reloading
sudo nginx -t

# Expected output:
# nginx: the configuration file syntax is ok
# nginx: configuration file /etc/nginx/nginx.conf test is successful

Verifying Traffic Flow

# Test from local machine
curl -I http://your-domain.com

# Check response headers
curl -v http://your-domain.com

# View Nginx access logs
sudo tail -f /var/log/nginx/access.log

# View Nginx error logs
sudo tail -f /var/log/nginx/error.log

Performance Testing

# Install load testing tool
sudo apt install hey

# Run simple load test
hey -n 1000 -c 10 http://your-domain.com

Compare response times with and without Nginx as the reverse proxy to measure the performance improvement.

Conclusion

Setting up Nginx as a reverse proxy for your Node.js application transforms it from a development-ready demo into a production-ready service:

  • Performance: Static file serving, SSL offloading, and caching make your application faster
  • Security: Infrastructure hiding, centralized security controls, and DDoS protection
  • Scalability: Load balancing and zero-downtime deployments prepare for growth

Start with a basic configuration, then progressively add optimizations as you monitor your application's needs. The investment in proper infrastructure setup pays dividends throughout your application's lifecycle. For teams building complex applications, our web development services team can handle the entire production infrastructure setup.


Sources:

Need Help Setting Up Your Production Infrastructure?

Our team specializes in building scalable, secure web applications with production-ready deployment architecture.