Nginx rarely “randomly breaks.” Most incidents come from a small set of predictable mis-wires: the wrong block matches, headers don’t reach the app, paths don’t resolve, or TLS is pointed at the wrong files.
This guide is a decision tree with examples, plus a checklist of the pitfalls people hit when they’re tired and the site is down.
Start with one question: what’s the symptom you can observe from the outside?
Decision tree: what symptom do you see?
Pick the closest match and follow that branch.
- 502 / 504 from Nginx (bad gateway / timeout) → go to “Upstream and proxy pitfalls (502/504)”
- 404 for files you’re sure exist → go to “Static files and path pitfalls (404)”
- 301/302 loop or endless HTTP↔HTTPS bouncing → go to “Redirect loop pitfalls”
- TLS/HTTPS error (certificate mismatch, handshake failure) → go to “TLS pitfalls”
- Wrong site answers (another vhost, default page) → go to “Server block matching pitfalls”
- Works in one environment but not another (VM vs container, local vs prod) → skim all sections, then “Final takeaway”
If you can run commands on the server, do one quick safety check first: nginx -t (config test) before restarting anything.
Upstream and proxy pitfalls (502/504)
If Nginx returns 502/504, it’s usually saying: “I tried to talk to your app and couldn’t.” The pitfall is treating it like an Nginx bug instead of an upstream reachability problem.
- If you see 502 immediately, suspect connection failure (wrong host/port, app down, firewall, socket permissions).
- If you see 504 after waiting, suspect timeouts (slow upstream, too-low proxy timeout, upstream stuck).
Example A: wrong upstream address
Pitfall: proxying to localhost when the app is in another container/VM.
- Bad: proxy_pass http://127.0.0.1:3000; (but the app is not on the same network namespace)
- Better: proxy to the correct service DNS/name/IP reachable from Nginx.
Example B: missing headers breaks auth or routing
Pitfall: the app needs the original host/scheme, but Nginx doesn’t pass them (or passes the wrong values), leading to weird redirects or auth failures that look like “502 sometimes.”
- Common set to pass through: Host, X-Forwarded-For, X-Forwarded-Proto.
- If your app is Microsoft-hosted or sitting behind Microsoft services elsewhere, be extra strict about scheme/host correctness—token callbacks and redirect URIs are unforgiving.
Example C: timeouts don’t match reality
Pitfall: long uploads or slow API calls exceed default proxy read timeouts.
- If requests legitimately take longer, raise the relevant proxy timeouts.
- If they shouldn’t, treat it as an upstream performance problem—raising timeouts just hides the symptom.
Static files and path pitfalls (404)
A surprising number of 404s come from one of three issues: the wrong root, a misunderstood location match, or alias/root used incorrectly.
If the URL maps to a directory-like path, check how Nginx resolves it.
- root appends the URI to the directory you set.
- alias replaces the matched location prefix with the directory you set (easy to get subtly wrong).
Example A: alias with a missing trailing slash
- Pitfall pattern: a location like location /static/ with alias /var/www/static (missing slash) makes Nginx build unexpected filesystem paths.
- Fix pattern: keep trailing slashes consistent: location /static/ with alias /var/www/static/.
Example B: the “try_files” trap
Pitfall: single-page apps often use try_files to fall back to index.html, but an overly broad rule can shadow real files or API routes.
- If API calls are returning HTML, your SPA fallback is probably catching /api/.
- Fix by making API locations more specific (and placed appropriately), then keep SPA fallback limited to the frontend path.
Redirect loop pitfalls (301/302)
Redirect loops usually come from Nginx and the upstream disagreeing about the “real” scheme/host, or from two layers both enforcing HTTPS/canonical host.
- If you terminate TLS at Nginx but proxy to HTTP upstream, your app must still learn that the original request was HTTPS.
- If a load balancer terminates TLS before Nginx, Nginx might only see HTTP—so your own HTTPS redirect rule can create loops if not keyed off forwarded headers.
Example A: HTTP→HTTPS forced twice
- Nginx: redirects all HTTP to HTTPS
- Upstream app: also redirects based on its own scheme detection (which might be wrong)
- Result: bounce between endpoints or repeated redirects to the same URL
Example B: canonical host mismatch
Pitfall: Nginx serves both example.com and www.example.com, but the app only expects one, so it redirects—and Nginx redirects back.
Pick one canonical host and make the “other” a single, simple redirect.
TLS pitfalls (cert errors, handshake failures, mixed content)
TLS problems are often config wiring mistakes rather than “bad certificates.” The fastest way to waste an hour is to rotate certs without confirming what Nginx is actually serving.
- If the browser shows the wrong cert, you might be hitting the wrong server block (see the next section) or SNI is mismatched.
- If handshake fails, check protocol/cipher settings only after confirming the cert chain and key match.
- If you see mixed content, your app may be generating http:// links because it thinks requests are HTTP (forwarded proto again).
A common pitfall: pointing ssl_certificate at the leaf cert only, but forgetting the full chain (behavior varies by client).
Server block matching pitfalls (wrong site answers)
If you get the default Nginx page or the wrong vhost, you’re in “matching and precedence” territory: the request isn’t landing in the server block you think it is.
If multiple server blocks listen on the same IP:port, Nginx chooses based on listen and server_name rules.
- Pitfall: a catch-all server_name like _ or a broad wildcard swallowing requests.
- Pitfall: the intended server block only listens on 443 but you’re testing http:// on 80 (or vice versa).
- Pitfall: certificate/SNI mismatch makes HTTPS land on a “default” TLS server.
When you’re unsure, temporarily make the correct server block unmistakable (for example, return a unique header or distinct error page) so you can prove which block matched.
Quick checklist: the pitfalls that waste the most time
Use this as a final sweep after you’ve followed the branch that matches your symptom.
- Editing the wrong file (enabled vs available, include paths, multiple conf.d directories).
- Forgetting precedence: a more specific location or earlier regex match changes behavior.
- Proxy headers missing (Host / X-Forwarded-Proto / X-Forwarded-For), causing auth and redirect weirdness—common when integrating with Microsoft identity flows.
- Alias vs root confusion, especially trailing slashes.
- Timeout “fixes” applied blindly, hiding an upstream regression.
- TLS chain not complete, or key/cert mismatch after renewal.
- Restarting before testing: run nginx -t first to avoid turning one problem into downtime.
One calm habit: change one thing, then re-test the exact symptom that started the investigation.
Takeaway: a small decision tree beats random poking
When Nginx misbehaves, identify the symptom (502/504, 404, redirect loop, TLS error, wrong vhost), follow the matching branch, and watch for the classic pitfalls: wrong upstream reachability, missing forwarded headers, path resolution mistakes, and server block matching surprises.
If you can explain “which block matched” and “what upstream Nginx tried to contact,” you’re usually 80% of the way to the fix.