Get Real Client IP from Cloudflare and pass to Apache or PHP using CF-Connecting-IP and Apache mod

How to Get the Real Client IP Address from Cloudflare in Apache or PHP

Last updated on

In this article we will learn how to get the real client IP from Cloudlfare (CF-Connecting-IP) and pass it on to PHP or Apache with mod_remoteip.

Introduction

Cloudflare is great as a quick-and-easy CDN and DDoS protection, but one downside is that the IP address seen by your web server will be that of the Clouflare proxy and not the actual client.

This can be a big security issue because your Apache access and error logs will only show the IP of the Cloudflare proxy and not the actual client. Also, if you have IP restrictions in place defined in .htaccess or a PHP script, these will not work.

Cloudflare sends the real client IP as CF-Connecting-IP in the HTTP header, and we can pass this on to PHP or Apache using mod_remoteip.

Note: Cloudflare’s own Apache mod mod_cloudflare is now redundant and discontinued as Apache’s own mod mod_remoteip performs the same function.

PHP Script

You can easily fetch the real client IP in PHP with no further configuration required.

echo $_SERVER["HTTP_CF_CONNECTING_IP"]; // real IP of visitor
echo $_SERVER["HTTP_CF_IPCOUNTRY"]; //country of visitor

If you do this, and the validity of the visiting IP address is important, you might need to verify that the $_SERVER["REMOTE_ADDR"] contains an actual Cloudflare proxy IP address, because anyone can fake the header if they are able to connect directly to the server. See “Trusted Proxies” down the page for more info.

Apache

This configuration was tested on Ubuntu 18.04 so the process should be similar for any Debian-based web servers.

This method also works for Virtual Hosts. If you have multiple sites hosted and some do not use Cloudlfare, Apache will simply default back to the Remote Address (REMOTE_ADDR).

Enable remoteip mod

Firstly, enable the remoteip mod.

sudo a2enmod remoteip

Restart Apache:

sudo systemctl restart apache2

Edit Config and Define Trusted Proxies

In order to pass the real client IP address from Cloudflare to Apache, we need to define the RemoteIPHeader directive as CF-Connecting-IP in the remoteip configuration file /etc/apache2/conf-enabled/remoteip.conf.

Create the remoteip.conf configuration file:

sudo nano /etc/apache2/conf-enabled/remoteip.conf

Simply add RemoteIPHeader CF-Connecting-IP as the first line and then a list of trusted Cloudflare proxies below it (RemoteIPTrustedProxy). As it’s easy for hackers to spoof CF-Connecting-IP in the http header, we need to make sure that Apache knows which proxies to trust. The proxies I’ve included below are correct as of June 2019. Cloudflare keeps an updated list of these proxies here: Cloudflare IPv4 Proxies and Cloudflare IPv6 Proxies.

/etc/apache2/conf-enabled/remoteip.conf
RemoteIPHeader CF-Connecting-IP
RemoteIPTrustedProxy 173.245.48.0/20
RemoteIPTrustedProxy 103.21.244.0/22
RemoteIPTrustedProxy 103.22.200.0/22
RemoteIPTrustedProxy 103.31.4.0/22
RemoteIPTrustedProxy 141.101.64.0/18
RemoteIPTrustedProxy 108.162.192.0/18
RemoteIPTrustedProxy 190.93.240.0/20
RemoteIPTrustedProxy 188.114.96.0/20
RemoteIPTrustedProxy 197.234.240.0/22
RemoteIPTrustedProxy 198.41.128.0/17
RemoteIPTrustedProxy 162.158.0.0/15
RemoteIPTrustedProxy 104.16.0.0/12
RemoteIPTrustedProxy 172.64.0.0/13
RemoteIPTrustedProxy 131.0.72.0/22
RemoteIPTrustedProxy 2400:cb00::/32
RemoteIPTrustedProxy 2606:4700::/32
RemoteIPTrustedProxy 2803:f800::/32
RemoteIPTrustedProxy 2405:b500::/32
RemoteIPTrustedProxy 2405:8100::/32
RemoteIPTrustedProxy 2a06:98c0::/29
RemoteIPTrustedProxy 2c0f:f248::/32

Save and exit (press CTRL + X, press Y and then press ENTER)

If Apache doesn’t detect CF-Connecting-IP in the HTTP header (e.g. if Cloudflare is turned off or not configured for a particular Virtual Host), it will fall back to the Remote Address (REMOTE_ADDR).

If Apache does detect CF-Connecting-IP but it is coming from an IP not defined in RemoteIPTrustedProxy (e.g. a hacker trying to spoof the headers), Apache will fall back to the Remote Address (REMOTE_ADDR).

Apache Access and Error Logs

In order for the real client IP (CF-Connecting-IP) to appear in access.log and error.log, we must make a small change to apache2.conf.

Edit apache2.conf:

sudo nano /etc/apache2/apache2.conf

Press CTRL + W and search for LogFormat.

The default log format should look something similar to below:

/etc/apache2/apache2.conf
LogFormat "%v:%p %h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" vhost_combined
LogFormat "%h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" combined
LogFormat "%h %l %u %t \"%r\" %>s %O" common
LogFormat "%{Referer}i -> %U" referer
LogFormat "%{User-agent}i" agent

The %h variable in red here is the Remote IP. We just need to change this to %a, which is the Client IP as defined by the mod_remoteip module.

/etc/apache2/apache2.conf
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
LogFormat "%a %l %u %t \"%r\" %>s %O" common
LogFormat "%{Referer}i -> %U" referer
LogFormat "%{User-agent}i" agent

Save and exit (press CTRL + X, press Y and then press ENTER)

Restart Apache:

sudo systemctl restart apache2

To view the access log to see if it is now reporting CF-Connecting-IP:

sudo tail /var/log/apache2/access.log -n 200

Make sure that the Cloudlfare Proxy IP does not appear in the access log, but instead your own client IP.

If Apache doesn’t detect CF-Connecting-IP in the HTTP header (e.g. if Cloudflare is turned off or not configured for a particular Virtual Host), the log will fall back to the Remote Address (REMOTE_ADDR).

If Apache does detect CF-Connecting-IP but it is coming from an IP not defined in RemoteIPTrustedProxy (e.g. a hacker trying to spoof the headers), the log will fall back to the Remote Address (REMOTE_ADDR).

Let me know in the comments if this helped. Follow me on Twitter, Facebook and YouTube.

p.s. I increased my AdSense revenue by 68% using AI 🤖. Read my Ezoic review to find out how.

1 Star2 Stars3 Stars4 Stars5 Stars 5.00 (1 votes)

Leave a Reply

Your email address will not be published. Required fields are marked *

We use Markdown to style comments, like on Github and Reddit.
To do a line break, type two spaces after the sentence.
You can add inline code by wrapping it in backticks: `code here`

    To do an entire block of code  
    type four spaces before the line
    and it will appear in a block like this.
    <-- four empty spaces