Why Restoring Real Client IPs Requires Explicit Trust
When an origin web server operates behind a reverse proxy, content delivery network (CDN), or load balancer, the incoming network connection terminates at the proxy. By default, both Nginx and Apache HTTP Server identify the immediate connecting proxy as the client address. While forwarding headers such as X-Forwarded-For or X-Real-IP relay client addresses, trusting these headers unconditionally allows remote clients to spoof arbitrary IP addresses by injecting custom request headers. Securing client IP restoration requires configuring origin servers to accept header overrides strictly from verified upstream proxy addresses.
Configuring Nginx with ngx_http_realip_module
Nginx manages client IP replacement using the ngx_http_realip_module. This module is not compiled into Nginx by default; it must be enabled during build time using the --with-http_realip_module configuration parameter. The module operates in the http, server, or location contexts.
Nginx Directives and Recursive Parsing
To evaluate upstream addresses, Nginx provides three core directives:
set_real_ip_from <address | CIDR | unix:>;— Declares trusted proxy addresses known to send correct replacement addresses. Accepts IPv4 addresses, IPv6 addresses (supported starting in versions 1.3.0 and 1.2.1), CIDR blocks, hostnames (added in version 1.13.1), or the special tokenunix:to trust all UNIX-domain sockets.real_ip_header <field | X-Real-IP | X-Forwarded-For | proxy_protocol>;— Defines the request header field used to replace the client address (defaults toX-Real-IP). Starting in version 1.11.0, an address containing an optional port specified according to RFC 3986 also replaces the client port. If usingproxy_protocol(added in 1.5.12), the PROXY protocol must be enabled previously via thelistendirective.real_ip_recursive on | off;— Controls multi-hop header evaluation (defaults tooff). When disabled (off), an original client address matching one of the trusted addresses is replaced by the last address sent in the header field. When enabled (on), an original client address matching one of the trusted addresses is replaced by the last non-trusted address sent in the header field.
Nginx Configuration Example
In an environment where requests pass through trusted upstream proxies (for example, 192.168.1.0/24, 192.168.2.1, and IPv6 prefix 2001:0db8::/32), enabling recursive evaluation ensures Nginx steps back through trusted hops and stops at the last non-trusted address:
set_real_ip_from 192.168.1.0/24;
set_real_ip_from 192.168.2.1;
set_real_ip_from 2001:0db8::/32;
real_ip_header X-Forwarded-For;
real_ip_recursive on;
Nginx preserves access to the original underlying network connection values via embedded variables: $realip_remote_addr retains the original client address (available since 1.9.7), and $realip_remote_port retains the original client port (available since 1.11.0).
Configuring Apache with mod_remoteip
Apache HTTP Server 2.4 provides client address replacement through the mod_remoteip module (source file mod_remoteip.c). Once replaced, the overridden useragent IP address is used for mod_authz_host Require ip checks, reported by mod_status, and recorded by mod_log_config %a and core %a format strings.
RemoteIPInternalProxy vs RemoteIPTrustedProxy
Apache distinguishes between internal intranet proxies and external trusted proxies when processing addresses in RemoteIPHeader:
RemoteIPHeader <header-field>: Triggersmod_remoteipto parse the specified header field (such asX-Forwarded-FororX-Client-IP) for useragent IP addresses. Unless proxy-filtering directives are configured,mod_remoteipwill trust all hosts presenting aRemoteIPHeaderIP value.RemoteIPInternalProxy <proxy-ip | proxy-ip/subnet | hostname> ...: Declares client intranet IP addresses trusted to present the header. Internal private addresses (10/8,172.16/12,192.168/16,169.254/16,127/8, and IPv6 addresses outside public2000::/3) are evaluated bymod_remoteiponly whenRemoteIPInternalProxyintranet proxies are registered. IntermediateRemoteIPInternalProxyaddresses are discarded rather than recorded in intermediate proxy lists.RemoteIPTrustedProxy <proxy-ip | proxy-ip/subnet | hostname> ...: Declares intermediate proxies (such as external load balancers) to trust as presenting a valid header value. UnlikeRemoteIPInternalProxy, private or intranet IP addresses reported by such proxies are not trusted as the useragent IP and remain inside the header value.RemoteIPProxiesHeader <HeaderFieldName>: Designates a header to record intermediate client IP addresses resolved during request evaluation. IntermediateRemoteIPTrustedProxyaddresses are recorded in this header, while intermediateRemoteIPInternalProxyaddresses are discarded.
Apache Logging and Underlying Connection Variables
When addresses are overridden, Apache maintains access to the physical connection details:
%{c}a: Format string inmod_log_configrepresenting the underlying client IP of the physical connection.CONN_REMOTE_ADDR: Expression variable representing the underlying client IP of the connection for use in Apache expressions.%{remoteip-proxy-ip-list}n: Format token inmod_log_configrecording the list of intermediate hosts stored in the internal request note.
Apache Configuration Example
The following example configures Apache to parse X-Forwarded-For and record intermediate proxy hops into X-Forwarded-By:
RemoteIPHeader X-Forwarded-For
RemoteIPProxiesHeader X-Forwarded-By
HAProxy PROXY Protocol Support in Apache
Available in Apache 2.4.31 and newer, mod_remoteip also implements the server side of HAProxy’s PROXY Protocol:
RemoteIPProxyProtocol On|Off: Enables or disables reading the PROXY protocol connection header. If enabled withOn, the upstream client must send the header every time it opens a connection, or the connection is aborted. Because PROXY protocol handling is connection-based, enabling it for one virtual host enables it for all virtual hosts sharing that IP address and port.RemoteIPProxyProtocolExceptions <host|range> ...: Configures specific client hosts or CIDR ranges permitted to connect directly without providing the PROXY protocol header (useful for direct monitoring or administrative traffic).
Comparing Header Processing: Nginx vs Apache
| Feature | Nginx (ngx_http_realip_module) | Apache (mod_remoteip) |
|---|---|---|
| Module Availability | Requires configuration parameter --with-http_realip_module |
Base module (mod_remoteip.c) in Apache 2.4 |
| Header Directive | real_ip_header (default: X-Real-IP) |
RemoteIPHeader (default: none) |
| Proxy Trust Configuration | set_real_ip_from (address, CIDR, hostname, unix:) |
RemoteIPInternalProxy and RemoteIPTrustedProxy |
| Multi-hop Traversal | real_ip_recursive on; replaces trusted address with the last non-trusted address |
Evaluates header list; discards internal proxies and stops when reaching an untrusted address |
| Underlying Connection Variables | $realip_remote_addr, $realip_remote_port |
%{c}a log token, CONN_REMOTE_ADDR expression variable |
| PROXY Protocol Support | real_ip_header proxy_protocol; (requires listen proxy_protocol) |
RemoteIPProxyProtocol On (Apache 2.4.31+) |

Text version of the diagrams
- Trusted Client IP Flow: Proxy hop — Forwards client address; Trust check — Matches configured proxy; Origin address — Uses restored client IP
- Nginx vs Apache IP Handling: Nginx — realip directives and recursion; Apache — remoteip proxy directives; Shared rule — Trust only known proxies
Research Method and Limitations
This guide was prepared strictly from the supplied public documentation excerpts for Nginx (ngx_http_realip_module) and Apache HTTP Server 2.4 (mod_remoteip). The Apache reference excerpt was partially truncated, limiting review of additional directive parameters (such as the detailed syntax descriptions for proxy list file directives). A critical operational limitation is that header-based client restoration alone does not protect an origin server if untrusted clients can connect directly to the origin listener; network-level access controls or firewall rules must prevent clients from bypassing trusted reverse proxies.
