2 min read

Get Real IP Behind Cloudflare with Nginx

By default, when you place Nginx behind Cloudflare, the http_remote_addr in access_log will contain the Cloudflare IP, which is not what we want.

To enable Nginx to resolve the real IP of visitors, we need to whitelist the Cloudflare IPs and map the header value.

set_real_ip_from [Cloudflare IP]

real_ip_header CF-Connecting-IP;

To automate this process, we can write a bash script that handles this repetitive task.

/etc/nginx/cloudflare-ip-whitelist-sync.sh
#!/bin/bash
 
CLOUDFLARE_FILE_PATH=/etc/nginx/conf.d/cloudflare.conf
 
echo "#Cloudflare" > $CLOUDFLARE_FILE_PATH;
echo "" >> $CLOUDFLARE_FILE_PATH;
 
echo "# - IPv4" >> $CLOUDFLARE_FILE_PATH;
for i in `curl -s -L https://www.cloudflare.com/ips-v4`; do
    echo "set_real_ip_from $i;" >> $CLOUDFLARE_FILE_PATH;
done
 
echo "" >> $CLOUDFLARE_FILE_PATH;
echo "# - IPv6" >> $CLOUDFLARE_FILE_PATH;
for i in `curl -s -L https://www.cloudflare.com/ips-v6`; do
    echo "set_real_ip_from $i;" >> $CLOUDFLARE_FILE_PATH;
done
 
echo "" >> $CLOUDFLARE_FILE_PATH;
echo "real_ip_header CF-Connecting-IP;" >> $CLOUDFLARE_FILE_PATH;
 
#test configuration and reload nginx
nginx -t && service nginx restart

Assuming you are using Ubuntu or Debian-based systems, where Nginx automatically loads configuration files from /etc/nginx/conf.d, you can simply run bash /etc/nginx/cloudflare-ip-whitelist-sync.sh to enable the real IP from Cloudflare.

Here’s a sample content of /etc/nginx/conf.d/cloudflare.conf:

# - IPv4
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 104.16.0.0/13;
set_real_ip_from 104.24.0.0/14;
set_real_ip_from 172.64.0.0/13;
set_real_ip_from 131.0.72.0/22;

# - IPv6
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;

Since Cloudflare may update their IP addresses, it’s best practice to stay synced with them. We can set a cron job for this script to run every day at 1 am.

0 1 * * * /etc/nginx/cloudflare-ip-whitelist-sync.sh >/dev/null 2>&1

Reference: https://github.com/ergin/nginx-cloudflare-real-ip