X-Forwarded-For (XFF) is an HTTP request header that identifies the originating IP address of a client connecting to a web server through a proxy. Without it, the server sees only the IP of the last proxy. Because the header exposes the client's IP by design, a proxy that adds it passes your original address on to the destination site.
Each proxy in the chain appends the IP address it received the connection from. The leftmost entry is the claimed client and the rightmost is the most recent proxy, for example X-Forwarded-For: 203.0.113.195, 198.51.100.178.
Standard Status and Related Headers
- De facto standard: XFF is widely used but not defined in any current specification.
- Forwarded header: RFC 7239 defines a standard
Forwardedheader for the same information, but it is used much less in practice. - Companion headers:
X-Forwarded-Host,X-Forwarded-ProtoandViacarry related proxy details. - Load balancers: Some load balancers let you append the client IP to XFF, pass it through unchanged or remove it.
Trust and Spoofing
A client can send a forged X-Forwarded-For header, so only addresses added by trusted proxies are reliable. Servers that use XFF for rate limiting or access control should read the list from the right, skipping known trusted proxies, and treat the leftmost values as untrusted. If the server can also be reached directly from the internet, no part of the list can be trusted.
What X-Forwarded-For Is Used For
A server behind a proxy or load balancer logs only that device's IP address. XFF lets it recover the client's address for debugging, statistics and location-dependent content.
Reading X-Forwarded-For in NGINX
NGINX's realip module replaces the client address with one taken from a header such as X-Forwarded-For.
set_real_ip_from: Lists trusted addresses known to send correct values.real_ip_header X-Forwarded-For;: Tells NGINX which header to read.real_ip_recursive on;: Uses the last address in the header that is not trusted, instead of the last address overall.
The module is not built by default. It needs the --with-http_realip_module build option.