Nginx Command Cheatsheet
Nginx is a high-performance web server and reverse proxy, known for its concurrency handling, low memory footprint, and flexible configuration syntax. This cheatsheet covers the most commonly used Nginx configuration directives — location block matching, SSL/TLS setup, reverse proxy, caching strategies, URL rewriting, load balancing, and logging. Start with location and proxy directives, then gradually explore SSL and caching.
Quick Reference
| Task | Directive |
| Static file serving | root /var/www/html; + index index.html; |
| URL redirect | return 301 https://$host$request_uri; |
| Reverse proxy | proxy_pass http://backend; |
| Load balancing | upstream backend { server ...; } |
| HTTPS config | listen 443 ssl; + ssl_certificate |
| URL rewrite | rewrite ^/old/(.*)$ /new/$1 permanent; |
| Rate limiting | limit_req zone=mylimit burst=10; |
| Enable caching | proxy_cache mycache; |
| Access control | allow 192.168.1.0/24; deny all; |
| Config validation | nginx -t |
Location Matching
``nginx
# Exact match (highest priority)
location = / {
return 200 "Welcome to root!\n";
}
# Exact match for specific path location = /favicon.ico { log_not_found off; access_log off; }
# Prefix match with ^~ (stops regex checking) location ^~ /static/ { root /var/www; expires 30d; }
# Regex match (case-sensitive) location ~ \.php$ { fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; include fastcgi_params; }
# Regex match (case-insensitive) location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ { root /var/www; expires max; add_header Cache-Control "public, immutable"; }
# Regular prefix match (longest wins) location /api/ { proxy_pass http://api_backend; }
location / { root /var/www/html; index index.html; }
# Named location (internal redirect, not exposed) location @fallback { proxy_pass http://backend; }
# Nested location location /app/ { location ~ \.php$ { fastcgi_pass unix:/var/run/php.sock; } }
# Alias path mapping location /images/ { alias /data/uploads/; # /images/foo.jpg -> /data/uploads/foo.jpg }
# Access control location /admin/ { allow 192.168.1.0/24; allow 10.0.0.0/8; deny all; }
# try_files combination
location / {
try_files $uri $uri/ /index.html; # SPA fallback
}
`
SSL/TLS Configuration
`nginx
# HTTPS server basic config
server {
listen 443 ssl http2;
server_name example.com;
ssl_certificate /etc/nginx/ssl/example.com.pem; ssl_certificate_key /etc/nginx/ssl/example.com.key;
# Protocols and ciphers 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; ssl_prefer_server_ciphers on;
# DH parameters (improved security) ssl_dhparam /etc/nginx/ssl/dhparam.pem;
# HSTS (force HTTPS) add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
# OCSP Stapling ssl_stapling on; ssl_stapling_verify on; resolver 8.8.8.8 8.8.4.4 valid=300s; resolver_timeout 5s;
# Session cache ssl_session_cache shared:SSL:10m; ssl_session_timeout 10m; ssl_session_tickets off; }
# HTTP -> HTTPS redirect server { listen 80; server_name example.com www.example.com; return 301 https://$host$request_uri; }
# Mutual TLS (client certificate auth) server { listen 443 ssl; ssl_client_certificate /etc/nginx/ssl/ca.crt; ssl_verify_client on; ssl_verify_depth 2;
location / { if ($ssl_client_verify != SUCCESS) { return 403; } proxy_pass http://backend; } }
# Let's Encrypt auto-renewal
location ^~ /.well-known/acme-challenge/ {
root /var/www/html;
}
`
Reverse Proxy
`nginx
# Basic reverse proxy
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
# Forward client information 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 Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; }
# WebSocket proxy location /ws/ { proxy_pass http://ws_backend; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header Host $host; proxy_read_timeout 86400s; # Long connection timeout }
# Path rewrite + proxy location /app/ { rewrite ^/app/(.*)$ /$1 break; proxy_pass http://app_server; # Avoids /app/foo -> /app/foo (removes prefix) }
# Proxy buffer control location /api/ { proxy_pass http://api_server; proxy_buffering on; proxy_buffer_size 4k; proxy_buffers 8 4k; proxy_busy_buffers_size 8k; proxy_max_temp_file_size 0; }
# Timeout settings location /slow/ { proxy_pass http://slow_backend; proxy_connect_timeout 10s; proxy_read_timeout 30s; proxy_send_timeout 30s; }
# Error page override
location / {
proxy_pass http://backend;
proxy_intercept_errors on;
error_page 502 503 504 /50x.html;
}
`
Caching
`nginx
# Define cache zone (in http block)
proxy_cache_path /data/nginx/cache levels=1:2 keys_zone=mycache:10m max_size=1g inactive=60m use_temp_path=off;
# Backend cache control proxy_cache_key "$scheme$request_method$host$request_uri"; proxy_cache mycache;
# Cache TTL by response code proxy_cache_valid 200 302 60m; proxy_cache_valid 301 24h; proxy_cache_valid 404 1m; proxy_cache_valid any 5m;
# Cache bypass proxy_cache_bypass $http_cache_control; proxy_no_cache $http_pragma $http_authorization;
# Cache locking (prevents cache stampede) proxy_cache_lock on; proxy_cache_lock_timeout 5s;
# Cache hit debugging add_header X-Cache-Status $upstream_cache_status;
# Forward proxy cache location / { proxy_pass http://origin; proxy_cache public_cache; proxy_cache_valid 200 1h; proxy_cache_use_stale error timeout updating http_500 http_502 http_503;
# Cache purge (used with reverse proxy) location ~ /purge(/.*) { allow 127.0.0.1; deny all; proxy_cache_purge mycache "$scheme$request_method$host$1"; } }
# Per-parameter cache key proxy_cache_key "$scheme$host$request_uri$is_args$args";
# Micro-caching (for dynamic content) location / { proxy_cache micro; proxy_cache_valid 200 5s; proxy_cache_lock on; }
# FastCGI cache
fastcgi_cache_path /data/nginx/fastcgi_cache levels=1:2 keys_zone=phpcache:10m max_size=1g inactive=60m;
location ~ \.php$ {
fastcgi_cache phpcache;
fastcgi_cache_valid 200 60m;
fastcgi_cache_methods GET HEAD;
fastcgi_cache_use_stale error timeout updating;
}
`
URL Rewriting & Redirects
`nginx
# Permanent redirect (301)
rewrite ^/old-page$ /new-page permanent;
rewrite ^/category/(.*)$ /shop/category/$1 permanent;
# Temporary redirect (302) rewrite ^/temp$ /temporary redirect;
# Internal rewrite (URL unchanged) rewrite ^/articles/(\d+)$ /show.php?id=$1 last; rewrite ^/user/([a-z]+)$ /profile.php?name=$1 last;
# Protocol redirect if ($scheme != "https") { return 301 https://$server_name$request_uri; }
# Remove www if ($host ~* ^www\.(.*)) { set $host_no_www $1; return 301 $scheme://$host_no_www$request_uri; }
# Add www if ($host !~* ^www\.) { return 301 $scheme://www.$host$request_uri; }
# Strip tracking parameters if ($args ~* "utm_source|utm_medium|utm_campaign") { return 301 $scheme://$host$uri; }
# Trailing slash handling rewrite ^([^.]*[^/])$ $1/ permanent;
# File extension mapping location ~ \.php$ { rewrite ^(.*)$ /index.php?$1 last; }
# Custom error pages
error_page 404 /404.html;
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /var/www/html;
}
`
Upstream & Load Balancing
`nginx
# HTTP load balancing
upstream backend {
# Default: round robin
server 192.168.1.10:3000 weight=3 max_fails=3 fail_timeout=30s;
server 192.168.1.11:3000 weight=2 max_fails=3 fail_timeout=30s;
server 192.168.1.12:3000 backup; # Backup server
server unix:/var/run/app.sock; # Unix Socket
keepalive 32; # Connection pool }
# IP Hash session persistence upstream sticky_backend { ip_hash; server 192.168.1.10:3000; server 192.168.1.11:3000; }
# Least connections upstream least_conn_backend { least_conn; server 192.168.1.10:3000; server 192.168.1.11:3000; }
# Random strategy upstream random_backend { random two least_conn; server 192.168.1.10:3000; server 192.168.1.11:3000; server 192.168.1.12:3000; }
# Health checks (passive via max_fails + fail_timeout) # Active health checks require nginx-plus (commercial)
# Canary release (weight-based traffic split) upstream canary { server 192.168.1.10:3000 weight=90; # Stable 90% server 192.168.1.20:3000 weight=10; # Canary 10% }
# Map-based traffic routing map $cookie_user $backend_group { default backend; ~^admin admin_backend; }
# Upstream timeout and retry
location / {
proxy_pass http://backend;
proxy_next_upstream error timeout invalid_header http_500 http_502 http_503;
proxy_next_upstream_timeout 10s;
proxy_next_upstream_tries 3;
}
`
Logging
`nginx
# Custom log format
http {
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
# JSON format (for log analysis tools) log_format json escape=json '{' '"time_local":"$time_local",' '"remote_addr":"$remote_addr",' '"remote_user":"$remote_user",' '"request":"$request",' '"status":$status,' '"body_bytes_sent":$body_bytes_sent,' '"request_time":"$request_time",' '"http_referrer":"$http_referer",' '"http_user_agent":"$http_user_agent",' '"http_x_forwarded_for":"$http_x_forwarded_for"' '}';
# Cache hit/miss log log_format cache '$remote_addr - $upstream_cache_status [$time_local] "$request" $status'; }
# Access logs access_log /var/log/nginx/access.log main; access_log /var/log/nginx/json.log json;
# Error log error_log /var/log/nginx/error.log warn;
# Per-site logs server { access_log /var/log/nginx/example.com.access.log main buffer=32k flush=5s; error_log /var/log/nginx/example.com.error.log error; }
# Disable logging for specific locations location = /health { access_log off; return 200 "OK\n"; }
location = /favicon.ico { access_log off; log_not_found off; }
# Conditional logging map $status $loggable { ~^[23] 0; # Skip 2xx and 3xx default 1; # Log everything else } access_log /var/log/nginx/error_only.log main if=$loggable;
# Log rotation (triggered by nginx -s reopen)
# Use with logrotate:
# /var/log/nginx/*.log {
# daily
# rotate 30
# compress
# postrotate
# [ ! -f /var/run/nginx.pid ] || kill -USR1 cat /var/run/nginx.pid
# endscript
# }
# Request body limits client_body_buffer_size 128k; client_max_body_size 10m;
# Debug logging (enable only when troubleshooting) # error_log /var/log/nginx/debug.log debug; ``
Location(8)
| Command | Level | ||
|---|---|---|---|
location = /path { ... }Exact URI match (highest priority) | Basic | location = /favicon.ico { log_not_found off; } | |
location ^~ /path/ { ... }Prefix match that stops regex checking after match | Intermediate | location ^~ /static/ { root /var/www; } | |
location ~ pattern { ... }Regex match (case-sensitive) | Intermediate | location ~ \.php$ { fastcgi_pass 127.0.0.1:9000; } | |
location ~* pattern { ... }Regex match (case-insensitive) | Intermediate | location ~* \.(jpg|png|css|js)$ { expires max; } | |
location /path/ { ... }Regular prefix match (longest match wins) | Basic | location /api/ { proxy_pass http://backend; } | |
location @name { ... }Named location (internal redirect, not exposed externally) | Intermediate | location @fallback { proxy_pass http://backend; } | |
alias <path>Map request path to a different filesystem path | Intermediate | location /images/ { alias /data/uploads/; } | |
try_files $uri $uri/ /index.htmlTry files/directories in order, fallback to last argument | Basic | try_files $uri $uri/ /index.html |
SSL/TLS(7)
| Command | Level | ||
|---|---|---|---|
listen 443 ssl http2Listen on port 443 with SSL and HTTP/2 enabled | Basic | listen 443 ssl http2 | |
ssl_certificate / ssl_certificate_keySpecify SSL certificate and private key file paths | Basic | ssl_certificate /etc/nginx/ssl/example.com.pem | |
ssl_protocols TLSv1.2 TLSv1.3Specify allowed SSL/TLS protocol versions (disable old ones) | Intermediate | ssl_protocols TLSv1.2 TLSv1.3 | |
ssl_ciphers <cipher_list>Specify allowed SSL cipher suites | Expert | ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384 | |
add_header Strict-Transport-SecurityEnable HSTS to force browser HTTPS access | Intermediate | add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always | |
ssl_session_cache shared:SSL:10mConfigure SSL session cache (reduces repeated handshakes) | Intermediate | ssl_session_cache shared:SSL:10m | |
return 301 https://$host$request_uriAutomatic HTTP to HTTPS redirect | Basic | return 301 https://$host$request_uri |
Reverse Proxy(5)
| Command | Level | ||
|---|---|---|---|
proxy_pass <url>Forward the request to a backend server | Basic | proxy_pass http://127.0.0.1:3000 | |
proxy_set_header <field> <value>Set HTTP headers forwarded to the backend | Basic | proxy_set_header X-Real-IP $remote_addr | |
proxy_http_version 1.1Set proxy HTTP protocol version (required for WebSocket) | Intermediate | proxy_http_version 1.1 | |
proxy_read_timeout 30sSet proxy read timeout | Intermediate | proxy_read_timeout 30s | |
proxy_intercept_errors onIntercept backend error codes and show custom error pages | Intermediate | proxy_intercept_errors on |
Caching(5)
| Command | Level | ||
|---|---|---|---|
proxy_cache_path <path> <options>Define cache storage path and parameters | Expert | proxy_cache_path /data/nginx/cache levels=1:2 keys_zone=mycache:10m max_size=1g inactive=60m | |
proxy_cache <zone>Enable proxy cache and specify cache zone name | Intermediate | proxy_cache mycache | |
proxy_cache_valid 200 302 60mSet cache TTL by response status code | Intermediate | proxy_cache_valid 200 302 60m | |
proxy_cache_bypass <condition>Specify conditions for bypassing the cache | Intermediate | proxy_cache_bypass $http_cache_control | |
add_header X-Cache-Status $upstream_cache_statusAdd cache hit/miss status to response headers (debugging) | Intermediate | add_header X-Cache-Status $upstream_cache_status |
Rewrite(7)
| Command | Level | ||
|---|---|---|---|
rewrite ^/old$ /new permanentPermanent redirect (301) | Basic | rewrite ^/old-page$ /new-page permanent | |
rewrite ^/temp$ /temporary redirectTemporary redirect (302) | Basic | rewrite ^/temp$ /temporary redirect | |
rewrite ^/path/(.*)$ /new/$1 lastInternal URL rewrite (browser URL unchanged) | Intermediate | rewrite ^/articles/(\d+)$ /show.php?id=$1 last | |
return 301 https://$server_name$request_uriReturn a specific status code and redirect URL | Basic | return 301 https://$server_name$request_uri | |
if ($scheme != "https") { ... }Conditional block (used in rewrites) | Intermediate | if ($scheme != "https") { return 301 https://$server_name$request_uri; } | |
error_page 404 /404.htmlCustom error page configuration | Basic | error_page 404 /404.html | |
rewrite ^([^.]*[^/])$ $1/ permanentAutomatically add a trailing slash | Intermediate | rewrite ^([^.]*[^/])$ $1/ permanent |
Upstream(5)
| Command | Level | ||
|---|---|---|---|
upstream name { server ...; }Define an upstream server group (backend pool) | Basic | upstream backend { server 192.168.1.10:3000; } | |
server <address> weight=<n>Add a backend server with weight in upstream block | Intermediate | server 192.168.1.10:3000 weight=3 max_fails=3 fail_timeout=30s | |
server <address> backupSet as backup server (used only when all primary servers are down) | Intermediate | server 192.168.1.12:3000 backup | |
ip_hashEnable IP hash load balancing (session persistence) | Intermediate | ip_hash | |
least_connEnable least connections load balancing strategy | Intermediate | least_conn |
Logging(5)
| Command | Level | ||
|---|---|---|---|
log_format <name> <format>Define a custom log format | Intermediate | log_format json escape=json {"time":"$time_local","status":$status} | |
access_log <file> <format>Configure access log file path and format | Basic | access_log /var/log/nginx/access.log main | |
error_log <file> <level>Configure error log file path and severity level | Basic | error_log /var/log/nginx/error.log warn | |
access_log offDisable access logging for a specific location | Basic | location = /health { access_log off; } | |
client_max_body_size <size>Set the maximum client request body size | Basic | client_max_body_size 10m |