NGINX Cheat Sheet
NGINX directives and commands for server blocks, locations, reverse proxying, TLS, headers, rate limits, and reloads.
NGINX selects a virtual server, chooses a location for the request URI, and then serves content or passes the request to an upstream. Directive context matters: server blocks belong in http, and some controls are valid only at http, server, or location scope.
Server blocks and static files
A server block matches an address and Host value. root joins the configured directory with the request URI, while index names files considered for directory requests.
server {
listen 80;
server_name example.com www.example.com;
root /srv/www/example;
index index.html;
location / {
try_files $uri $uri/ =404;
}
}
| Directive | Role |
|---|---|
listen 80 | Accept HTTP connections on port 80. |
server_name example.com | Match the request host against this virtual server. |
root /srv/www/example | Set the filesystem base for URI lookup. |
index index.html | Select an index file for a directory URI. |
try_files | Test candidate files in order and use the final fallback. |
For a client-routed application, a fallback such as try_files $uri $uri/ /index.html; internally sends unknown paths to the application entry point. Use =404 instead when nonexistent static paths must stay missing.
Location matching and precedence
NGINX first checks exact and prefix locations, then may evaluate regular expressions. Regular-expression locations are tested in configuration order, not by the length of their pattern.
| Form | Match behavior |
|---|---|
location = /health | Exact URI match; selected immediately. |
location ^~ /assets/ | Prefix match that suppresses regular-expression checks when it is the longest prefix. |
location ~ \.php$ | Case-sensitive regular expression. |
| `location ~* .(png | jpg)$` |
location / | Ordinary prefix and common fallback. |
The practical order is exact =, the longest prefix, regular expressions unless that prefix uses ^~, and finally the remembered longest ordinary prefix.
location = /health {
return 200 "ok\n";
}
location ^~ /assets/ {
try_files $uri =404;
}
location ~* \.(css|js|png|jpg)$ {
expires 1h;
}
Reverse proxy and request variables
A reverse proxy should preserve the requested host and carry the original client and scheme information in conventional forwarding headers.
location /api/ {
proxy_pass http://127.0.0.1:3000;
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;
}
With proxy_pass http://127.0.0.1:3000;, the original request URI is forwarded. In this prefix location, adding a URI slash as proxy_pass http://127.0.0.1:3000/; replaces the matched /api/ prefix, so /api/users is sent upstream as /users.
| Variable | Value |
|---|---|
$host | Normalized request host, with a configured server name as fallback. |
$request_uri | Original request URI, including its query string. |
$scheme | Request scheme, usually http or https. |
$remote_addr | Address of the direct client connected to NGINX. |
$proxy_add_x_forwarded_for | Existing forwarded-for chain plus $remote_addr. |
Only trust incoming forwarding headers when the network path and real-IP configuration make their source trustworthy.
Redirects and rewrites
Use return for a fixed redirect because it is direct and easy to audit. A 301 is permanent and may be cached aggressively; a 302 is temporary.
server {
listen 80;
server_name example.com www.example.com;
return 301 https://example.com$request_uri;
}
location = /maintenance {
return 302 /status.html;
}
location /old/ {
rewrite ^/old/(.*)$ /new/$1 permanent;
}
| Syntax | Result |
|---|---|
return 301 URL | Permanent redirect. |
return 302 URL | Temporary redirect. |
rewrite REGEX REPLACEMENT permanent | Rewrite and return 301. |
rewrite REGEX REPLACEMENT redirect | Rewrite and return 302. |
rewrite REGEX REPLACEMENT last | Restart location processing with the rewritten URI. |
TLS and HTTP/2
Certificates and private keys are configured in the TLS server block. Protect key files with restrictive filesystem permissions and use complete certificate chains supplied by the certificate issuer.
server {
listen 443 ssl;
http2 on;
server_name example.com www.example.com;
ssl_certificate /etc/ssl/example/fullchain.pem;
ssl_certificate_key /etc/ssl/example/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
root /srv/www/example;
index index.html;
}
http2 on; is the current syntax and was introduced in NGINX 1.25.1. Older releases enable HTTP/2 with listen 443 ssl http2;; on 1.25.1 and later, the http2 parameter on listen is deprecated in favor of the separate directive. Confirm that the installed build includes the HTTP/2 module before enabling it.
Headers, body size, and rate limiting
limit_req_zone belongs in http; limit_req applies the named zone in a server or location. The zone stores request state keyed here by the binary client address.
http {
limit_req_zone $binary_remote_addr zone=api_per_ip:10m rate=10r/s;
server {
listen 443 ssl;
server_name api.example.com;
ssl_certificate /etc/ssl/example/fullchain.pem;
ssl_certificate_key /etc/ssl/example/privkey.pem;
client_max_body_size 20m;
add_header Strict-Transport-Security "max-age=31536000" always;
add_header X-Frame-Options "SAMEORIGIN" always;
location /api/ {
limit_req zone=api_per_ip burst=20 nodelay;
proxy_pass http://127.0.0.1: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;
}
}
}
| Directive | Effect |
|---|---|
add_header ... always | Add the header across response status codes supported by the module. |
Strict-Transport-Security | Tell browsers to use HTTPS for future requests; send it only over HTTPS. |
X-Frame-Options SAMEORIGIN | Restrict framing to the same origin in supporting browsers. |
client_max_body_size 20m | Reject larger request bodies, normally with status 413. |
rate=10r/s | Set the sustained request rate for a limit zone. |
burst=20 nodelay | Admit a bounded burst without delaying accepted excess requests. |
Enable HSTS only after HTTPS is dependable for the intended host scope. Rate limiting controls request arrival, not concurrent upstream work.
Validate and reload
Test the full configuration before signaling the master process. A successful reload starts workers with the new configuration and lets old workers finish active requests gracefully.
sudo nginx -t
sudo nginx -T
sudo nginx -s reload
| Command | Use |
|---|---|
nginx -t | Check syntax and referenced files. |
nginx -T | Test and print the expanded configuration. |
nginx -s reload | Ask the running master process to reload. |
systemctl reload nginx | Reload through systemd on installations that provide the service. |
Do not reload after a failed nginx -t; correct the reported file and line first.