Nginx Configuration Reference
Comprehensive reference material for Nginx configuration, architecture, directives, optimization, and best practices.
Table of Contents
- Nginx Architecture
- Configuration Contexts
- Core Directives Reference
- Server Block Configuration
- Location Matching
- Upstream Configuration
- Proxy Configuration
- SSL/TLS Configuration
- Caching Strategies
- Security Configuration
- Performance Optimization
- Variables Reference
- Module System
- Best Practices
- Anti-Patterns
- Troubleshooting
- Real-World Configurations
- RFC References
Nginx Architecture
Process Model
Nginx uses a master-worker process architecture:
Master Process (nginx)
├── Worker Process 1 (handles connections)
├── Worker Process 2 (handles connections)
├── Worker Process N (handles connections)
└── Cache Manager Process (optional)
Master Process:
- Read and validate configuration
- Create worker processes
- Handle signals (reload, shutdown)
- Maintain worker processes
Worker Processes:
- Handle client connections
- Process requests
- Serve static content
- Proxy to backends
- Non-blocking event-driven architecture
Event Model:
Worker Process
├── epoll/kqueue (event notification)
├── Event Queue
│ ├── Connection accepted
│ ├── Data received
│ ├── Backend response ready
│ └── Timer expired
└── Request Processing Pipeline
├── Parse request
├── Find location
├── Apply directives
├── Generate/proxy response
└── Send to client
Request Processing Phases
Nginx processes requests through multiple phases:
1. NGX_HTTP_POST_READ_PHASE - Read request body
2. NGX_HTTP_SERVER_REWRITE_PHASE - Server-level rewrite
3. NGX_HTTP_FIND_CONFIG_PHASE - Find location configuration
4. NGX_HTTP_REWRITE_PHASE - Location-level rewrite
5. NGX_HTTP_POST_REWRITE_PHASE - Post-rewrite processing
6. NGX_HTTP_PREACCESS_PHASE - Access pre-checks (limit_req, limit_conn)
7. NGX_HTTP_ACCESS_PHASE - Access control (allow, deny)
8. NGX_HTTP_POST_ACCESS_PHASE - Post-access processing
9. NGX_HTTP_PRECONTENT_PHASE - Before content generation
10. NGX_HTTP_CONTENT_PHASE - Content generation/proxy
11. NGX_HTTP_LOG_PHASE - Logging
Connection Processing
┌──────────────────────────────────────────────────────────────┐
│ Client Connection │
└──────────────────────────────────────────────────────────────┘
↓
┌────────────────┐
│ Accept Socket │
└────────────────┘
↓
┌────────────────┐
│ Read Request │
└────────────────┘
↓
┌────────────────┐
│ Parse Headers │
└────────────────┘
↓
┌────────────────┐
│ Find Location │
└────────────────┘
↓
┌──────────────┴──────────────┐
↓ ↓
┌──────────────┐ ┌──────────────┐
│ Static File │ │ Proxy Pass │
└──────────────┘ └──────────────┘
↓ ↓
│ ┌──────────────┐
│ │ Connect Pool │
│ └──────────────┘
│ ↓
│ ┌──────────────┐
│ │ Send Request │
│ └──────────────┘
│ ↓
│ ┌──────────────┐
│ │ Read Response│
│ └──────────────┘
↓ ↓
┌──────────────────────────────────────┐
│ Send Response to Client │
└──────────────────────────────────────┘
↓
┌────────────────┐
│ Log Request │
└────────────────┘
↓
┌──────────────┴──────────────┐
↓ ↓
┌──────────────┐ ┌──────────────┐
│ Keep-Alive │ │ Close │
└──────────────┘ └──────────────┘
Configuration Contexts
Context Hierarchy
Main Context (global)
├── events { } # Connection processing
├── http { } # HTTP server
│ ├── upstream { } # Backend servers
│ ├── map { } # Variables mapping
│ ├── geo { } # Geographic mapping
│ ├── limit_req_zone # Rate limiting zones
│ ├── limit_conn_zone # Connection limiting zones
│ ├── proxy_cache_path # Cache configuration
│ └── server { } # Virtual host
│ ├── location { } # Request matching
│ │ └── location { } # Nested locations
│ └── if { } # Conditional
├── stream { } # TCP/UDP load balancing
│ ├── upstream { }
│ └── server { }
└── mail { } # Mail proxy
└── server { }
Directive Inheritance
Directives inherit from parent contexts:
http {
# Applies to all servers
client_max_body_size 10m;
server {
# Inherits 10m, applies to all locations in this server
listen 80;
location /api/ {
# Inherits 10m, can override
client_max_body_size 50m; # Override for this location
}
location /static/ {
# Inherits 10m from http context
}
}
}
Core Directives Reference
Main Context Directives
user
Syntax: user user [group];
Default: nobody
Context: main
Defines user and group credentials used by worker processes.
user nginx nginx;
worker_processes
Syntax: worker_processes number | auto;
Default: 1
Context: main
Number of worker processes. Use auto to match CPU cores.
worker_processes auto;
worker_rlimit_nofile
Syntax: worker_rlimit_nofile number;
Default: —
Context: main
Changes the limit on the maximum number of open files for worker processes.
worker_rlimit_nofile 65535;
error_log
Syntax: error_log file [level];
Default: logs/error.log error
Context: main, http, server, location
Error log configuration. Levels: debug, info, notice, warn, error, crit, alert, emerg.
error_log /var/log/nginx/error.log warn;
pid
Syntax: pid file;
Default: logs/nginx.pid
Context: main
PID file location.
pid /var/run/nginx.pid;
Events Context Directives
worker_connections
Syntax: worker_connections number;
Default: 512
Context: events
Maximum number of simultaneous connections per worker.
events {
worker_connections 4096;
}
Calculation:
max_clients = worker_processes × worker_connections
# For reverse proxy: max_clients = worker_processes × worker_connections / 2
# (each proxied connection uses 2 connections: client and upstream)
use
Syntax: use method;
Default: auto-select
Context: events
Connection processing method: select, poll, kqueue, epoll, /dev/poll, eventport.
events {
use epoll; # Linux
# use kqueue; # BSD/macOS
}
multi_accept
Syntax: multi_accept on | off;
Default: off
Context: events
Accept multiple connections at once.
events {
multi_accept on;
}
HTTP Context Directives
include
Syntax: include file | mask;
Context: any
Include another file or files matching pattern.
http {
include /etc/nginx/mime.types;
include /etc/nginx/conf.d/*.conf;
}
default_type
Syntax: default_type mime-type;
Default: text/plain
Context: http, server, location
Default MIME type for responses.
http {
default_type application/octet-stream;
}
log_format
Syntax: log_format name [escape=default|json|none] string ...;
Default: combined "..."
Context: http
Define custom log format.
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for" '
'rt=$request_time uct="$upstream_connect_time" '
'uht="$upstream_header_time" urt="$upstream_response_time"';
log_format json escape=json '{'
'"time":"$time_iso8601",'
'"remote_addr":"$remote_addr",'
'"request":"$request",'
'"status":$status,'
'"body_bytes_sent":$body_bytes_sent,'
'"request_time":$request_time,'
'"upstream_response_time":"$upstream_response_time"'
'}';
access_log
Syntax: access_log path [format [buffer=size] [gzip[=level]] [flush=time] [if=condition]];
Default: logs/access.log combined
Context: http, server, location, if in location
Access log configuration.
access_log /var/log/nginx/access.log main;
access_log /var/log/nginx/access.log main buffer=32k;
access_log /var/log/nginx/access.log json;
access_log off; # Disable logging
sendfile
Syntax: sendfile on | off;
Default: off
Context: http, server, location
Enable efficient file transfer using sendfile() syscall.
http {
sendfile on;
}
tcp_nopush
Syntax: tcp_nopush on | off;
Default: off
Context: http, server, location
Enable TCP_CORK (send headers and file in one packet). Requires sendfile on.
http {
tcp_nopush on;
}
tcp_nodelay
Syntax: tcp_nodelay on | off;
Default: on
Context: http, server, location
Enable TCP_NODELAY (disable Nagle algorithm). For keep-alive connections.
http {
tcp_nodelay on;
}
keepalive_timeout
Syntax: keepalive_timeout timeout [header_timeout];
Default: 75s
Context: http, server, location
Keep-alive connection timeout.
http {
keepalive_timeout 65;
}
keepalive_requests
Syntax: keepalive_requests number;
Default: 100
Context: http, server, location
Maximum requests per keep-alive connection.
http {
keepalive_requests 100;
}
client_max_body_size
Syntax: client_max_body_size size;
Default: 1m
Context: http, server, location
Maximum allowed size of client request body.
http {
client_max_body_size 10m;
}
client_body_buffer_size
Syntax: client_body_buffer_size size;
Default: 8k|16k
Context: http, server, location
Buffer size for reading client request body.
http {
client_body_buffer_size 16k;
}
client_header_buffer_size
Syntax: client_header_buffer_size size;
Default: 1k
Context: http, server
Buffer size for reading client request header.
http {
client_header_buffer_size 1k;
}
large_client_header_buffers
Syntax: large_client_header_buffers number size;
Default: 4 8k
Context: http, server
Maximum number and size of buffers for large client headers.
http {
large_client_header_buffers 4 16k;
}
types_hash_max_size
Syntax: types_hash_max_size size;
Default: 1024
Context: http, server, location
Maximum size of types hash tables.
http {
types_hash_max_size 2048;
}
server_tokens
Syntax: server_tokens on | off | build | string;
Default: on
Context: http, server, location
Show Nginx version in error messages and Server header.
http {
server_tokens off; # Hide version
}
gzip
Syntax: gzip on | off;
Default: off
Context: http, server, location
Enable gzip compression.
http {
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_types text/plain text/css text/xml text/javascript
application/json application/javascript application/xml+rss;
}
Server Block Configuration
listen Directive
Syntax: listen address[:port] [parameters];
Default: 0.0.0.0:80
Context: server
Listen on specified address and port.
# IPv4
listen 80;
listen 443 ssl http2;
listen 127.0.0.1:8080;
# IPv6
listen [::]:80;
listen [::]:443 ssl http2;
# Parameters
listen 443 ssl http2 default_server;
listen 443 ssl http2 reuseport;
listen 443 ssl http2 so_keepalive=on;
listen 443 ssl http2 backlog=4096;
# Unix socket
listen unix:/var/run/nginx.sock;
Parameters:
default_server: Default server for address:portssl: Enable SSL/TLShttp2: Enable HTTP/2reuseport: Create individual listening socket for each worker (SO_REUSEPORT)backlog=number: Set listen() backlog queue sizeso_keepalive=on|off|[keepidle]:[keepintvl]:[keepcnt]: TCP keepalive
server_name Directive
Syntax: server_name name ...;
Default: ""
Context: server
Virtual host name matching.
# Exact name
server_name example.com;
# Multiple names
server_name example.com www.example.com;
# Wildcard
server_name *.example.com;
server_name example.*;
# Regular expression
server_name ~^www\d+\.example\.com$;
server_name ~^(?<subdomain>.+)\.example\.com$;
# Match all (catch-all)
server_name _;
# Default server (no server_name needed)
server {
listen 80 default_server;
}
Matching Priority:
- Exact name
- Longest wildcard starting with
* - Longest wildcard ending with
* - First matching regular expression
- Default server
root and alias
Syntax: root path;
Default: html
Context: http, server, location
Document root directory.
# root: appends URI to root path
location /static/ {
root /var/www;
# /static/file.js → /var/www/static/file.js
}
# alias: replaces location with alias path
location /static/ {
alias /var/www/assets/;
# /static/file.js → /var/www/assets/file.js
}
# Common mistake with alias
location /static { # ❌ Missing trailing slash
alias /var/www/assets/;
}
location /static/ { # ✅ Correct
alias /var/www/assets/;
}
index
Syntax: index file ...;
Default: index.html
Context: http, server, location
Index files to serve for directory requests.
location / {
index index.html index.htm;
}
location /app/ {
index index.php index.html;
}
try_files
Syntax: try_files file ... uri | =code;
Context: server, location
Try files in order, fallback to URI or return code.
# SPA fallback
location / {
try_files $uri $uri/ /index.html;
}
# PHP application
location / {
try_files $uri $uri/ /index.php?$query_string;
}
# Static files, then proxy
location / {
try_files $uri @proxy;
}
location @proxy {
proxy_pass http://backend;
}
# Return 404 if not found
location /images/ {
try_files $uri =404;
}
return
Syntax: return code [text] | code URL | URL;
Context: server, location, if
Return response immediately.
# HTTP → HTTPS redirect
server {
listen 80;
return 301 https://$host$request_uri;
}
# Redirect
location /old-page {
return 301 /new-page;
}
# Return text
location /health {
return 200 "OK\n";
add_header Content-Type text/plain;
}
# Return JSON
location /status {
return 200 '{"status":"ok"}';
add_header Content-Type application/json;
}
rewrite
Syntax: rewrite regex replacement [flag];
Context: server, location, if
Rewrite URI using regular expression.
# Basic rewrite
rewrite ^/old/(.*)$ /new/$1 permanent;
# Flags:
# last - stop processing, search for new location
# break - stop processing, use current location
# redirect - 302 temporary redirect
# permanent - 301 permanent redirect
# Example with last
location /download/ {
rewrite ^/download/(.*)$ /files/$1 last;
}
# Example with break
location /download/ {
rewrite ^/download/(.*)$ /files/$1 break;
root /var/www;
}
Location Matching
Location Syntax
Syntax: location [modifier] pattern { ... }
Context: server, location
Match request URI.
Modifiers:
=: Exact match^~: Preferential prefix (no regex check if matched)~: Case-sensitive regex~*: Case-insensitive regex- (none) : Prefix match
Matching Order
- Exact match (
=) - Preferential prefix (
^~) - Regular expressions (
~and~*) in order of appearance - Prefix match (longest match wins)
# 1. Exact match (highest priority)
location = / {
return 200 "Exact root";
}
location = /exact {
return 200 "Exact match";
}
# 2. Preferential prefix (stops regex matching)
location ^~ /images/ {
root /var/www;
}
location ^~ /static/ {
alias /var/www/static/;
}
# 3. Regex match (case-sensitive)
location ~ \.php$ {
fastcgi_pass unix:/var/run/php-fpm.sock;
}
location ~ ^/api/v[0-9]+/ {
proxy_pass http://api_backend;
}
# 4. Regex match (case-insensitive)
location ~* \.(jpg|jpeg|png|gif|ico)$ {
expires 30d;
}
location ~* \.(css|js)$ {
expires 1y;
}
# 5. Prefix match (lowest priority, longest wins)
location /api/ {
proxy_pass http://backend;
}
location / {
try_files $uri $uri/ /index.html;
}
Location Matching Examples
# Request: /exact
# Matches: location = /exact (exact match)
# Request: /images/logo.png
# Matches: location ^~ /images/ (preferential prefix)
# Request: /style.css
# Matches: location ~* \.(css|js)$ (case-insensitive regex)
# Request: /api/v1/users
# Matches: location ~ ^/api/v[0-9]+/ (case-sensitive regex)
# Request: /about
# Matches: location / (prefix match)
Named Locations
location / {
try_files $uri $uri/ @fallback;
}
location @fallback {
proxy_pass http://backend;
}
# Error page named location
error_page 404 @not_found;
location @not_found {
return 404 '{"error":"not found"}';
add_header Content-Type application/json;
}
Nested Locations
location /api/ {
# Applies to all /api/* requests
limit_req zone=api burst=50;
location /api/v1/ {
# Applies to /api/v1/* requests
proxy_pass http://backend_v1;
}
location /api/v2/ {
# Applies to /api/v2/* requests
proxy_pass http://backend_v2;
}
# Fallback for other /api/* requests
proxy_pass http://backend_default;
}
Upstream Configuration
Basic Upstream
Syntax: upstream name { ... }
Context: http
Define backend server pool.
upstream backend {
server 127.0.0.1:8080;
server 127.0.0.1:8081;
server 127.0.0.1:8082;
}
server {
location / {
proxy_pass http://backend;
}
}
Load Balancing Methods
Round-robin (default)
upstream backend {
server backend1.internal:8080;
server backend2.internal:8080;
server backend3.internal:8080;
}
Least Connections
upstream backend {
least_conn;
server backend1.internal:8080;
server backend2.internal:8080;
}
IP Hash (sticky sessions)
upstream backend {
ip_hash;
server backend1.internal:8080;
server backend2.internal:8080;
}
Hash (generic hash)
upstream backend {
hash $request_uri consistent;
server backend1.internal:8080;
server backend2.internal:8080;
}
# Hash by cookie
upstream backend {
hash $cookie_session_id;
server backend1.internal:8080;
server backend2.internal:8080;
}
Random
upstream backend {
random;
server backend1.internal:8080;
server backend2.internal:8080;
}
# Random with least_conn weighting
upstream backend {
random two least_conn;
server backend1.internal:8080;
server backend2.internal:8080;
}
Server Parameters
upstream backend {
# Weight (default: 1)
server backend1.internal:8080 weight=3;
server backend2.internal:8080 weight=2;
server backend3.internal:8080 weight=1;
# Max failures before marking down
server backend4.internal:8080 max_fails=3 fail_timeout=30s;
# Backup server (only used when primary servers down)
server backup.internal:8080 backup;
# Mark server down temporarily
server backend5.internal:8080 down;
# Max concurrent connections (nginx-plus or third-party module)
# server backend6.internal:8080 max_conns=100;
}
Keepalive Connections
upstream backend {
server backend1.internal:8080;
server backend2.internal:8080;
# Keep 32 idle connections to each backend
keepalive 32;
# Maximum requests per connection
keepalive_requests 100;
# Idle timeout
keepalive_timeout 60s;
}
server {
location / {
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_set_header Connection ""; # Required for keepalive
}
}
Health Checks (passive)
upstream backend {
server backend1.internal:8080 max_fails=3 fail_timeout=30s;
server backend2.internal:8080 max_fails=3 fail_timeout=30s;
server backup.internal:8080 backup;
}
# Nginx Plus supports active health checks:
# upstream backend {
# zone backend 64k;
# server backend1.internal:8080;
# server backend2.internal:8080;
# }
#
# server {
# location / {
# proxy_pass http://backend;
# health_check interval=5s fails=3 passes=2 uri=/health;
# }
# }
Advanced Upstream Configuration
upstream api_backend {
# Load balancing
least_conn;
# Servers
server api1.internal:8080 weight=2 max_fails=3 fail_timeout=30s;
server api2.internal:8080 weight=2 max_fails=3 fail_timeout=30s;
server api3.internal:8080 weight=1 max_fails=3 fail_timeout=30s;
server api-backup.internal:8080 backup;
# Keepalive
keepalive 32;
keepalive_requests 100;
keepalive_timeout 60s;
# Shared memory zone (for state sharing between workers)
# zone api_backend 64k;
}
Proxy Configuration
proxy_pass
Syntax: proxy_pass URL;
Context: location, if in location
Proxy requests to backend server.
# Without URI
location /api/ {
proxy_pass http://backend;
# /api/users → http://backend/api/users
}
# With URI
location /api/ {
proxy_pass http://backend/;
# /api/users → http://backend/users (location path stripped)
}
location /api/ {
proxy_pass http://backend/v1/;
# /api/users → http://backend/v1/users
}
# With variable (requires resolver)
location / {
set $backend "backend.internal";
resolver 8.8.8.8;
proxy_pass http://$backend;
}
Proxy Headers
location / {
proxy_pass http://backend;
# Standard headers
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_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Port $server_port;
# WebSocket support
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
# Custom headers
proxy_set_header X-Request-ID $request_id;
}
# Connection upgrade map for WebSocket
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
Proxy Timeouts
location / {
proxy_pass http://backend;
# Connection timeout (default: 60s)
proxy_connect_timeout 5s;
# Send timeout (default: 60s)
proxy_send_timeout 10s;
# Read timeout (default: 60s)
proxy_read_timeout 30s;
# Next upstream timeout
proxy_next_upstream_timeout 10s;
proxy_next_upstream_tries 3;
}
Proxy Buffering
location / {
proxy_pass http://backend;
# Enable buffering (default: on)
proxy_buffering on;
# Buffer size for response headers (default: 4k|8k)
proxy_buffer_size 4k;
# Number and size of buffers for response body (default: 8 4k|8k)
proxy_buffers 8 4k;
# Buffer size for busy reading (default: 8k|16k)
proxy_busy_buffers_size 16k;
# Temp file size (default: 1024m)
proxy_max_temp_file_size 1024m;
# Threshold for temp file (default: 16k|32k)
proxy_temp_file_write_size 16k;
}
# Disable buffering for streaming
location /stream/ {
proxy_pass http://streaming_backend;
proxy_buffering off;
}
Proxy Error Handling
location / {
proxy_pass http://backend;
# When to try next upstream server
proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
# Timeout for next upstream
proxy_next_upstream_timeout 10s;
# Max tries
proxy_next_upstream_tries 3;
# Intercept errors
proxy_intercept_errors on;
}
# Custom error pages
error_page 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
Proxy Redirect
location / {
proxy_pass http://backend;
# Rewrite Location and Refresh headers
proxy_redirect default;
# or
proxy_redirect http://backend/ http://$host/;
# or disable
proxy_redirect off;
}
SSL/TLS Configuration
Basic SSL Configuration
server {
listen 443 ssl http2;
server_name example.com;
# Certificate and key
ssl_certificate /etc/ssl/certs/example.com.crt;
ssl_certificate_key /etc/ssl/private/example.com.key;
# Protocols
ssl_protocols TLSv1.2 TLSv1.3;
# Ciphers
ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384';
ssl_prefer_server_ciphers off;
}
SSL Session Cache
http {
# Shared session cache (1MB ≈ 4000 sessions)
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
# Disable session tickets (for better forward secrecy)
ssl_session_tickets off;
}
OCSP Stapling
server {
listen 443 ssl http2;
ssl_certificate /etc/ssl/certs/example.com.crt;
ssl_certificate_key /etc/ssl/private/example.com.key;
# OCSP stapling
ssl_stapling on;
ssl_stapling_verify on;
# Trusted certificate for stapling verification
ssl_trusted_certificate /etc/ssl/certs/ca-chain.crt;
# DNS resolver for OCSP
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;
}
Security Headers
server {
listen 443 ssl http2;
# HSTS (HTTP Strict Transport Security)
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
# Prevent clickjacking
add_header X-Frame-Options "SAMEORIGIN" always;
# Prevent MIME type sniffing
add_header X-Content-Type-Options "nosniff" always;
# XSS protection (legacy)
add_header X-XSS-Protection "1; mode=block" always;
# CSP (Content Security Policy)
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline';" always;
# Referrer policy
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
# Permissions policy
add_header Permissions-Policy "geolocation=(), microphone=(), camera=()" always;
}
SSL Configuration (Mozilla Modern)
# Modern configuration (TLS 1.3 only)
ssl_protocols TLSv1.3;
ssl_prefer_server_ciphers off;
# Modern configuration (TLS 1.2 + 1.3)
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384';
ssl_prefer_server_ciphers off;
SSL Configuration (Mozilla Intermediate)
# Intermediate configuration (wider compatibility)
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305';
ssl_prefer_server_ciphers off;
HTTP to HTTPS Redirect
# Method 1: Separate server blocks
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
# Allow certbot challenges
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
# Redirect everything else
location / {
return 301 https://$host$request_uri;
}
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name example.com www.example.com;
# SSL configuration
ssl_certificate /etc/ssl/certs/example.com.crt;
ssl_certificate_key /etc/ssl/private/example.com.key;
}
# Method 2: if statement (less efficient)
server {
listen 80;
listen 443 ssl http2;
if ($scheme != "https") {
return 301 https://$host$request_uri;
}
}
Caching Strategies
Proxy Cache Path
Syntax: proxy_cache_path path [levels=levels] [keys_zone=name:size] [max_size=size] [inactive=time] [use_temp_path=on|off];
Context: http
Define cache storage.
http {
# Cache for API responses
proxy_cache_path /var/cache/nginx/api
levels=1:2
keys_zone=api_cache:10m
max_size=1g
inactive=60m
use_temp_path=off;
# Cache for static proxied content
proxy_cache_path /var/cache/nginx/static
levels=1:2
keys_zone=static_cache:100m
max_size=10g
inactive=7d
use_temp_path=off;
}
Parameters:
levels: Directory hierarchy (1:2 = 2 levels, 1 char and 2 chars)keys_zone: Shared memory zone name and size (1MB ≈ 8000 keys)max_size: Maximum cache sizeinactive: Remove cached items not accessed for this timeuse_temp_path: Use temp path or write directly to cache
Proxy Cache Configuration
location /api/ {
proxy_pass http://backend;
# Enable caching
proxy_cache api_cache;
# Cache key (default: $scheme$proxy_host$request_uri)
proxy_cache_key "$scheme$request_method$host$request_uri";
# Cache validity by status code
proxy_cache_valid 200 10m;
proxy_cache_valid 301 302 1h;
proxy_cache_valid 404 1m;
proxy_cache_valid any 1m;
# Use stale cache on backend errors
proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
# Update stale cache in background
proxy_cache_background_update on;
# Lock multiple identical requests
proxy_cache_lock on;
proxy_cache_lock_timeout 5s;
# Minimum uses before caching
proxy_cache_min_uses 3;
# Methods to cache
proxy_cache_methods GET HEAD;
# Add cache status header
add_header X-Cache-Status $upstream_cache_status;
}
Cache Bypass and Revalidation
location /api/ {
proxy_pass http://backend;
proxy_cache api_cache;
# Bypass cache conditions
proxy_cache_bypass $http_cache_control $cookie_nocache $arg_nocache;
# Don't cache conditions
proxy_no_cache $http_pragma $http_authorization;
# Revalidate with backend
proxy_cache_revalidate on;
}
# Skip caching for authenticated users
map $http_cookie $no_cache {
default 0;
~*session_id 1;
}
location / {
proxy_cache api_cache;
proxy_cache_bypass $no_cache;
proxy_no_cache $no_cache;
}
Cache Status Values
# $upstream_cache_status values:
# MISS - not in cache, fetched from backend
# HIT - served from cache
# EXPIRED - cache expired, fetched from backend
# STALE - using stale cache (backend error)
# UPDATING - cache updating in background
# REVALIDATED - cache revalidated with backend (304)
# BYPASS - cache bypassed
add_header X-Cache-Status $upstream_cache_status;
FastCGI Cache (for PHP)
http {
fastcgi_cache_path /var/cache/nginx/fastcgi
levels=1:2
keys_zone=php_cache:100m
max_size=2g
inactive=60m;
}
server {
location ~ \.php$ {
fastcgi_pass unix:/var/run/php-fpm.sock;
fastcgi_cache php_cache;
fastcgi_cache_key "$scheme$request_method$host$request_uri";
fastcgi_cache_valid 200 10m;
# Don't cache POST requests
fastcgi_cache_methods GET HEAD;
# Bypass cache for logged-in users
fastcgi_cache_bypass $cookie_PHPSESSID;
fastcgi_no_cache $cookie_PHPSESSID;
add_header X-FastCGI-Cache $upstream_cache_status;
}
}
Cache Purging
# Using proxy_cache_purge directive (nginx-plus or cache_purge module)
location ~ /purge(/.*) {
allow 127.0.0.1;
deny all;
proxy_cache_purge api_cache "$scheme$request_method$host$1";
}
# Manual purge (remove cache files)
# rm -rf /var/cache/nginx/api/*
Security Configuration
Rate Limiting
http {
# Define rate limit zones
limit_req_zone $binary_remote_addr zone=general:10m rate=10r/s;
limit_req_zone $binary_remote_addr zone=api:10m rate=30r/s;
limit_req_zone $binary_remote_addr zone=login:10m rate=5r/m;
limit_req_zone $binary_remote_addr zone=search:10m rate=10r/s;
# Connection limit zone
limit_conn_zone $binary_remote_addr zone=addr:10m;
}
server {
# General rate limit
location / {
limit_req zone=general burst=20 nodelay;
limit_req_status 429;
}
# API rate limit
location /api/ {
limit_req zone=api burst=50 nodelay;
limit_conn addr 10;
}
# Login rate limit (strict)
location /login {
limit_req zone=login burst=2 nodelay;
limit_req_status 429;
}
# Search rate limit with delay
location /search {
limit_req zone=search burst=5 delay=3;
}
}
Parameters:
zone: Rate limit zoneburst: Allow burst of requests beyond ratenodelay: Process burst immediately (no delay)delay: Start delaying after N requests in burstlimit_req_status: HTTP status code for rejected requests
IP Access Control
# Method 1: allow/deny directives
location /admin/ {
allow 192.168.1.0/24;
allow 10.0.0.0/8;
deny all;
}
# Method 2: geo module
geo $allowed_ip {
default 0;
192.168.1.0/24 1;
10.0.0.0/8 1;
172.16.0.0/12 1;
}
server {
location /admin/ {
if ($allowed_ip = 0) {
return 403;
}
proxy_pass http://admin_backend;
}
}
# Method 3: map module with real_ip
map $remote_addr $admin_allowed {
default 0;
~^192\.168\. 1;
~^10\. 1;
}
location /admin/ {
if ($admin_allowed = 0) {
return 403;
}
}
Basic Authentication
location /admin/ {
auth_basic "Admin Area";
auth_basic_user_file /etc/nginx/.htpasswd;
}
# Create password file:
# htpasswd -c /etc/nginx/.htpasswd username
Request Filtering
# Block by User-Agent
map $http_user_agent $block_ua {
default 0;
~*bot 1;
~*crawler 1;
~*spider 1;
}
server {
if ($block_ua) {
return 403;
}
}
# Block by Referer
map $http_referer $block_referer {
default 0;
~*spam\.com 1;
~*malicious\.com 1;
}
server {
if ($block_referer) {
return 403;
}
}
# Block requests without Host header
if ($host = "") {
return 444; # Connection closed without response
}
Request Size Limits
server {
# Request body size
client_max_body_size 10m;
# Request header size
client_header_buffer_size 1k;
large_client_header_buffers 4 16k;
# Rate limiting
limit_rate 1m; # Limit download speed to 1MB/s
limit_rate_after 10m; # Apply limit after 10MB downloaded
}
DDoS Protection
http {
# Connection limits
limit_conn_zone $binary_remote_addr zone=addr:10m;
limit_conn_zone $server_name zone=perserver:10m;
# Request rate limits
limit_req_zone $binary_remote_addr zone=general:10m rate=10r/s;
# Timeout configurations
client_body_timeout 10s;
client_header_timeout 10s;
keepalive_timeout 15s;
send_timeout 10s;
}
server {
# Connection limits
limit_conn addr 10; # Max 10 connections per IP
limit_conn perserver 1000; # Max 1000 connections to server
# Request rate limit
limit_req zone=general burst=20 nodelay;
# Slow request protection
client_body_timeout 10s;
client_header_timeout 10s;
}
Performance Optimization
Worker Process Tuning
# Main context
user nginx;
worker_processes auto; # Match CPU cores
worker_rlimit_nofile 65535;
pid /var/run/nginx.pid;
events {
worker_connections 4096; # Max connections per worker
use epoll; # Linux
multi_accept on;
}
Calculate max clients:
reverse proxy: max_clients = worker_processes × worker_connections / 2
web server: max_clients = worker_processes × worker_connections
Connection Optimization
http {
# Sendfile and TCP optimization
sendfile on;
tcp_nopush on; # Send headers and file in one packet
tcp_nodelay on; # Disable Nagle algorithm
# Keepalive
keepalive_timeout 65;
keepalive_requests 100;
# Client timeouts
client_body_timeout 12s;
client_header_timeout 12s;
send_timeout 10s;
# Reset lingering connections
reset_timedout_connection on;
}
Buffer Optimization
http {
# Client buffers
client_body_buffer_size 16k;
client_header_buffer_size 1k;
large_client_header_buffers 4 16k;
client_max_body_size 10m;
# Output buffers
output_buffers 2 32k;
postpone_output 1460;
}
location / {
proxy_pass http://backend;
# Proxy buffers
proxy_buffering on;
proxy_buffer_size 4k;
proxy_buffers 8 4k;
proxy_busy_buffers_size 16k;
}
Compression
http {
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_min_length 1000;
gzip_disable "msie6";
gzip_types
text/plain
text/css
text/xml
text/javascript
application/json
application/javascript
application/xml+rss
application/rss+xml
font/truetype
font/opentype
application/vnd.ms-fontobject
image/svg+xml;
# Pre-compressed files
gzip_static on;
}
Static File Optimization
location ~* \.(jpg|jpeg|png|gif|ico|css|js|svg|woff|woff2|ttf|eot)$ {
root /var/www/static;
# Cache headers
expires 1y;
add_header Cache-Control "public, immutable";
# Disable logging
access_log off;
# Pre-compressed files
gzip_static on;
# Open file cache
open_file_cache max=10000 inactive=30s;
open_file_cache_valid 60s;
open_file_cache_min_uses 2;
open_file_cache_errors on;
}
Open File Cache
ht
…(truncated)