Mod Remote IP
Luke Hebert
- 3 minutes read - 474 wordsGetting mod_remoteip to report the correct client IP under Apache 2.4 can be a frustrating afternoon of trial and error. The issue usually comes down to two things: cPanel misconfiguring the log directive, and the module being loaded but never actually included in the vhost. Once both are fixed, the real challenge is understanding how %a and %{c}a map to the proxy IP versus the real client IP. The key insight is that mod_remoteip expects two distinct headers: one identifying the proxy system (used for ACL and trust control) and one carrying the real client IP. Once you wire those up correctly, the fix propagates to access logs, error logs, and every tied-in module like mod_security.
The Problem
After a full day of debugging, the symptoms looked like this:
- The log directive was wrong (thanks, cPanel).
- The module was set up but not included in the vhost (thanks again, cPanel).
- The values of
%{c}aandX-Forwarded-Fordid not match up in the access log.
A quick workaround is to swap %a for %{X-Forwarded-For}i in the LogFormat directive, but that only patches the log output. Modules that rely on the connection IP (mod_security, mod_geoip, rate limiters, etc.) still see the proxy address.
How mod_remoteip Actually Works
The documentation for mod_remoteip is dense, but the core idea is straightforward. You have two headers at play:
- One represents the system doing the proxying (the internal proxy).
- One carries the real client IP (the forwarded header).
One acts as an ACL or trust control, while the other retains the actual user IP.
Working Configuration
After some trial and error (and a good chunk of time spent with Gabriel), this is what finally worked:
LogFormat "%a %l %u %t \"%r\" %s %b \"%{Referer}i\" \"%{User-agent}i\"" combined_forwardedWith this in place:
%anow contains the Client IP (the real user IP).%{c}anow contains the Proxy system IP (the connecting IP), as described in the mod_remoteip and Apache 2.4 documentation.
The RemoteIP directives that made it click:
RemoteIPInternalProxy 198.1.121.233 # The system we get proxied from
RemoteIPHeader X-Forwarded-For # The real IP header
RemoteIPInternalProxy 198.154.231.144 # The system we get proxied from
RemoteIPHeader X-Forwarded-For # The real IP headerUse mod_remoteip rather than the %{X-Forwarded-For}i log-format shortcut. The shortcut only fixes log output. mod_remoteip corrects the IP at the connection level, so mod_security, mod_geoip, and every other IP-aware module see the real client address.
Why This Matters
If you only patch the LogFormat, your access logs will look correct but your security rules, geo-blocking, and rate limiting will all key off the proxy IP. That means a single proxy IP can trigger or bypass rules for every client behind it. mod_remoteip solves this at the right layer, keeping the access log, error log, and every other IP-aware module in sync.