CodeForFinance
← Back to DevOps & Cloud

Nginx Configuration Guide

Reverse proxy, SSL, load balancing, and caching. The web server that powers half the internet.

What is Nginx?

Nginx (pronounced "engine-x") sits in front of your application and handles things your app should not worry about: SSL termination, static file serving, load balancing, caching, rate limiting, and request routing. Your Node/Python/Go app just handles business logic.

Almost every production deployment uses Nginx or a similar reverse proxy. Understanding its configuration is a core DevOps skill.

Reverse Proxy with SSL

The most common setup: Nginx listens on ports 80 and 443, handles SSL, and forwards requests to your app running on a local port. This example also serves static files directly - much faster than routing them through your application.

server {
    listen 80;
    server_name myapp.com www.myapp.com;

    # Redirect HTTP to HTTPS
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    server_name myapp.com www.myapp.com;

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

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

    # Serve static files directly
    location /static/ {
        alias /var/www/myapp/static/;
        expires 30d;
        add_header Cache-Control "public, immutable";
    }
}

Load Balancing

Running multiple copies of your app? Nginx distributes traffic across them. If one goes down, Nginx stops sending it traffic. Round-robin is the default; use least_conn for long-running requests.

upstream backend {
    # Round-robin by default
    server 10.0.1.10:3000;
    server 10.0.1.11:3000;
    server 10.0.1.12:3000;

    # Or use least connections
    # least_conn;

    # Or weighted distribution
    # server 10.0.1.10:3000 weight=3;
    # server 10.0.1.11:3000 weight=1;
}

server {
    listen 443 ssl http2;
    server_name myapp.com;

    location / {
        proxy_pass http://backend;
        proxy_set_header Host $host;
    }
}

Caching and Compression

Nginx can cache responses from your backend, dramatically reducing load. The X-Cache-Status header tells you if a response came from cache (HIT) or the backend (MISS). Gzip compression reduces response sizes by 60-80%.

proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=app_cache:10m
    max_size=1g inactive=60m use_temp_path=off;

server {
    listen 443 ssl http2;
    server_name myapp.com;

    location /api/ {
        proxy_pass http://localhost:3000;
        proxy_cache app_cache;
        proxy_cache_valid 200 10m;
        proxy_cache_valid 404 1m;
        add_header X-Cache-Status $upstream_cache_status;
    }

    # Gzip compression
    gzip on;
    gzip_types text/plain text/css application/json application/javascript;
    gzip_min_length 1000;
}

Security Hardening

Rate limiting prevents abuse. Security headers protect against common attacks. Always block access to hidden files (like .env or .git).

# Rate limiting
limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;

server {
    listen 443 ssl http2;
    server_name myapp.com;

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

    # Apply rate limiting to API
    location /api/ {
        limit_req zone=api burst=20 nodelay;
        proxy_pass http://localhost:3000;
    }

    # Block common attack paths
    location ~ /\. {
        deny all;
    }
}

Developer Essentials

As an Amazon Associate we may earn from qualifying purchases.