Hosting · WordPress · performance · infrastructure
how to

Configuring Trusted Reverse Proxy Headers in Nginx and Apache mod_remoteip

Short answer

Configure Nginx ngx_http_realip_module and Apache mod_remoteip to securely restore client IP addresses from trusted reverse proxies while preventing header spoofing.

Research-based

Last verified:

Applies to: Nginx ngx_http_realip_module; Apache HTTP Server 2.4 mod_remoteip, with PROXY protocol directives requiring Apache 2.4.31+

Flow from trusted proxy through address validation to restored client IP

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 token unix: 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 to X-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 using proxy_protocol (added in 1.5.12), the PROXY protocol must be enabled previously via the listen directive.
  • real_ip_recursive on | off; — Controls multi-hop header evaluation (defaults to off). 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>: Triggers mod_remoteip to parse the specified header field (such as X-Forwarded-For or X-Client-IP) for useragent IP addresses. Unless proxy-filtering directives are configured, mod_remoteip will trust all hosts presenting a RemoteIPHeader IP 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 public 2000::/3) are evaluated by mod_remoteip only when RemoteIPInternalProxy intranet proxies are registered. Intermediate RemoteIPInternalProxy addresses 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. Unlike RemoteIPInternalProxy, 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. Intermediate RemoteIPTrustedProxy addresses are recorded in this header, while intermediate RemoteIPInternalProxy addresses are discarded.

Apache Logging and Underlying Connection Variables

When addresses are overridden, Apache maintains access to the physical connection details:

  • %{c}a: Format string in mod_log_config representing 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 in mod_log_config recording 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 with On, 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+)
Comparison of Nginx and Apache trusted IP handling

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.