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.
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
| Component | Purpose | Port |
|---|---|---|
| Nginx | Reverse proxy & SSL termination | 80, 443 |
| Node App 1 | Primary API service | 3000 |
| Node App 2 | Secondary service | 3001 |
| Node App 3 | Utility service | 3002 |
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
- Nginx Official Documentation
- Let's Encrypt Certbot
- Mozilla SSL Configuration Generator
- Nginx Security Best Practices
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.