When your website traffic is routed through the Cloudflare, they act as a reverse proxy. This allows Cloudflare to speed up page load time by routing packets more efficiently and caching static resources (images, JavaScript, CSS, etc.). As a result, when responding to requests and logging them, your origin server returns a Cloudflare IP instead of user’s real IP address.

Example. If you have a wordpress website running behind NGINX and you face an issue with spam. You would want to see the IP addresses of the users who are spamming your website. Normally, without cloudflare it is straight forward, you just look up in NGINX access log file and get the client IP addresses. But when the website is behind Cloudflare, you’ll see Cloudflare’s IP instead of user’s real IP.

The following diagram illustrates the different ways that IP addresses are handled with and without Cloudflare.

How to find real ip address behind cloudflare?

Solution: There is an easy fix for this. You just need to tell you webserver, in this case NGINX that whenever it is a cloudflare IP, tell me the real user’s IP. In this case we will use Module ngx_http_realip_module.

Where can I find Cloudflare IP ranges?

Cloudflare publishes their IP ranges at https://www.cloudflare.com/en-gb/ips. They often update thes IPS. So it becomes repetitive task keep updating these Nginx headers. That is why we have made this little script to always show the latest header rules based on current cloudflare IP address ranges.

Cloudflare Real IP header (Updated Daily)

You can just copy and paste the code from the next block into you NGINX server block and then you will start seeing real IP addresses of users on your website.

Note: You may have to change your code to look for IP addresses in CF-Connecting-IP header.

# Add following to get user's real IPs info from Cloudflare
# (last updated 30 Jul 2021)
set_real_ip_from 173.245.48.0/20;
set_real_ip_from 103.21.244.0/22;
set_real_ip_from 103.22.200.0/22;
set_real_ip_from 103.31.4.0/22;
set_real_ip_from 141.101.64.0/18;
set_real_ip_from 108.162.192.0/18;
set_real_ip_from 190.93.240.0/20;
set_real_ip_from 188.114.96.0/20;
set_real_ip_from 197.234.240.0/22;
set_real_ip_from 198.41.128.0/17;
set_real_ip_from 162.158.0.0/15;
set_real_ip_from 172.64.0.0/13;
set_real_ip_from 131.0.72.0/22;
set_real_ip_from 104.16.0.0/13;
set_real_ip_from 104.24.0.0/14;
set_real_ip_from 2400:cb00::/32;
set_real_ip_from 2606:4700::/32;
set_real_ip_from 2803:f800::/32;
set_real_ip_from 2405:b500::/32;
set_real_ip_from 2405:8100::/32;
set_real_ip_from 2a06:98c0::/29;
set_real_ip_from 2c0f:f248::/32;
real_ip_header CF-Connecting-IP;

Bonus Setup: A bash script to automatically update nginx configs with updated IPs

Here is a nifty little resource that lets you keep you nginx file up to date through a bash script. It basically does the same thing as above but through a cron job. Check it out.

nginx-cloudflare-real-ip