Nginx Reverse Proxy Configuration for Multiple Applications
Back to blog
nginxreverse-proxydevopssslload-balancing

Nginx Reverse Proxy Configuration for Multiple Applications

Step-by-step guide to configuring Nginx as a reverse proxy, load balancer, and SSL termination point for multiple Node.js applications on a VPS.

February 14, 2025
5 min read

Nginx Reverse Proxy Configuration for Multiple Applications

Nginx is a lightweight, high-performance web server that excels at reverse proxying, load balancing, and SSL termination. This guide shows how to configure Nginx to route traffic to multiple backend applications, handle HTTPS, and implement security best practices.

Why Use Nginx as Reverse Proxy?

A reverse proxy sits between clients and backend servers, providing several benefits: SSL/TLS termination, load balancing across instances, request filtering, caching, and simplified certificate management. This architecture allows you to update backend services without client-side changes.

Prerequisites

  • Linux VPS with sudo access
  • Multiple Node.js applications running on different ports
  • Domain name with DNS pointing to VPS IP
  • Basic understanding of HTTP and DNS

Step 1: Install Nginx

Update package manager:

sudo apt-get update
sudo apt-get upgrade -y

Install Nginx:

sudo apt-get install nginx -y

Verify installation:

nginx -v

Start Nginx:

sudo systemctl start nginx
sudo systemctl enable nginx

Step 2: Create Upstream Configurations

Create configuration directory:

sudo mkdir -p /etc/nginx/conf.d

Edit the main Nginx config:

sudo nano /etc/nginx/nginx.conf

Ensure it includes conf.d directory:

include /etc/nginx/conf.d/*.conf;

Step 3: Configure Upstream Servers

Create upstream configuration:

sudo nano /etc/nginx/conf.d/upstreams.conf

Define your upstream servers:

upstream api_backend {
  least_conn;
  server 127.0.0.1:3000 max_fails=3 fail_timeout=30s;
  server 127.0.0.1:3001 max_fails=3 fail_timeout=30s;
  keepalive 32;
}

upstream admin_backend {
  server 127.0.0.1:3002;
  keepalive 32;
}

upstream websocket_backend {
  server 127.0.0.1:3003;
  keepalive 64;
}

Step 4: Configure HTTP to HTTPS Redirect

Create server configuration:

sudo nano /etc/nginx/sites-available/redirect.conf

Add configuration:

server {
  listen 80;
  listen [::]:80;
  server_name api.example.com admin.example.com;

  location /.well-known/acme-challenge/ {
    root /var/www/certbot;
  }

  location / {
    return 301 https://$server_name$request_uri;
  }
}

Enable the configuration:

sudo ln -s /etc/nginx/sites-available/redirect.conf /etc/nginx/sites-enabled/

Step 5: Install SSL Certificate

Install Certbot:

sudo apt-get install certbot python3-certbot-nginx -y

Obtain certificates:

sudo certbot certonly --webroot -w /var/www/certbot -d api.example.com -d admin.example.com

Verify SSL is installed:

sudo ls -la /etc/letsencrypt/live/api.example.com/

Step 6: Configure HTTPS Server Blocks

Create main API configuration:

sudo nano /etc/nginx/sites-available/api.conf
ComponentPurposePort
NginxReverse proxy & SSL termination80, 443
Node App 1Primary API service3000
Node App 2Secondary service3001
Node App 3Utility service3002

Add configuration:

server {
  listen 443 ssl http2;
  listen [::]:443 ssl http2;
  server_name api.example.com;

  # SSL configuration
  ssl_certificate /etc/letsencrypt/live/api.example.com/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/api.example.com/privkey.pem;

  # SSL security
  ssl_protocols TLSv1.2 TLSv1.3;
  ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256';
  ssl_prefer_server_ciphers on;
  ssl_session_cache shared:SSL:10m;
  ssl_session_timeout 10m;
  ssl_session_tickets off;

  # Security headers
  add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
  add_header X-Content-Type-Options "nosniff" always;
  add_header X-Frame-Options "DENY" always;
  add_header X-XSS-Protection "1; mode=block" always;

  # Logging
  access_log /var/log/nginx/api_access.log combined;
  error_log /var/log/nginx/api_error.log warn;

  # Gzip compression
  gzip on;
  gzip_vary on;
  gzip_types text/plain text/css text/xml text/javascript application/x-javascript application/xml+rss application/json;
  gzip_min_length 1000;

  # Rate limiting
  limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s;
  limit_req zone=api_limit burst=20 nodelay;

  location / {
    proxy_pass http://api_backend;

    # Proxy headers
    proxy_http_version 1.1;
    proxy_set_header Connection "";
    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;

    # Timeouts
    proxy_connect_timeout 60s;
    proxy_send_timeout 60s;
    proxy_read_timeout 60s;

    # Buffering
    proxy_buffering on;
    proxy_buffer_size 4k;
    proxy_buffers 8 4k;
  }

  location /health {
    access_log off;
    proxy_pass http://api_backend;
  }
}

Enable the configuration:

sudo ln -s /etc/nginx/sites-available/api.conf /etc/nginx/sites-enabled/

Create admin panel configuration:

sudo nano /etc/nginx/sites-available/admin.conf
server {
  listen 443 ssl http2;
  listen [::]:443 ssl http2;
  server_name admin.example.com;

  ssl_certificate /etc/letsencrypt/live/admin.example.com/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/admin.example.com/privkey.pem;

  # Reuse SSL configuration from api.conf
  ssl_protocols TLSv1.2 TLSv1.3;
  ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256';
  ssl_prefer_server_ciphers on;
  ssl_session_cache shared:SSL:10m;

  add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;

  access_log /var/log/nginx/admin_access.log combined;
  error_log /var/log/nginx/admin_error.log warn;

  # Stricter rate limiting for admin
  limit_req_zone $binary_remote_addr zone=admin_limit:10m rate=5r/s;
  limit_req zone=admin_limit burst=10 nodelay;

  location / {
    proxy_pass http://admin_backend;
    proxy_http_version 1.1;
    proxy_set_header Connection "";
    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;
  }
}

Enable it:

sudo ln -s /etc/nginx/sites-available/admin.conf /etc/nginx/sites-enabled/

Step 7: WebSocket Configuration

For real-time applications:

sudo nano /etc/nginx/sites-available/websocket.conf
server {
  listen 443 ssl http2;
  listen [::]:443 ssl http2;
  server_name ws.example.com;

  ssl_certificate /etc/letsencrypt/live/ws.example.com/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/ws.example.com/privkey.pem;

  ssl_protocols TLSv1.2 TLSv1.3;

  location / {
    proxy_pass http://websocket_backend;
    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;

    # Important for WebSocket
    proxy_read_timeout 86400;
    proxy_send_timeout 86400;
  }
}

Enable it:

sudo ln -s /etc/nginx/sites-available/websocket.conf /etc/nginx/sites-enabled/

Step 8: Test Configuration

Test Nginx configuration syntax:

sudo nginx -t

Expected output:

nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration will be successful

Step 9: Reload Nginx

Reload with new configuration:

sudo systemctl reload nginx

Check status:

sudo systemctl status nginx

Step 10: Monitor and Maintain

View access logs:

sudo tail -f /var/log/nginx/api_access.log

View error logs:

sudo tail -f /var/log/nginx/api_error.log

Monitor connections:

sudo netstat -antp | grep nginx

Auto-renew SSL certificates with cron:

sudo crontab -e

Add:

0 3 * * * /usr/bin/certbot renew --quiet && /usr/bin/systemctl reload nginx

Performance Optimization Tips

  • Enable caching for static assets
  • Use upstream connection pooling (keepalive)
  • Implement progressive image loading
  • Enable Gzip compression for text-based content
  • Consider using ngx_http_cache_purge for cache management

Troubleshooting

502 Bad Gateway: Check if backend servers are running

ps aux | grep node

Connection timeout: Verify backend port and firewall rules

sudo ufw status

SSL certificate errors: Verify certificate paths

sudo ls -la /etc/letsencrypt/live/

Useful Resources

Conclusion

You've configured Nginx as a robust reverse proxy with SSL termination, load balancing, and security headers. This setup handles multiple applications with minimal overhead and provides excellent performance and maintainability.