Server Blocks
listen 80;
Port to accept connections on
listen 443 ssl;
Accept TLS on this port
listen 80 default_server;
Catch requests matching no name
server_name example.com www.example.com;
Hosts this server answers
server_name *.example.com;
Wildcard host match
root <dir>;
Document root; URI is appended
index index.html index.htm;
File served for a directory
include <file>;
Pull in more config files, globs allowed
Typically include conf.d/*.conf; inside http.
error_page 404 /404.html;
Custom page for an error code
gzip on;
Compress responses
Add gzip_types for anything beyond text/html.
allow <ip>; deny all;
Restrict access by client address
auth_basic "<realm>";
Ask for a password (needs auth_basic_user_file)
error_page 500 502 503 504 /50x.html;
One page for several codes
client_max_body_size 10m;
Max upload size (default 1m, else 413)
keepalive_timeout 75s;
Idle time for keep-alive connections
Locations
location / { }
Prefix match: the catch-all
location = /path { }
Exact match, stops the search
location ^~ /static/ { }
Prefix that skips regex checks
location ~ \.php$ { }
Case-sensitive regex
location ~* \.(jpg|png)$ { }
Case-insensitive regex
location @fallback { }
Named location for internal jumps
alias <dir>/;
Replace the location prefix with a path
With a prefix location, keep trailing slashes consistent on
both sides; use root when the location matches the end of the
path.
try_files $uri $uri/ =404;
Try file, directory, then 404
try_files $uri /index.html;
SPA fallback to the index page
return 301 <url>;
Redirect permanently
return 200 "<text>";
Answer directly with a body
rewrite <regex> <url> permanent;
Regex-based redirect
autoindex on;
List directory contents
Location matching order
| Step |
Rule |
| 1 |
Exact = match ends the search |
| 2 |
Longest prefix is remembered; ^~ stops here |
| 3 |
Regex ~ and ~* in file order, first wins |
| 4 |
No regex hit: first matching predicate $var location
(1.31.5+)
|
| 5 |
Nothing else matched: use the remembered prefix |
Reverse Proxy
proxy_pass http://127.0.0.1:8080;
Forward requests to a backend
Without a URI part the request path is passed unchanged; with
one (even just a trailing /) the matched location prefix is
replaced.
proxy_pass http://<upstream>;
Forward to a named upstream group
proxy_set_header Host $host;
Pass the original host to the backend
The default sends the backend address as Host. A
proxy_set_header in a location replaces all inherited ones.
proxy_set_header X-Real-IP $remote_addr;
Tell the backend the client IP
proxy_set_header X-Forwarded-For
$proxy_add_x_forwarded_for;
Append client IP to the chain
proxy_set_header X-Forwarded-Proto $scheme;
Pass http or https
proxy_http_version 1.1;
Default since 1.29.7; set it on older builds
proxy_read_timeout 60s;
Wait between reads from the backend
proxy_buffering off;
Stream responses, e.g. for SSE
limit_req zone=<zone> burst=<n>;
Rate limit (needs limit_req_zone)
upstream <upstream> { server <host:port>;
}
Define a backend pool
Keep-alive to backends is on by default since 1.29.7.
least_conn;
Balance by fewest connections (in upstream)
proxy_redirect off;
Keep backend Location headers as is
fastcgi_pass <host:port>;
Hand off to a FastCGI backend
TLS
ssl_certificate <file>;
Certificate (leaf first, then chain)
ssl_certificate_key <file>;
Private key, PEM
ssl_protocols TLSv1.2 TLSv1.3;
Allowed TLS versions (the default)
ssl_session_cache shared:SSL:10m;
Share TLS sessions across workers
http2 on;
Enable HTTP/2 in the server (1.25.1+)
return 301 https://$host$request_uri;
Redirect HTTP to HTTPS
add_header Strict-Transport-Security
"max-age=31536000" always;
Send an HSTS header
An add_header in a deeper block drops this one unless
add_header_inherit merge; is set.
add_header_inherit merge;
Keep outer add_header lines (1.29.3+)