NGINX Proxy Headers Checker
Check an NGINX proxy block for forwarded-header gaps, spoofed-client risks, WebSocket handling, timeout mismatches, and fix order.- {{ warning }}
| Check | Status | Severity | Observed | Evidence | Recommended action | Copy |
|---|---|---|---|---|---|---|
| {{ row.check }} | {{ row.status }} | {{ row.severity }} | {{ row.observed }} | {{ row.evidence }} | {{ row.action }} |
| Upstream field | Observed value | Expected for profile | Signal | Copy |
|---|---|---|---|---|
| {{ row.field }} | {{ row.observed }} | {{ row.expected }} | {{ row.signal }} |
| Priority | Directive | Suggested edit | Reason | Copy |
|---|---|---|---|---|
| {{ row.priority }} | {{ row.directive }} | {{ row.edit }} | {{ row.reason }} |
A reverse proxy decides which request details survive the trip from the public edge to an upstream application.
NGINX can forward a request while changing what the application sees as the host, scheme, client address, port, connection type, and upstream protocol. That metadata drives redirects, absolute URLs, secure cookies, OAuth callbacks, tenant routing, rate limits, audit logs, WebSocket upgrades, and TLS behavior to named upstreams.
The risky part is trust. A visitor can send a header named X-Forwarded-For or X-Forwarded-Proto before the request ever reaches the proxy. A public-facing proxy should normally rebuild identity and scheme headers from variables it controls. If NGINX is behind a trusted load balancer, the trusted source ranges and real-IP rules need to be explicit so spoofed client headers do not become application identity.
| Concept | What it controls | Common failure |
|---|---|---|
| Host forwarding | The public host or fixed upstream virtual host seen by the application. | Using the proxy target host when the app expects the visitor-facing host. |
| Client address chain | How the upstream reconstructs the original client and proxy hops. | Relaying a client-supplied forwarding header without appending the trusted proxy hop. |
| Scheme and port | Whether the app builds HTTP or HTTPS links and cookies. | Forwarding http or a raw inbound value on a TLS-only public route. |
| Hop-by-hop upgrade | Whether WebSocket routes pass upgrade intent upstream. | Forgetting explicit Upgrade and Connection handling. |
A snippet that works for ordinary API traffic can still be wrong for a browser app, WebSocket route, stream, or HTTPS upstream. Route profile matters because each profile changes which headers and runtime directives are significant.
How to Use This Tool:
Use the checker on one effective NGINX server, location, include, or NGINX Proxy Manager advanced block at a time.
- Set Proxy block label to the route, upstream, environment, or change ticket you are reviewing.
- Choose Route profile. Browser app and API routes focus on ordinary request metadata, WebSocket checks upgrade handling, and Streaming checks timeout and buffering choices for long-lived responses.
- Set NGINX proxy version, Public edge scheme, and Expected read timeout so the audit uses the right default assumptions.
- Paste the NGINX proxy snippet, drop a
.confor text file, use Browse conf, or load a sample. File import stops at 1 MiB, so paste the relevant effective block if a full file is too large. - Read Parsing notes before trusting the result. Brace-count or missing-semicolon warnings mean the pasted text may not represent the effective NGINX context.
- Start with Proxy Header Audit, compare expected and observed values in Request Header Map, then work through Remediation Queue before treating the score or Proxy Risk Mix chart as evidence.
Interpreting Results:
The headline band combines score, fail count, warning count, and route profile. Fix critical routing failures first, then high-severity identity and scheme findings, then lower-severity timeout, buffering, and optional-header notes.
| Band | When it appears | Action |
|---|---|---|
| Blocked | Three or more failures, or score below 55. | Do not rely on the route until critical proxy or identity failures are fixed. |
| Fix first | At least one failure remains, or score below 75. | Apply the highest-priority remediation rows and retest the same effective block. |
| Review | No failures, but warnings remain, or score below 90. | Confirm whether each warning is intentional for the selected route profile. |
| Ready | No failures or warnings, with score 90 or higher. | Validate the deployed effective config and an upstream request trace before handoff. |
A clean score does not prove the deployed proxy is secure. It means the pasted snippet matches the checked baseline for the selected profile; inherited includes, upstream trusted-proxy settings, and real traffic traces still matter.
Technical Details:
NGINX request proxying separates original request headers from headers explicitly set for the upstream request. The proxy_set_header directive changes request metadata sent to the upstream; add_header writes response headers and is the wrong tool for forwarding client identity. A local proxy_set_header context can also stop inherited header settings, so the effective block should show the complete set of required upstream request headers.
Hop-by-hop fields need special treatment. WebSocket upgrade intent is not automatically passed through a reverse proxy, so Upgrade and Connection must be forwarded deliberately. Real-client-IP handling also depends on trust boundaries: real_ip_header should be paired with narrow set_real_ip_from ranges, and recursive handling matters when trusted proxy chains contain more than one hop.
Score Core:
The audit score starts at 100 and subtracts weighted penalties for failing and warning rows. Warnings count as 60 percent of the row severity weight, rounded up.
| Severity | Fail penalty | Warning penalty |
|---|---|---|
| Critical | 28 | 17 |
| High | 18 | 11 |
| Medium | 10 | 6 |
| Low | 5 | 3 |
| Info | 0 | 0 |
Rule Core:
| Check area | Good signal | Risk signal |
|---|---|---|
| Routing | proxy_pass is present and original request headers are not disabled. |
Missing proxy_pass or proxy_pass_request_headers off creates critical failure evidence. |
| Host and scheme | Host, X-Forwarded-Host, and X-Forwarded-Proto come from proxy-controlled values or documented fixed values. |
Proxy target host, raw inbound host, or client-supplied scheme values can break redirects and security assumptions. |
| Client address | X-Forwarded-For uses $proxy_add_x_forwarded_for, and X-Real-IP uses a trusted proxy variable. |
Forwarding $http_x_forwarded_for or $http_x_real_ip trusts caller-controlled metadata. |
| Runtime behavior | Read timeout, buffering, upstream HTTP version, WebSocket upgrade, and SNI settings match the route profile. | Streaming routes with buffering on, WebSocket routes without upgrade headers, or named HTTPS upstreams without SNI can fail in production. |
Limitations and Privacy Notes:
The checker analyzes pasted text in the browser. It does not run nginx -T, follow includes, read the live process configuration, or confirm how the upstream framework trusts proxy headers.
- Paste the effective block when inherited configuration matters, especially for
proxy_set_headerand real-IP settings. - Parsing notes are important because partial snippets can hide braces, missing semicolons, or include boundaries.
- Do not paste secrets, private hostnames, or production-only tokens into output you plan to share, even when the browser-side analysis itself does not need a server lookup.
Advanced Tips:
- Use Hardened sample, Risky sample, and WebSocket sample as calibration checks before reviewing production text; the expected result pattern makes parser or profile mismatches easier to spot.
- For older deployments, set NGINX proxy version to legacy or unknown so the HTTP/1.1 and empty
Connectionkeep-alive check does not assume newer upstream defaults. - Raise Expected read timeout for streaming, long-poll, or WebSocket routes before judging
proxy_read_timeout; otherwise a route that is intentionally long-lived can look underconfigured. - Compare Request Header Map with Proxy Header Audit when a row looks surprising. The map shows the observed upstream field value and the expected pattern that drove the finding.
- Use Remediation Queue for change planning because it keeps the directive, evidence, and recommended action together, while the score and Proxy Risk Mix are better for summary reporting.
Worked Examples:
Hardened API route
A block with proxy_pass, Host $host, X-Real-IP $remote_addr, X-Forwarded-For $proxy_add_x_forwarded_for, and X-Forwarded-Proto $scheme usually clears the request-identity checks for an API route. Review remaining timeout or buffering warnings before calling the route ready.
Client-supplied forwarding header
A snippet that forwards X-Forwarded-For $http_x_forwarded_for receives a high-severity failure because the upstream can receive a value supplied by the caller. Replace it with $proxy_add_x_forwarded_for and review real-IP handling separately.
WebSocket route without upgrade handling
Select WebSocket route for a realtime location. If WebSocket upgrade headers fails, add explicit Upgrade and Connection forwarding and make sure the supporting upgrade map is present or included.
FAQ:
Why does forwarding $http_x_forwarded_for fail?
That value comes from the inbound request header. Use $proxy_add_x_forwarded_for for normal reverse-proxy chains so NGINX appends the current proxy hop instead of simply trusting the caller's header.
Should every route set the standardized Forwarded header?
No. The checker treats Forwarded as optional because many deployments still rely on X-Forwarded-* fields. Add it only when the upstream stack understands RFC 7239 metadata and compatibility has been considered.
Why do WebSocket routes need extra headers?
Upgrade and Connection are hop-by-hop headers, so they are not automatically forwarded through a reverse proxy. Select the WebSocket profile and confirm that the upgrade check passes.
Can I paste a whole NGINX file?
You can paste text directly or import a small text file, but the most useful result comes from one effective block that contains both proxy_pass and the relevant header directives.
Does Ready prove the deployed proxy is secure?
No. Ready means the pasted snippet matches the checked baseline for the selected route profile. Confirm the deployed effective config, upstream trusted-proxy settings, and a real request trace before handoff.
Glossary:
- Forwarded header
- A standardized HTTP request header from RFC 7239 that can carry proxy, client, host, and protocol metadata.
- Hop-by-hop header
- A header such as
UpgradeorConnectionthat applies to one connection step and is not automatically passed to the upstream. - Public edge
- The trusted point that knows the public scheme, host, port, and direct client or previous-proxy address.
- Real-IP handling
- NGINX logic that replaces the client address using a configured trusted source and header.
- SNI
- Server Name Indication, the TLS extension that lets a named HTTPS upstream choose the expected certificate.
- Upstream
- The backend application or service that receives the proxied request after NGINX has applied proxy rules.
References:
- NGINX ngx_http_proxy_module documentation, NGINX.
- NGINX ngx_http_realip_module documentation, NGINX.
- NGINX WebSocket proxying, NGINX.
- Keep-alive to upstreams is now default in NGINX 1.29.7, NGINX Community Blog, March 24, 2026.
- RFC 7239: Forwarded HTTP Extension, RFC Editor, June 2014.
- How to configure Nginx as a reverse proxy, Simplified Guide.