Acquiring Real IP of Client with NGINX, Apache and WordPress (also with Cloudflare)

For this particular example I was trying to block brute force authentication to WordPress using the Limit Login Attempts Reloaded plugin.  This setup had an NGINX proxy in front of Apache that was serving a WordPress instance as a Virtual Host all running on Ubuntu (specifically 18.04 bionic). The problem was Apache (and the WordPress plugin) were seeing the IP of NGINX proxy (127.0.0.1) rather than the true IP of the client. This resulted in the IP of the NGINX proxy being blocked by WordPress.

Client—> NGINX—> Apache —> WordPress

If you are using Cloudflare, it may look like one of the following:
Client—> Cloudflare—> NGINX—> Apache —> WordPress
Client—> Cloudflare—> Apache —> WordPress

For the last example the Apache/WordPress plugin would see the IP of Cloudflare rather than the client. The steps below will work for that situation, but Cloudflare also has their own support article for an Apache behind Cloudflare configuration (using a slightly different approach): https://support.cloudflare.com/hc/en-us/articles/360029696071

To solve the issue (for any of these configurations) it requires several steps:

  1. First you need mod_remoteip for Apache
    sudo a2enmod remoteip
  2. Then create a configuration file for remoteip with any name you prefer. In this example the config file is named remoteip.
    sudo nano /etc/apache2/conf-available/remoteip
  3. This configuration file needs several lines depending on your setup (see Notes below)
    RemoteIPHeader X-Forwarded-For
    RemoteIPInternalProxy x.x.x.x
    RemoteIPTrustedProxy y.y.y.y
    LogFormat "%v:%p %a %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" vhost_combined
    LogFormat "%a %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" combined

    Notes

    1. RemoteIPInternalProxy directive should be added for a local NGINX proxy and x.x.x.x represents the internal address of the NGINX server (e.g., 127.0.0.1)
    2. For an external server such as Cloudflare, then you will need RemoteIPTrustedProxy and y.y.y.y represents the external address. For Cloudflare you would need several of these lines in CIDR notation, one for each of their IP ranges (https://www.cloudflare.com/ips/)
    3. If you have an internal proxy and an external proxy then you would need both of the above directives in your configuration file
    4. Adding LogFormat is not required to make this work however it will configure Apache to properly log the client IP.  The only change from default is replacing %h with %a.
  4. The last step is to configure the appropriate sites-enabled file of NGINX. In the same location block containing the proxy_pass IP of your Apache server, add the following lines:
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  5. Then restart the NGINX and Apache services
    sudo service apache2 restart
    sudo service nginx restart
This entry was posted in Uncategorized. Bookmark the permalink.