Overview of ngx_http_realip_module
The ngx_http_realip_module is a core Nginx module designed to extract the original client's real IP address from HTTP headers set by proxy servers (like CDNs or load balancers) when Nginx sits behind a reverse proxy.
Without this module, Nginx access logs and backend applications (e.g., PHP via $_SERVER['REMOTE_ADDR']) will record the IP of the last proxy server, not the end user. This affects access statistics, security auditing, and geo-restriction features.
Installation and Verification
Most precompiled Nginx packages include this module. Verify with:
nginx -V 2>&1 | grep -o http_realip_module
If http_realip_module is printed, it's available. For custom compilation, add --with-http_realip_module to ./configure.
Basic Configuration and Use Cases
Single Reverse Proxy
Architecture: Client (IP: 123.123.123.123) → Proxy (IP: 10.10.10.10) → Backend Nginx.
Without realip, backend logs show 10.10.10.10. To get the real client IP, add this to the http, server, or location context:
set_real_ip_from 10.10.10.10;
real_ip_header X-Forwarded-For;
set_real_ip_from: Defines trusted proxy IPs or CIDR ranges.real_ip_header: Specifies the HTTP header containing the real IP (e.g.,X-Forwarded-FororX-Real-IP).
After configuration, Nginx uses the first IP from X-Forwarded-For (123.123.123.123) as the real client IP, overwriting the $remote_addr variable.
Multiple Proxies and real_ip_recursive
Complex architecture: Client → Proxy1 (192.168.1.10) → Proxy2 (10.10.10.10) → Backend Nginx.
The X-Forwarded-For header received may be: 123.123.123.123, 192.168.1.10, 10.10.10.10.
With basic config:
set_real_ip_from 10.10.10.10;
real_ip_header X-Forwarded-For;
# real_ip_recursive is off by default
Nginx incorrectly takes the last IP (10.10.10.10). To fix, enable real_ip_recursive and list all trusted proxies:
set_real_ip_from 10.10.10.10;
set_real_ip_from 192.168.1.10;
real_ip_header X-Forwarded-For;
real_ip_recursive on;
- real_ip_recursive off (default): Uses the last IP in the specified header.
- real_ip_recursive on: Traverses the header from right to left, skipping IPs in
set_real_ip_from, and selects the first untrusted IP as the real client IP.
In the example, Nginx checks: 10.10.10.10 (trusted, skip) → 192.168.1.10 (trusted, skip) → 123.123.123.123 (untrusted, selected).
Configuration Example and Verification
Full example for nginx.conf:
# Define trusted proxy IP ranges
set_real_ip_from 10.0.0.0/8;
set_real_ip_from 192.168.0.0/16;
# Specify the HTTP header containing the real IP
real_ip_header X-Forwarded-For;
# Enable recursive search for multi‑proxy chains
real_ip_recursive on;
Reload Nginx: nginx -s reload.
Verify by checking access logs. Ensure the $remote_addr variable shows the real client IP. Example log format:
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
Important Notes and Common Issues
- Security: Only add trusted proxy IPs to
set_real_ip_from. Misconfiguration allows IP spoofing via forged headers. - Header Selection: Coordinate with upstream proxies on which header to use (commonly
X-Forwarded-FororX-Real-IP). - Variable Override: The module modifies
$remote_addr, affecting all features relying on it (e.g., rate limiting, access control). - PROXY Protocol: For proxies using PROXY protocol (common in TCP/UDP), use
listen ... proxy_protocol;andreal_ip_header proxy_protocol;instead.
Proper configuration ensures your logs and security policies are based on accurate end‑user IPs, even behind complex proxy networks.