Nginx cheat sheet

A scannable Nginx reference: 15 short snippets across 9 topics, each linking back to the lesson it came from.

At a glance

TopicWhat it covers
Server blocks and static filesConfiguration is a tree. http holds global settings, each server block is a virtual host, and location blocks decidelesson
Reverse proxy and TLSWithout the forwarded headers the application sees nginx as the client, believes every request arrived over plain HTTPlesson
Caching, compression and trapsThe cache key decides correctness. The query string is already part of $request_uri; exclude cookies and headers you dolesson
Installing nginx and understanding the configuration layoutThe sites-available and sites-enabled convention is a Debian and Ubuntu packaging choice, not an nginx feature. Onlesson
How nginx matches a request: locations and rewrite phasesWork top down: the server block by server_name and listen port, then the location by the precedence rules, then thelesson
Load balancing and upstreamsproxy_next_upstream retries on another node, but only for requests nginx knows are safe to repeat. A non-idempotentlesson
WebSockets, gRPC and streaming responsesUpgrade headers for long-lived sockets, timeouts and buffering for streaming, gRPC proxying with HTTP/2, and disablinglesson
Logging, metrics and debugging a configCustom log formats, structured JSON access logs, error log levels, request IDs, stub_status metrics, and isolating alesson
Performance tuning: workers, buffers and timeoutsWorker processes and connections, sendfile and tcp_nopush, buffer sizing, keepalive timeouts, file descriptor limitslesson

Quick snippets

Server blocks and static files

Test and reload

sudo nginx -t                  # parse the config, report the first error
sudo nginx -T | less           # dump the fully expanded config
sudo nginx -s reload           # graceful: new workers, old ones drain
sudo systemctl reload nginx    # the same thing under systemd

Full lesson: Server blocks and static files →

Reverse proxy and TLS

Proxying an application

location / {
    proxy_pass http://127.0.0.1:3000;      # no trailing slash: URI passes through
    proxy_http_version 1.1;
    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";   # websockets
    proxy_read_timeout 60s;
}

Upstream pools

upstream app {
    least_conn;                       # or round-robin, or ip_hash
    server 10.0.0.11:3000 max_fails=3 fail_timeout=15s;
    server 10.0.0.12:3000 max_fails=3 fail_timeout=15s;
    keepalive 32;                     # reuse upstream connections
}

location /api/ {
    proxy_pass            http://app;
    proxy_next_upstream   error timeout http_502 http_503;
}

TLS termination

sudo certbot --nginx -d example.com -d www.example.com
sudo certbot renew --dry-run      # certificates last 90 days; automate renewal

Full lesson: Reverse proxy and TLS →

Caching, compression and traps

Compression

gzip              on;
gzip_comp_level   5;            # 5 is the sweet spot; 9 costs CPU for little gain
gzip_min_length   1024;         # do not compress tiny responses
gzip_vary         on;           # add Vary: Accept-Encoding for shared caches
gzip_types        text/plain text/css application/json
                  application/javascript text/xml image/svg+xml;

# serve pre-compressed .gz files instead of compressing per request
gzip_static       on;

Full lesson: Caching, compression and traps →

Installing nginx and understanding the configuration layout

Installing and finding the files

# Debian and Ubuntu: the official repo has a newer build than the distribution
sudo apt install nginx
nginx -v                       # the version
nginx -V                       # version plus every compile-time module and prefix

# RHEL family
sudo dnf install nginx

# inspect what the running binary actually loads
nginx -V 2>&1 | tr ' ' '\n' | grep -E 'prefix|conf-path|modules-path'

Testing and reloading safely

sudo nginx -t                       # parse and test the whole config
sudo nginx -t -c /etc/nginx/nginx.conf
sudo nginx -T                       # dump the fully expanded config with includes

sudo systemctl reload nginx         # graceful: old workers finish, new ones start
sudo nginx -s reload                # the same via a signal
sudo nginx -s quit                  # graceful shutdown

# never do this on a busy server
sudo systemctl restart nginx

Full lesson: Installing nginx and understanding the configuration layout →

How nginx matches a request: locations and rewrite phases

The request phases in order

# return ends the request immediately, in the rewrite phase,
# before access controls run. It is cheap and cannot be bypassed by a file.
location = /old-page {
    return 301 https://example.com/new-page;
}

# an internal rewrite re-runs location matching, which is why it costs more
location /legacy/ {
    rewrite ^/legacy/(.*)$ /new/$1 last;
}

Reading an unfamiliar config

# 1. what is the fully expanded config, in order?
nginx -T > /tmp/expanded.conf

# 2. which server handles this host?
grep -n "server_name" /tmp/expanded.conf

# 3. which location matches this URI? add a marker and reload
#    location = /debug-match { return 200 "matched exact\n"; }

# 4. test with a real request and inspect the result
curl -sSI https://example.com/static/app.css | head -20
curl -sS -o /dev/null -w '%{http_code} %{time_total}s\n' https://example.com/api/health

Full lesson: How nginx matches a request: locations and rewrite phases →

Load balancing and upstreams

Deploying and draining safely

# drain: keep serving existing requests but send new ones elsewhere.
# Mark the node down and reload; in-flight requests are not interrupted by a reload.
upstream app {
    server 10.0.0.11:8080 down;
    server 10.0.0.12:8080;
}

# then, after the connections have drained, deploy that node
# nginx -s reload   -> graceful handover, old workers finish their requests

Full lesson: Load balancing and upstreams →

WebSockets, gRPC and streaming responses

Server-sent events and streaming responses

location /events/ {
    proxy_pass http://app_backend;
    proxy_http_version 1.1;
    proxy_set_header Connection "";
    proxy_buffering off;               # deliver each chunk as it is written
    proxy_cache off;
    proxy_read_timeout 24h;
    chunked_transfer_encoding on;
    add_header X-Accel-Buffering no;   # tell the app not to buffer either
    add_header Cache-Control "no-cache";
}

Full lesson: WebSockets, gRPC and streaming responses →

Logging, metrics and debugging a config

Error levels and request ids

# tail the error log while reproducing a problem
sudo tail -f /var/log/nginx/error.log

# correlate a single request across nginx and the app
curl -sS -H 'X-Request-Id: trace-1234' https://example.com/api/orders -o /dev/null
grep trace-1234 /var/log/nginx/access.log /var/log/app/app.log

# raise the level for one server only, then reload and revert
# server { error_log /var/log/nginx/debug.log info; }

Metrics and bisecting a config

location = /nginx_status {
    stub_status;
    allow 127.0.0.1;
    deny all;
}

# the output tells you whether you have a capacity or a latency problem
# Active connections: 291
# server accepts handled requests
#  1203948 1203948 4093211
# Reading: 4 Writing: 18 Waiting: 269

Metrics and bisecting a config

# bisect: comment out includes until the problem disappears, then narrow
grep -n "include" /etc/nginx/nginx.conf
nginx -t && systemctl reload nginx

# confirm the parsed value of a directive rather than guessing
nginx -T | grep -A5 "server_name example.com"

Full lesson: Logging, metrics and debugging a config →

Performance tuning: workers, buffers and timeouts

Measure, then change one thing

# quick load test with concurrency, against a static file first
ab -n 20000 -c 200 https://example.com/static/app.css

# then against the dynamic path
ab -n 2000 -c 50 https://example.com/api/health

# watch the error log and the dashboard during the run
tail -f /var/log/nginx/error.log &
curl -s http://127.0.0.1/nginx_status

Full lesson: Performance tuning: workers, buffers and timeouts →

FAQ

Is this Nginx cheat sheet free to use?
Yes. No sign-up and no tracking: the page is static, every example is on the page itself, and you can print it or save it as a one-page reference.
Where do the examples come from?
Every snippet is taken from the 9 lessons of the Nginx course on this site, and each section links back to the lesson it was pulled from.
How do I go deeper than a cheat sheet?
Open the full Nginx course — it carries the worked explanations, the edge cases and the exercises behind every line here.

Git Linux Docker Kubernetes CI / CD Bash Scripting

Last refreshed 2026-09-27.