{"id":11033,"date":"2021-12-07T16:06:14","date_gmt":"2021-12-07T21:06:14","guid":{"rendered":"http:\/\/local.brightwhiz\/?p=11033"},"modified":"2021-12-07T16:44:16","modified_gmt":"2021-12-07T21:44:16","slug":"real-client-ip-address-cloudflare-apache-php","status":"publish","type":"post","link":"http:\/\/local.brightwhiz\/real-client-ip-address-cloudflare-apache-php\/","title":{"rendered":"Get the Real Client IP Address With Cloudflare CF-Connecting-IP in Apache | PHP"},"content":{"rendered":"\n

Cloudflare is a website security service from a company of the same name that provides content delivery network and DDoS mitigation services. For several good reasons, you want to know the Real Client IP Address of your visitors.<\/p>\n\n\n\n

With Cloudflare like any proxy, the webserver will not be able to tell what the visitor’s IP address is. This can open up several security issues because your Apache<\/a> access and error logs will not show the correct IP but rather those of the Cloudflare infrastructure.<\/p>\n\n\n\n

It also becomes difficult to define IP restrictions in your web server configuration, .htaccess, or even in PHP<\/a> scripts.<\/p>\n\n\n\n

Real Client IP Address Using CF-Connecting-IP<\/h2>\n\n\n\n

To solve this problem, Cloudflare sends the real client IP as CF-Connecting-IP in the HTTP header. CF-Connecting-IP provides the real client (visitor) IP address to the origin web server. cf-connecting-ip contains a special Cloudflare IP 2a06:98c0:3600:0:0:0:0:103 when the request originates from a Cloudflare Workers subrequest instead of the visitor’s true IP.<\/p>\n\n\n\n

This works similar to the x-forwarded-for header which is used by proxy servers to tell the origin of any HTTP servers involved in relaying the request between the user and the origin.<\/p>\n\n\n\n

There are some differences between CF-Connecting-IP and x-forwarded-for headers. With x-forwarded-for, you may see one or multiple sets of IP addresses in this header while CF-Connecting-IP will always contain one IP.<\/p>\n\n\n\n

If Cloudflare does not receive the x-forwarded-for header from the client it will pass the same value as CF-Connecting-IP to the origin web server<\/a>.<\/p>\n\n\n\n

Cloudflare recommends your logs or applications look at CF-Connecting-IP or True-Client-IP instead of X-Forwarded-For since CF-Connecting-IP and True-Client-IP have a consistent format containing only one IP.<\/p>\n\n\n\n

How to Handle CF-Connecting-IP on the Origin Server<\/h2>\n\n\n\n

We can retrieve the value of CF-Connecting-IP on the origin web server by enabling Apache’s mod mod_remoteip.<\/p>\n\n\n\n

First, you need to enable remoteip <\/em>on your server. In Ubuntu\/Debian as well as CentOS\/RHEL based systems run the following commands:<\/p>\n\n\n\n

$ sudo a2enmod remoteip<\/code><\/pre>\n\n\n\n

Then restart Apache:<\/p>\n\n\n\n

$ sudo systemctl restart apache2<\/code><\/pre>\n\n\n\n

Edit Apache Configs to Define Trusted Proxies<\/p>\n\n\n\n

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 remoteip.conf<\/strong>.<\/p>\n\n\n\n

Create the remoteip.conf<\/strong> configuration file by running this command in Ubuntu<\/a>\/Debian<\/a> Linux<\/a> systems.<\/p>\n\n\n\n

$ sudo nano \/etc\/apache2\/conf-enabled\/remoteip.conf<\/code><\/pre>\n\n\n\n

On CentOS<\/a>\/RHEL Linux systems run this:<\/p>\n\n\n\n

$ sudo nano \/etc\/httpd\/conf.d\/remoteip.conf<\/code><\/pre>\n\n\n\n

Add RemoteIPHeader CF-Connecting-IP as the first line and then a list of trusted Cloudflare proxies below it as RemoteIPTrustedProxy directives.<\/p>\n\n\n\n

We do the above to mitigate hackers trying to spoof CF-Connecting-IP in the HTTP header by making sure that Apache knows which proxies to trust.<\/p>\n\n\n\n

You can find an updated list of these IP addresses for Cloudflare IPv4 Proxies and Cloudflare IPv6 Proxies respectively.<\/p>\n\n\n\n

RemoteIPHeader CF-Connecting-IP\nRemoteIPTrustedProxy 173.245.48.0\/20\nRemoteIPTrustedProxy 103.21.244.0\/22\nRemoteIPTrustedProxy 103.22.200.0\/22\nRemoteIPTrustedProxy 103.31.4.0\/22\nRemoteIPTrustedProxy 141.101.64.0\/18\nRemoteIPTrustedProxy 108.162.192.0\/18\nRemoteIPTrustedProxy 190.93.240.0\/20\nRemoteIPTrustedProxy 188.114.96.0\/20\nRemoteIPTrustedProxy 197.234.240.0\/22\nRemoteIPTrustedProxy 198.41.128.0\/17\nRemoteIPTrustedProxy 162.158.0.0\/15\nRemoteIPTrustedProxy 104.16.0.0\/13\nRemoteIPTrustedProxy 104.24.0.0\/14\nRemoteIPTrustedProxy 172.64.0.0\/13\nRemoteIPTrustedProxy 131.0.72.0\/22\nRemoteIPTrustedProxy 2400:cb00::\/32\nRemoteIPTrustedProxy 2606:4700::\/32\nRemoteIPTrustedProxy 2803:f800::\/32\nRemoteIPTrustedProxy 2405:b500::\/32\nRemoteIPTrustedProxy 2405:8100::\/32\nRemoteIPTrustedProxy 2a06:98c0::\/29\nRemoteIPTrustedProxy 2c0f:f248::\/32<\/code><\/pre>\n\n\n\n

Save and exit then restart Apache.<\/p>\n\n\n\n

$ sudo systemctl restart apache2<\/code><\/pre>\n\n\n\n

Note: 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.<\/p>\n\n\n\n

If Apache detects CF-Connecting-IP but it is coming from an IP not defined in RemoteIPTrustedProxy, Apache will fall back to the REMOTE_ADDR.<\/p>\n\n\n\n

Verify the Apache Access and Error Logs<\/h2>\n\n\n\n

If you find that your access and error logs are showing the Cloudflare proxy IP instead of the remote user IP then you will need to complete these steps.<\/p>\n\n\n\n

Note: You can verify by visiting your website then checking the logs for your IP for example:<\/p>\n\n\n\n

$ sudo tail \/var\/log\/apache2\/access.log -n 20<\/code><\/pre>\n\n\n\n

To fix the issue in case it’s not your IP that is being logged, edit apache2.conf like so:<\/p>\n\n\n\n

$ sudo nano \/etc\/apache2\/apache2.conf<\/code><\/pre>\n\n\n\n

The search type CTRL + W to search for LogFormat.<\/p>\n\n\n\n

The default log format should look something similar to below:<\/p>\n\n\n\n

LogFormat "%v:%p %h %l %u %t \\"%r\\" %>s %O \\"%{Referer}i\\" \\"%{User-Agent}i\\"" vhost_combined\nLogFormat "%h %l %u %t \\"%r\\" %>s %O \\"%{Referer}i\\" \\"%{User-Agent}i\\"" combined\nLogFormat "%h %l %u %t \\"%r\\" %>s %O" common\nLogFormat "%{Referer}i -> %U" referer\nLogFormat "%{User-agent}i" agent<\/code><\/pre>\n\n\n\n

Change the %h<\/strong> variable to %a<\/strong>, which is the Client IP as defined by the mod_remoteip module. The %h<\/strong> variable is the Remote IP.<\/p>\n\n\n\n

Your LogFormat entries should look like this now:<\/p>\n\n\n\n

LogFormat "%v:%p %a %l %u %t \\"%r\\" %>s %O \\"%{Referer}i\\" \\"%{User-Agent}i\\"" vhost_combined\nLogFormat "%a %l %u %t \\"%r\\" %>s %O \\"%{Referer}i\\" \\"%{User-Agent}i\\"" combined\nLogFormat "%a %l %u %t \\"%r\\" %>s %O" common\nLogFormat "%{Referer}i -> %U" referer\nLogFormat "%{User-agent}i" agent<\/code><\/pre>\n\n\n\n

Save and exit the file then restart Apache:<\/p>\n\n\n\n

$ sudo systemctl restart apache2<\/code><\/pre>\n\n\n\n

Access the website again then view the access log to see if it is now logging the correct IP:<\/p>\n\n\n\n

$ sudo tail \/var\/log\/apache2\/access.log -n 20<\/code><\/pre>\n\n\n\n

Get the Real Client IP Address From Within PHP<\/p>\n\n\n\n

To get the real client IP address in PHP using the following:<\/p>\n\n\n\n

\/\/ real IP of visitor\necho $_SERVER["HTTP_CF_CONNECTING_IP"]; \n\n\/\/country of visitor\necho $_SERVER["HTTP_CF_IPCOUNTRY"]; \n\n\/\/cloudflare IP\necho $_SERVER["REMOTE_ADDR"];<\/code><\/pre>\n\n\n\n

We retrieve the $_SERVER[“REMOTE_ADDR”] to verify that it contains an actual Cloudflare proxy IP address just in case a bad actor has faked the CF-Connecting-IP header if they have connected directly to the server.<\/p>\n\n\n\n

Get the list of Cloudflare Ip addresses from the links below:<\/p>\n\n\n\n