Table of Contents

nginx — High-Performance Web Server

What is nginx?

nginx (pronounced “engine-x”) is one of the world’s most widely deployed web servers and reverse proxies. Originally developed to solve the C10K problem — handling 10,000 concurrent connections — nginx uses an event-driven, non-blocking architecture that delivers exceptional throughput with minimal memory usage.

Today, nginx powers a significant portion of the internet’s busiest websites. It excels at serving static files, acting as a reverse proxy in front of application servers, terminating TLS, load balancing across backend nodes, and caching HTTP responses. It is a fundamental component of the modern web infrastructure stack.

Why Use nginx?

  • High performance — handles tens of thousands of concurrent connections efficiently.
  • Low memory footprint — a single nginx worker process can handle thousands of connections.
  • Versatile — web server, reverse proxy, load balancer, mail proxy, and HTTP cache in one binary.
  • Battle-tested — used by Cloudflare, Netflix, GitHub, WordPress.com, and many more.
  • Easy configuration — clean, readable configuration file format.
  • Active community — extensive documentation, modules, and community support.
  • Docker-friendly — the official nginx Docker image is one of the most pulled images on Docker Hub.

Installation

# Ubuntu / Debian
sudo apt update && sudo apt install nginx

# Fedora / RHEL / CentOS
sudo dnf install nginx

# Arch Linux
sudo pacman -S nginx

# macOS (Homebrew)
brew install nginx

# Alpine Linux (containers)
apk add nginx

# Start and enable on boot
sudo systemctl start nginx
sudo systemctl enable nginx

# Check status
sudo systemctl status nginx

# Verify installation
nginx -v

Basic Usage

# Start nginx
sudo systemctl start nginx

# Stop nginx
sudo systemctl stop nginx

# Reload configuration without downtime
sudo systemctl reload nginx
# or:
sudo nginx -s reload

# Test configuration syntax before applying
sudo nginx -t

# View the main configuration file
cat /etc/nginx/nginx.conf

# View available site configurations (Debian/Ubuntu)
ls /etc/nginx/sites-available/
ls /etc/nginx/sites-enabled/

Configuration File Structure

nginx configuration is built from hierarchical blocks:

# /etc/nginx/nginx.conf

user www-data;
worker_processes auto;  # one per CPU core
pid /run/nginx.pid;

events {
    worker_connections 1024;
}

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    sendfile        on;
    tcp_nopush      on;
    keepalive_timeout 65;

    gzip on;
    gzip_types text/plain application/json application/javascript text/css;

    include /etc/nginx/sites-enabled/*;
}

Serving Static Files

The most basic nginx use case is serving static HTML, CSS, JavaScript, and image files:

server {
    listen 80;
    server_name example.com www.example.com;
    root /var/www/html;
    index index.html;

    location / {
        try_files $uri $uri/ =404;
    }

    # Serve a custom 404 page
    error_page 404 /404.html;
    location = /404.html {
        internal;
    }
}

Reverse Proxy Configuration

nginx shines as a reverse proxy in front of Node.js, Python (Gunicorn), Ruby (Puma), Go, or any other HTTP application server:

upstream app_server {
    server 127.0.0.1:8080;
    server 127.0.0.1:8081;  # second instance for load balancing
}

server {
    listen 80;
    server_name api.example.com;

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

TLS / HTTPS with Let’s Encrypt

Use Certbot to automatically obtain and configure TLS certificates:

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

# Obtain a certificate and configure nginx automatically
sudo certbot --nginx -d example.com -d www.example.com

# Certificates auto-renew via a cron job or systemd timer
sudo certbot renew --dry-run

Or configure TLS manually:

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

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

    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_prefer_server_ciphers off;

    add_header Strict-Transport-Security "max-age=63072000" always;

    root /var/www/html;
    index index.html;
}

# Redirect HTTP to HTTPS
server {
    listen 80;
    server_name example.com;
    return 301 https://$host$request_uri;
}

Static Asset Caching

Long-lived caching for versioned assets dramatically improves page load performance:

server {
    listen 80;
    server_name example.com;
    root /var/www/html;

    # Long-term cache for hashed/versioned assets
    location ~* \.(js|css|png|jpg|jpeg|gif|ico|woff2|woff|svg)$ {
        expires 1y;
        add_header Cache-Control "public, immutable";
        access_log off;
    }

    # No cache for HTML (always serve fresh)
    location ~* \.html$ {
        expires -1;
        add_header Cache-Control "no-store";
    }

    location / {
        try_files $uri $uri/ =404;
    }
}

Load Balancing

nginx supports multiple load balancing strategies:

upstream backend {
    # Default: round-robin
    server backend1.example.com weight=3;
    server backend2.example.com weight=1;
    server backend3.example.com backup;  # only used when others fail

    # Alternative: least connections
    # least_conn;

    # Alternative: IP hash (sticky sessions)
    # ip_hash;

    keepalive 32;
}

server {
    listen 80;
    location / {
        proxy_pass http://backend;
    }
}

💡 Tips & Tricks

Tip 1: Always Test Before Reloading

sudo nginx -t && sudo nginx -s reload

Tip 2: Rate Limiting to Prevent Abuse

http {
    limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;

    server {
        location /api/ {
            limit_req zone=api burst=20 nodelay;
            proxy_pass http://localhost:8080;
        }
    }
}

Tip 3: Enable gzip Compression

http {
    gzip on;
    gzip_vary on;
    gzip_min_length 1000;
    gzip_comp_level 6;
    gzip_types
        text/plain
        text/css
        application/json
        application/javascript
        text/xml
        application/xml
        image/svg+xml;
}

Tip 4: 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 Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Content-Security-Policy "default-src 'self'" always;

Tip 5: Check and Tail nginx Logs

# Error log
sudo tail -f /var/log/nginx/error.log

# Access log
sudo tail -f /var/log/nginx/access.log

# Filter for 5xx errors
sudo tail -f /var/log/nginx/access.log | grep '" 5'

Tip 6: Use include for Cleaner Configuration

Split your config into reusable snippets:

# /etc/nginx/snippets/proxy-params.conf
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

# In your server block:
location / {
    proxy_pass http://app;
    include /etc/nginx/snippets/proxy-params.conf;
}

Advanced Applications

Reverse Proxy with Static Assets and Caching

server {
    listen 80;
    server_name example.com;

    location /assets/ {
        root /var/www/html;
        expires 30d;
        add_header Cache-Control "public";
    }

    location /api/ {
        proxy_pass http://127.0.0.1:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }

    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

Test the caching headers with curl:

curl -I https://example.com/assets/app.js
# Look for: Cache-Control: public, Expires: ...
  • curl — test nginx endpoints and inspect response headers.
  • certbot — automate TLS certificate provisioning with Let’s Encrypt.
  • docker — run nginx as a container for local development or production.

Real-world Use Cases

  • Static site hosting — serve HTML, CSS, JS, and images for Astro, Next.js, or Hugo sites directly from the filesystem.
  • API reverse proxy — sit in front of Node.js, Python, or Go app servers, handling TLS, compression, and load balancing.
  • Microservice gateway — route traffic to multiple backend services based on URL prefix (/api/users, /api/orders).
  • SSL termination — decrypt HTTPS at the nginx level and forward plain HTTP to internal app servers on localhost.
  • CDN-like edge caching — cache API and asset responses at the nginx level to reduce backend load.

When Not To Use nginx

  • Development server — use npm run dev, vite, or framework-native dev servers during development; nginx is for production.
  • Complex routing logic — if routes need dynamic application logic, put that logic in the app layer and use nginx as a dumb proxy.
  • Very small projects — for a single-process app on a small VPS, nginx adds complexity; consider Caddy for simpler automatic HTTPS.
  • Kubernetes ingress — inside Kubernetes, use an Ingress controller (nginx Ingress, Traefik, or Istio) rather than managing nginx config files manually.

Practical Examples: Configure nginx for Production Traffic

# 1. Quickly test a new nginx config before applying
sudo nginx -t && echo "Config OK" && sudo nginx -s reload

# 2. Tail access logs and filter for errors only
sudo tail -f /var/log/nginx/access.log | grep '" [45]'

# 3. Benchmark your nginx setup with ab (Apache Bench)
ab -n 1000 -c 50 https://example.com/

# 4. Generate a self-signed certificate for local development
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
  -keyout /etc/nginx/ssl/nginx.key \
  -out /etc/nginx/ssl/nginx.crt \
  -subj "/CN=localhost"

# 5. Check which config file nginx is using
sudo nginx -T | head -20
📦 Quick install:sudo apt install nginx
🌐 Official site ↗📅 Published: June 1, 2024