HTTP Forwarded Header Reference

X-Forwarded-For, X-Forwarded-Proto, Forwarded header syntax with proxy chain notes.

Reference for HTTP forwarding headers — the standardised RFC 7239 Forwarded header and legacy X-Forwarded-For, X-Forwarded-Proto and X-Forwarded-Host — with proxy-chain parsing. It runs free in your browser on Gera Tools, with nothing uploaded.

Last updated Source: Gera Tools

What does X-Forwarded-For contain?

It is a comma-separated list of IP addresses appended as a request passes through proxies. The leftmost is the original client as seen by the first proxy, and each subsequent entry is added by the next hop. Because clients can spoof it, only entries added by proxies you trust are reliable.

How proxies preserve client information

When a request passes through reverse proxies and load balancers, the backend sees the proxy’s address, not the client’s. Forwarding headers carry the original client IP, protocol and host along the chain. This reference covers the standardised Forwarded header and the legacy X-Forwarded-* set, plus how to parse a proxy chain safely.

Legacy vs standard headers

PurposeLegacy headerStandard (RFC 7239)
Client IP chainX-Forwarded-For: a, b, cForwarded: for=a, for=b
Original schemeX-Forwarded-Proto: httpsForwarded: proto=https
Original hostnameX-Forwarded-Host: example.comForwarded: host=example.com
Receiving proxy identity(no standard legacy equivalent)Forwarded: by=proxy.example

The legacy set is more widely supported by existing middleware and CDNs. The RFC 7239 Forwarded header is the formal standard and carries more information in a single, unambiguous field. Many modern proxies and frameworks support both.

How it works

Each proxy appends what it observed. The legacy headers split the data across three fields; the standard Forwarded header combines them:

X-Forwarded-For: 203.0.113.7, 198.51.100.2, 10.0.0.1
X-Forwarded-Proto: https
X-Forwarded-Host: example.com

Forwarded: for=203.0.113.7;proto=https;host=example.com, for=198.51.100.2

The list grows left-to-right as hops are traversed, so the leftmost X-Forwarded-For entry is the original client as reported — but any client can forge entries. Trust only the addresses appended by proxies you control: count back from the right by your number of trusted hops to find the true client IP.

Extracting the real client IP safely

The naive approach — reading the leftmost X-Forwarded-For value — is exploitable. An attacker can send a request with a crafted X-Forwarded-For header to spoof an arbitrary IP. For example:

X-Forwarded-For: 1.2.3.4, 203.0.113.7

If your CDN or load balancer appends the real client address on the right and you trust the leftmost entry, an attacker who sends X-Forwarded-For: 1.2.3.4 in their request will appear to come from 1.2.3.4.

The correct approach: configure your framework with the number of trusted reverse proxies in your infrastructure. From the rightmost address in the chain, count back by that number. The address at that position is the real client IP — everything to its left was supplied by the client or untrusted intermediaries.

Most frameworks expose this directly: Express (trust proxy: 1), Django (NUM_PROXIES), Laravel (TrustProxies middleware), etc. Set the count to match your actual infrastructure and let the framework do the math.

Tips and notes

  • Configure a trusted-proxy count in your framework; never trust the leftmost value unconditionally.
  • IPv6 in Forwarded must be quoted and bracketed: for="[2001:db8::1]".
  • X-Forwarded-Proto lets a TLS-terminating proxy tell the app the original scheme was https, so redirect logic and Secure cookie checks work correctly behind a proxy.
  • Prefer Forwarded for new systems; keep X-Forwarded-* for compatibility with existing tooling.
  • RFC 7239 allows obfuscated identifiers (for=_hidden) and the special token unknown when the address cannot be disclosed.