nginx

Nginx web server and reverse proxy expert: configuration, reverse proxying, load balancing, SSL/TLS termination, rate limiting, caching, gzip compression, WebSocket proxying, and security hardening. Use for nginx.conf creation/review, performance tuning, HTTPS setup, upstream configuration, and troubleshooting.

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "nginx" with this command: npx skills add fellipeutaka/leon/fellipeutaka-leon-nginx

Nginx Expert

When to Use

  • Creating or reviewing nginx configuration files
  • Setting up reverse proxy or load balancer
  • Configuring SSL/TLS and HTTPS
  • Implementing rate limiting or access control
  • Optimizing performance (caching, gzip, keepalive)
  • WebSocket proxying
  • Serving static content
  • Debugging nginx issues (502, 504, connection errors)

Out of scope (recommend dedicated skills):

  • Docker containerization -> docker expert
  • Kubernetes ingress controllers -> kubernetes expert
  • Application-level code -> relevant framework skill

Core Principles

  1. Security-first -- TLS 1.2+ only, strong ciphers, no server tokens, rate limiting
  2. Minimal exposure -- only expose what's needed, hide upstream details
  3. Performance -- leverage caching, gzip, keepalive connections, sendfile
  4. Clarity -- well-organized config with comments, logical server/location blocks

Configuration File Structure

main (global)
├── events { }          -- connection processing
├── http { }            -- HTTP server config
│   ├── upstream { }    -- backend server groups
│   ├── server { }      -- virtual hosts
│   │   ├── location { } -- request routing
│   │   └── location { }
│   └── server { }
└── stream { }          -- TCP/UDP proxying

Key rules:

  • Simple directives end with semicolon (;)
  • Block directives use braces ({ })
  • Directives inherit from parent contexts unless overridden
  • Comments start with #
  • Default config path: /etc/nginx/nginx.conf

Process Management

nginx -t           # test configuration syntax
nginx -s reload    # graceful reload (re-read config)
nginx -s quit      # graceful shutdown
nginx -s stop      # fast shutdown
nginx -s reopen    # reopen log files

Location Matching

Priority order (highest to lowest):

ModifierTypeExample
=Exact matchlocation = /
^~Prefix (skip regex)location ^~ /images/
~Regex (case-sensitive)location ~ \.php$
~*Regex (case-insensitive)location ~* \.(jpg|png)$
(none)Prefixlocation /docs/

Algorithm: Check all prefix locations (remember longest) -> if longest has ^~, use it -> check regex in config order (first match wins) -> fallback to longest prefix.

Serving Static Content

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

    location / {
        try_files $uri $uri/ /index.html;
    }

    location ~* \.(js|css|png|jpg|gif|ico|svg|woff2?)$ {
        expires 1y;
        add_header Cache-Control "public, immutable";
    }
}

root vs alias

# root: appends URI to path
location /images/ {
    root /data;           # /images/photo.jpg -> /data/images/photo.jpg
}

# alias: replaces matched location
location /images/ {
    alias /data/photos/;  # /images/photo.jpg -> /data/photos/photo.jpg
}

Reverse Proxy

server {
    listen 80;
    server_name example.com;

    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;
    }
}

proxy_pass URI Behavior

# WITH trailing slash -- strips location prefix
location /api/ {
    proxy_pass http://backend/;    # /api/users -> /users
}

# WITHOUT trailing slash -- passes full URI
location /api/ {
    proxy_pass http://backend;     # /api/users -> /api/users
}

Full proxy and upstream reference: references/proxy-upstream.md

Load Balancing

# Round-robin (default)
upstream backend {
    server backend1.example.com;
    server backend2.example.com;
}

# Weighted
upstream backend {
    server backend1.example.com weight=5;
    server backend2.example.com weight=1;
}

# Least connections
upstream backend {
    least_conn;
    server backend1.example.com;
    server backend2.example.com;
}

# IP hash (session persistence)
upstream backend {
    ip_hash;
    server backend1.example.com;
    server backend2.example.com;
}

Server Parameters

  • weight=N -- server weight (default 1)
  • max_fails=N -- failures before marking unavailable (default 1)
  • fail_timeout=T -- failure window AND unavailability duration (default 10s)
  • max_conns=N -- max simultaneous connections (default 0 = unlimited)
  • backup -- only used when primary servers are all down
  • down -- permanently marked as unavailable

Upstream Keepalive

upstream backend {
    server backend1.example.com;
    keepalive 32;
}

server {
    location / {
        proxy_pass http://backend;
        proxy_http_version 1.1;
        proxy_set_header Connection "";
    }
}

Full proxy and upstream reference: references/proxy-upstream.md

SSL/TLS

server {
    listen 443 ssl;
    server_name example.com;

    ssl_certificate     /etc/nginx/ssl/example.com.crt;
    ssl_certificate_key /etc/nginx/ssl/example.com.key;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;
}

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

Full SSL/TLS reference (OCSP, SNI, cert chains, hardening): references/ssl-tls.md

Rate Limiting

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

    server {
        location /api/ {
            limit_req zone=api burst=20 nodelay;
            limit_req_status 429;
            proxy_pass http://backend;
        }
    }
}
  • rate=Nr/s or rate=Nr/m -- requests per second/minute (leaky bucket)
  • burst=N -- allow N excess requests to queue
  • nodelay -- process burst immediately without delay
  • $binary_remote_addr -- preferred over $remote_addr (4/16 bytes vs string)

Full security reference: references/security.md

Gzip Compression

http {
    gzip on;
    gzip_comp_level 5;
    gzip_min_length 256;
    gzip_vary on;
    gzip_proxied any;
    gzip_types text/plain text/css text/javascript
               application/javascript application/json
               application/xml image/svg+xml;
}

text/html is always compressed -- don't list it in gzip_types.

WebSocket Proxying

http {
    map $http_upgrade $connection_upgrade {
        default upgrade;
        ''      close;
    }

    server {
        location /ws/ {
            proxy_pass http://websocket_backend;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection $connection_upgrade;
            proxy_read_timeout 3600s;
            proxy_send_timeout 3600s;
        }
    }
}

Default proxy_read_timeout is 60s -- idle WebSocket connections will be closed. Increase the timeout or use backend ping frames.

Logging

http {
    log_format main '$remote_addr - $remote_user [$time_local] '
                    '"$request" $status $body_bytes_sent '
                    '"$http_referer" "$http_user_agent" '
                    '$request_time $upstream_response_time';

    access_log /var/log/nginx/access.log main;
    error_log  /var/log/nginx/error.log warn;

    server {
        location /health {
            access_log off;
            return 200 "OK";
        }
    }
}

Performance Tuning

worker_processes auto;

events {
    worker_connections 1024;
    multi_accept on;
}

http {
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    keepalive_timeout 65s;
    keepalive_requests 1000;

    open_file_cache max=1000 inactive=20s;
    open_file_cache_valid 30s;
    open_file_cache_min_uses 2;
    open_file_cache_errors on;
}

Full caching and performance reference: references/caching-performance.md

Production Checklist

  • nginx -t passes
  • server_tokens off
  • SSL/TLS with TLSv1.2+ only
  • HTTP to HTTPS redirect
  • HSTS header enabled
  • Security headers (X-Frame-Options, CSP, X-Content-Type-Options)
  • Rate limiting on sensitive endpoints
  • client_max_body_size set appropriately
  • Gzip compression enabled
  • Static asset caching with expires
  • Logging configured with rotation
  • Hidden files blocked (location ~ /\. { deny all; })
  • Upstream keepalive with proxy_http_version 1.1
  • worker_processes auto, sendfile on, tcp_nopush on

Anti-Patterns

Don'tDo Instead
Use if for complex routingUse map + variables or multiple location blocks
Leave server_tokens onserver_tokens off;
Allow TLSv1.0/1.1ssl_protocols TLSv1.2 TLSv1.3;
Use proxy_pass without Host headerSet proxy_set_header Host $host;
Skip proxy_http_version with keepaliveproxy_http_version 1.1; and clear Connection header
Hardcode IPs in configUse upstream blocks with named servers
Ignore proxy_read_timeout for long requestsTune per-location based on expected response times
Use root inside if blocksPlace root in server or location context

Diagnostics

502 Bad Gateway

  • Backend is down or not listening
  • Check proxy_pass URL and backend connectivity

504 Gateway Timeout

  • Backend is too slow -- increase proxy_read_timeout

413 Request Entity Too Large

  • Increase client_max_body_size

Configuration Errors

  • Always test before reload: nginx -t
  • Check error log: tail -f /var/log/nginx/error.log

Key Variables

VariableDescription
$hostHost header or server name
$remote_addrClient IP address
$binary_remote_addrClient IP in binary (for limit zones)
$proxy_add_x_forwarded_forX-Forwarded-For + client IP
$schemehttp or https
$request_uriFull original URI with query string
$uriNormalized URI (without query string)
$argsQuery string
$upstream_response_timeResponse time from upstream
$upstream_cache_statusCache hit/miss status

Reference Index

TopicFile
Proxy module, upstream, load balancing, timeouts, buffering, keepalivereferences/proxy-upstream.md
SSL/TLS, HTTPS, certificates, OCSP, SNI, HTTP/2, HTTP/3references/ssl-tls.md
Security headers, rate limiting, access control, client limitsreferences/security.md
Proxy caching, gzip, performance tuning, open file cachereferences/caching-performance.md
Full config patterns: API gateway, SPA, microservices, loggingreferences/common-patterns.md

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Security

seo-audit

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

ACME SSL automation for Alibaba Cloud ESA DNS

Automatically issue/renew HTTPS certificates using Alibaba Cloud ESA DNS + acme.sh (including wildcard *.example.com + example.com), with optional installati...

Registry SourceRecently Updated
1145
Profile unavailable
General

docker

No summary provided by upstream source.

Repository SourceNeeds Review