Linux

Log real IP address with CloudFlare and nginx

When you have a website behind the CloudFlare DNS (using its CDN services), chances are your nginx access logs are logging CloudFlare IP addresses. This is due to the fact that your are serving content where CloudFlare acts as proxy. To log the visitor’s real IP address, you need to modify some configuration or even rebuild nginx for that purpose.

To rebuild or not?

nginx has a module called HttpRealipModule where it allows setting real IP address for a given source IP by using the standard header values passed by proxy servers. This will allow us to tell nginx to pickup CloudFlare’s CF-Connecting-IP header value and use it as the real IP address and will be used when logging to access logs.

This feature requires that nginx is built with --with-http-realip_module build option. My current version is nginx 1.4.0 and luckily it has enabled --with-http-realip_module by default.

Since the CloudFlare documentation includes ipv6 IP addresses, we also need to ensure that our nginx can handle ipv6. This requires --with-ipv6 option when building nginx. Unfortunately, my nginx is not built with ipv6 support. I am forced to rebuild it. Luckily, I’m using Slackbuilds.org’s nginx Slackbuild script. I just edited the script to pass --with-ipv6 and re-installed nginx.

HttpRealipModule

This is the guide I used when setting up the CloudFlare real ip sniff. I’ve created a file called /etc/nginx/cloudflare-real-ip.conf.

# Cloudflare

set_real_ip_from   204.93.240.0/24;
set_real_ip_from   204.93.177.0/24;
set_real_ip_from   199.27.128.0/21;
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   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;
real_ip_header     CF-Connecting-IP;

Next, for all sites in your server that is CloudFlare enabled, include this config by putting a line in your vhost configuration like below:

server {
    # Some config
    # ...
    # ...

    # CloudFlare config
    include /etc/nginx/cloudflare-real-ip.conf;
}

Restart nginx and what your access logs. It should start logging real IP address from now on. Be sure to update the list of IP addresses from time to time since CloudFlare may add/remove IP address in the future.

Note: We didn’t actually configured nginx to allow ipv6, but instead we just make sure that our config syntax will work and not throw error. Without the ipv6 option, our config above will fail since it will not be able to understand the ipv6 syntax. However, we didn’t specifically mentioned how to allow ipv6 connections to nginx. This requires another configuration that I am not interested as of this time.

2 thoughts on “Log real IP address with CloudFlare and nginx”

  1. Thank you for the tutorial. Don’t know if this is new but with the latest nGINX version, you need to add a semicolon after the include statement. Otherwise, nGINX won’t start.

    # CloudFlare config
    include /etc/nginx/cloudflare-real-ip.conf;

  2. That’s correct. I missed the semi-colon when I typed it, for sure nginx would not start and I’ve experienced that a lot.

    I’ve updated the post now.

    Thanks

Leave a reply

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