Nginx Cheatsheet - Nginx Configuration & Command Reference
For engineers debugging 502/504s, adjusting location routing, or setting up reverse proxies. The hard part of Nginx is not the sheer number of directives but the details — location matching rules, whether proxy_pass carries a trailing slash, and upstream timeout tuning — which fail silently and only surface as anomalies under traffic. By the end you will validate with nginx -t before reloading, trace upstream errors back to the backend from the error log, and tell apart 502 Bad Gateway from 504 Gateway Timeout.
Typical Use Case
Configure reverse proxy, load balancing, static file serving and TLS termination; troubleshoot 502/504 gateway errors, redirect loops, config syntax errors, and permission denied (13: Permission denied).
Commands & Testing 5
nginx -tnginx -s reloadnginx -Tsystemctl restart nginxnginx -VLocation Matching Priority 5
location = /pathlocation ^~ /static/location ~ \.php$location ~* \.(jpg|png)$location /pathReverse Proxy Snippets 5
proxy_pass http://127.0.0.1:8080;proxy_set_header Host $host;proxy_set_header X-Real-IP $remote_addr;proxy_read_timeout 60s;client_max_body_size 50m;Logs & Troubleshooting 4
tail -f /var/log/nginx/error.logtail -f /var/log/nginx/access.loggrep " 502 " /var/log/nginx/access.logcurl -I http://localhostProcess Control & Performance (REQ-02 add-on) 22
nginx -g "daemon off;"nginx -p /usr/local/nginx -c conf/nginx.confkill -s QUIT $(cat /var/run/nginx.pid)ps -ax | grep nginxnginx -e /var/log/nginx/error.loginclude /etc/nginx/conf.d/*.conf;error_log /var/log/nginx/error.log warn;pid /var/run/nginx.pid;user nginx;sendfile on;tcp_nopush on;keepalive_timeout 65;server_tokens off;root /data/www;index index.html index.htm;location /images/ { root /data; }location ~ \.(gif|jpg|png)$ { root /data/images; }fastcgi_pass localhost:9000;fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;proxy_redirect off;proxy_connect_timeout 60s;stub_status;Parameter matrix
| Parameter | Effect | Example |
|---|---|---|
-t | Test the configuration syntax only, without starting anything | nginx -t |
-s reload | Reload the configuration smoothly without dropping connections | nginx -s reload |
-s stop | Shut down immediately | nginx -s stop |
-c | Point at a specific configuration file | nginx -c /etc/nginx/nginx.conf |
-g | Inject global directives at startup | nginx -g 'daemon off;' |
worker_processes | Number of worker processes, normally set to auto | worker_processes auto; |
proxy_pass | Forward the request to an upstream service | proxy_pass http://127.0.0.1:3000; |
upstream | Define a pool of backend servers for load balancing | upstream app { server 10.0.0.1; } |
try_files | Try each path in order and fall back to the last one | try_files $uri $uri/ /index.html; |
return 301 | Emit a redirect response | return 301 https://$host$request_uri; |
Common pitfalls
SymptomA configuration change has no effect, or old and new settings mix.
CauseThe file was edited but never reloaded, or the running worker was changed in memory.
FixValidate with nginx -t then apply with nginx -s reload each time; never kill workers, since that severs live connections.
SymptomThe site returns 502 Bad Gateway.
CauseThe upstream behind proxy_pass is down, the port is wrong, or a firewall blocks the connection.
Fixcurl the upstream directly from the nginx host, verify the address, port and backend listener, and look for connect() failed in error.log.
SymptomThe site returns 504 Gateway Timeout.
CauseThe upstream took longer than proxy_read_timeout, which defaults to 60s.
FixRaise proxy_read_timeout and proxy_send_timeout, or shorten the upstream work itself; first rule out an upstream deadlock.
SymptomStatic files return 403 Forbidden and the log shows 13: Permission denied.
CauseThe nginx worker user (typically www-data) cannot read the directory or file, or SELinux blocks it.
FixMake sure directories carry o+x and files carry o+r; with SELinux enabled, allow it via setsebool -P httpd_read_user_content 1.
SymptomHTTP redirects to HTTPS in an endless loop.
CauseTLS is already terminated at the CDN or load balancer layer, and nginx redirects a second time.
FixRedirect at exactly one layer; if the CDN already handles TLS, do not add return 301 https on the nginx side.
Symptomnginx -t reports unknown directive.
CauseThe directive belongs to a module that was not compiled into this binary, such as stub_status or lua.
FixRun nginx -V to list compiled modules; if one is missing, install a package that includes it or rebuild, and stop referencing absent directives.
Troubleshooting
1Validate the configuration syntax first
nginx -tMandatory before going live: a bad reload can leave the whole service unable to start.
2Smoothly reload the new configuration
nginx -s reloadExisting connections survive; if an old worker is stuck, use -s quit to let it finish gracefully.
3Follow the error log to find gateway failures
tail -f /var/log/nginx/error.log502s, 504s and permission problems all leave connect() or permission traces here.
4Hit the upstream directly from the nginx host
curl -I http://127.0.0.1:3000/healthThis separates an upstream outage from an nginx configuration mistake.
Command Examples
Validate the config, then reload gracefully
nginx -t
nginx -s reloadnginx -t fully parses every include and reports the line number of the first error. A plain restart also takes effect, but nginx -T is the only reliable source of truth when include conflicts are suspected.
Output
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful
Dump the fully merged config to catch include overrides
nginx -TWhen config is split across conf.d files and the same server_name is defined twice, the copy you edited may never have been read. nginx -T prints the final merged result segmented by source file, making overrides obvious at a glance.
Output
# configuration file /etc/nginx/nginx.conf: ... # configuration file /etc/nginx/conf.d/default.conf:
The trailing slash on proxy_pass decides path concatenation
location /api/ {
proxy_pass http://127.0.0.1:8080/;
}
location /api/ {
proxy_pass http://127.0.0.1:8080;
}With the trailing slash, /api/users is rewritten to /users; without it, the path stays /api/users. Which form is correct depends on how the backend routes, and a missing slash shows up as blanket 404s.
Separate connection failures from read timeouts on 502
tail -f /var/log/nginx/error.log
nginx -s reload
curl -I http://localhostconnect() failed (111: Connection refused) in error.log means the backend is down or the port is wrong, while upstream timed out means it is merely slow and needs a larger proxy_read_timeout in that location.
Debug location matching precedence
location = /exact {}
location ^~ /static/ {}
location ~* \.(gif|jpg|png)$ {}
location / {}
nginx -t
nginx -s reloadPrecedence runs: exact = first, then ^~ prefix, then the ~ and ~* regexes, with plain prefixes last. A regex hit steals paths that ^~ would not have stopped, so "I changed the static rule and nothing happened" usually means this ordering.
Common Pitfalls
- systemctl restart nginx is a full restart that drops every keepalive connection and fails in-flight requests; use nginx -s reload in production.
- Whether proxy_pass ends with a slash changes the forwarded path outright, and mixing both styles in one server is notoriously hard to debug — the diff often looks like a single character.
- client_max_body_size defaults to 1m, so any moderately sized upload returns 413 and the frontend just reports "upload failed" with no actionable message.
- Placing a directive such as client_max_body_size or proxy_read_timeout outside a server block makes nginx -t fail outright, and the same happens when an included file sits in the wrong scope.
- nginx -s reload only asks the master to re-read the config; if the syntax is valid but an include path points at the wrong file, the reload "succeeds" while behaviour is completely unchanged.
- access_log records request lines, not bodies, so putting tokens or passwords in query strings writes them in plaintext into /var/log/nginx/access.log.
Tips
- Trailing slash in proxy_pass changes semantics: with / replaces location prefix, without it appends.
- Always run nginx -t before reload — a syntax error won't break the running process but reload won't apply.
- For 502: check error.log — "connection refused" means backend is down, "timeout" means backend is too slow.
FAQ
How does Nginx decide the order of location matching?
Priority from highest to lowest: exact match with =, then the ^~ prefix (which stops without checking regexes), then regex ~/~* (the first matching regex wins, in config order), and finally plain longest-prefix matching. Both = and ^~ short-circuit immediately, while regex matching waits until all prefix locations have been tried.
When I get a 404, how do I tell whether the location did not match or the backend really returned 404?
Check the error log. If the request never reached the backend, you will only see an access entry, and the proxy_pass target server receives no request; if the backend returned 404, the log shows the upstream response to the backend request. You can also temporarily add a try_files rule or directly curl the backend port to compare.
What is the difference between proxy_pass with and without a trailing slash?
The key difference is path handling. When proxy_pass includes a URI such as http://upstream/api/, the part of the request that matched the location is appended to that path; when it has no URI (http://upstream or http://upstream/), the original request URI is passed through unchanged. Adding a path is how you rewrite /foo to a backend prefix like /api/... .
How do I troubleshoot a 502 Bad Gateway vs a 504 Gateway Timeout?
A 502 means Nginx could not get a valid response from the backend: first confirm the process is alive, the port is listening, and firewall and proxy_pass address are correct. A 504 means the backend exceeded the configured timeout, so check backend processing time first, then raise proxy_read_timeout/proxy_connect_timeout. Always cross-reference the upstream section of the error log in both cases.
Should I restart or reload after changing Nginx config?
Prefer nginx -s reload or systemctl reload nginx: it reloads gracefully without dropping existing connections and validates the config first. Only fall back to systemctl restart when the change touches parameters that cannot be hot-reloaded, such as listen sockets or worker counts, or when reload keeps failing. Always run nginx -t first.
Official References
Each command links to its official documentation below, so you can verify the latest usage and read deeper.
Maintained by LaoHand
Publicly updated on Sep 10, 2026, continuously proofread against official docs.
Contact Us
Wrong command or description? Send us corrections, business inquiries or product feedback by email.
Contact Us