TL;DR: Follow the bold commands to configure Apache 2 with mod_remoteip on a Ubuntu or Debian server to securely recover visitor IPs from Cloudflare proxies.
Background
When a reverse proxy makes a request to a webserver, the webserver will see the proxy’s own IP ip address instead of the visitor’s own IP. Therefore, the server logs will also just show the proxy’s IP and any .htaccess “Require ip” rules will fail. I encountered this problem when I started using Cloudflare load balancing for this blog. Luckily, most proxy servers also forward the visitor’s IP in a special headers such as “X-Forwarded-For” or “HTTP_CLIENT_IP”. The major problem with blindly using those headers is that they can be faked. Relying on those headers might, therefore, potentially open up security risks. Additionally, if the request passed multiple proxy servers – as it’s sometimes the case with Cloudflare -, the X-Forwarded-For header might contain multiple, comma-separated IPs. A simple solution to all these issues is to use the Apache 2 module mod_remoteip which takes care of the formatting and allows to define trusted proxy sources in order to fight any “X-Forwarded-For” spoofing.
Installation and Configuration
The server environment used for this tutorial runs on Ubuntu 24.04 and Apache version 2.4. The tutorial should, however, be compatible with most operating system versions of Ubuntu and Debian. While this howto is specifically written for the use with Cloudflare, it is also valid for use with other proxy servers.
To enable mod_remoteip, run the following command on your server:
sudo a2enmod remoteip
Next, create a configuration file named remoteip.conf in /etc/apache2/conf-available/ that will be used to define the special cloudflare header CF-Connecting-IP and the list of trusted proxy servers.
nano /etc/apache2/conf-available/remoteip.conf
At a bare minimum two parameters need to be defined in this configuration file: The header mod_remoteip is supposed to use to recover the visitor’s IP and at least one trusted procy IP. A general purpose example configuration could look like this:
RemoteIPHeader X-Forwarded-For
RemoteIPTrustedProxy 192.168.0.1
RemoteIPTrustedProxy 192.168.0.2
For Cloudflare there’s a long list of proxies that need to be defined as trusted. While it is possible to add every possible Cloudflare IP [2], there’s a much easier way by using the RemoteIPInternalProxyList directive. The correct remoteip.conf file for Cloudflare should look like this:
RemoteIPHeader CF-Connecting-IP
RemoteIPInternalProxyList /etc/apache2/conf-available/trusted-proxies.lst
Of course you can pick a different location for the trusted proxies list, but make sure to adapt the following instructions accordingly to your path selection. Next, the list file needs to be filled with all valid IPv4 and IPv6 address ranges that are supposed to be trusted. Edit the list file to add all the trusted proxy IPs.
nano /etc/apache2/conf-available/trusted-proxies.lst
This is a complete list of Cloudflare IP adress ranges that need to be trusted. The list has been compiled at the time of this article and may of course change in the future if Cloudflare ever decides to add or drop IP adresses.
173.245.48.0/20
103.21.244.0/22
103.22.200.0/22
103.31.4.0/22
141.101.64.0/18
108.162.192.0/18
190.93.240.0/20
188.114.96.0/20
197.234.240.0/22
198.41.128.0/17
162.158.0.0/15
104.16.0.0/13
104.24.0.0/14
172.64.0.0/13
131.0.72.0/22
2400:cb00::/32
2606:4700::/32
2803:f800::/32
2405:b500::/32
2405:8100::/32
2a06:98c0::/29
2c0f:f248::/32
Now the configuration file needs to be enabled by changing into the /etc/apache2/conf-available/ directory and enabling remoteip.conf.
cd /etc/apache2/conf-available/
sudo a2enconf remoteip
If sudo apache2ctl configtest doesn’t show any errors, Apache can be reloaded in order to apply the new settings.
sudo systemctl reload apache2
Apache now rewrites all IPs to reflect the correct user IP. There is no need to adjust the log file format or any .htaccess rules after enabling the mod!
Future Proofing
It is possible that Cloudflare adds or drops IP ranges in the future. All the IPs they currently use can be looked up from the official website [2] To automate this process, a PHP script was created to automatically pull all IPs that Cloudflare officially lists on their website and combine them into a valid list file. The list is updated once a day and is available for free from https://api.baltic-lab.com/trusted-proxies.lst. With the help of wget this file can be requested from my server using a cron job. Unfortunately, wget outputs on stderr rather than stdout, so “&> /dev/null” must be used if your intention is to suppress cron job messages.
crontab -e
Add the following line to update the trusted-proxies.lst once daily at midnight:
0 0 * * * wget -P /etc/apache2/conf-available/ https://api.baltic-lab.com/trusted-proxies.lst
If you previously chose a different path other than “/etc/apache2/conf-available/”, be sure to adjust it accordingly in your crontab.
Conclusion
Links and Sources:
[1] Apache Module mod_remoteip, Apache: https://httpd.apache.org/
[2] Restoring original visitor IPs, Cloudflare: https://developers.cloudflare.com/
[3] IP ranges, Cloudflare: https://www.cloudflare.com/ips/
Westerhold, S. (2024), "Restoring proxied visitor IPs from Cloudflare". Baltic Lab High Frequency Projects Blog. ISSN (Online): 2751-8140., https://baltic-lab.com/2024/12/restoring-proxied-visitor-ips-from-cloudflare/, (accessed: January 4, 2025).
- Restoring proxied visitor IPs from Cloudflare - December 26, 2024
- Simple Microphone Preamplifier - December 11, 2024
- DIY Spark Gap Transmitter - April 6, 2024