Configuring NginX to pass through real IP Addresses from Cloudflare, compatible with fail2ban and WordPress

Nginx is awesome – really fast compared to Apache. Cloudflare is also awesome – a fast and free for most CDN.

If you are running WordPress however, there is a problem you have to deal with – namely WordPress Botnets.

Countering Botnets

Cloudflare itself helps to counter a lot of bot attacks, but really if you’re serious about your site you should have fail2ban installed.

Fail2ban scans your traffic logs and based on rules you set adds IP addresses to your firewall blacklist.

This means you can stop things like XML-RPC attack vetors, login attacks and more. If you are relying on plugins like WordFence (a horror of a plugin!) or Sucuri (far better) then you are allowing bot traffic to consume your server resources. In order for Sucuri or WordFence to block attacks, the attack traffic uses NginX, PHP and MySQL resources before being stopped.

With fail2ban, this traffic is stopped before it even hits Nginx. Given the size of botnets (your site probably gets 1000 attacks per day at least), this can become a serious performance problem.

The Cloudflare Fail2ban problem

So we want to use cloudflare AND fail2ban since they both improve performance, but there’s a problem.

By default, Nginx will think your traffic is coming from the Cloudflare IP addresses. That means, fail2ban also thinks this. That means, when fail2ban bans IP addresses, if you are using Cloudflare it will ban entire groups of your customers from that Cloudflare region.

You can fix this by enabling the realip module in Nginx

Enabling realip with Nginx

To enable the realip module and fix the integration of cloudflare and fail2ban you need to do two things – first, you need to recompile nginx to have the realip module. Second you need to configure Nginx to set the realip from the cloudflare addresses.

Recompile nginx using the following on your server:


wget http://nginx.org/download/nginx-1.x.x.tar.gz
tar xvzf nginx-1.x.x.tar.gz
cd nginx-1.x.x
./configure --with-http_realip_module
make
make install

Configuring Nginx to get the real ip address from Cloudflare

Edit /etc/nginx/nginx.conf and add the following anywhere inside the http { … } area.

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 104.16.0.0/12;
set_real_ip_from 108.162.192.0/18;
set_real_ip_from 131.0.72.0/22;
set_real_ip_from 141.101.64.0/18;
set_real_ip_from 162.158.0.0/15;
set_real_ip_from 172.64.0.0/13;
set_real_ip_from 173.245.48.0/20;
set_real_ip_from 188.114.96.0/20;
set_real_ip_from 190.93.240.0/20;
set_real_ip_from 197.234.240.0/22;
set_real_ip_from 198.41.128.0/17;
set_real_ip_from 199.27.128.0/21;
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 2c0f:f248::/32;
set_real_ip_from 2a06:98c0::/29;
real_ip_header CF-Connecting-IP;

This last line ensures the connecting IP adress is available in the $http_cf_connecting_ip variable in fail2ban.

Save the file and then edit your /etc/nginx/sites-available/* file, e.g. on the rocket stack it might be /etc/nginx/sites-available/varnish-yourdomain.com.conf. Find the main server block and see if the headers are set, if not add them, else alter:

proxy_set_header X-Real-IP $http_cf_connecting_ip;
proxy_set_header X-Forwarded-For $http_x_forwarded_for;

That ensures the IP address from the connecting ip before cloudflare is the one set as the real ip.

Allowing WordPress to see the real IP address

If you are using any plugins that rely on the originator IP address (e.g. security plugins), you can add this to your wordpress config.php file somewhere before wp-settings.php is loaded. This is an option if you don’t have fail2ban so don’t care about that possibly blocking wide swathes of cloudflare traffic instead of the single targeted IP adress.

//restore original visitor IP if from Cloudflare
if ( isset( $_SERVER[‘HTTP_CF_CONNECTING_IP’] ) ){
$_SERVER[‘REMOTE_ADDR’] = $_SERVER[‘HTTP_CF_CONNECTING_IP’];
}

Finishing Cloudflare Configuration

Now you can switch cloudflare on. If you haven’t already, you can install the Cloudflare plugin – https://en-gb.wordpress.org/plugins/cloudflare/

If you’re using W3 Total Cache, you should enable the Cloudflare add on.

Enter your Cloudflare API key into both of these plugins if you have them.

Without the plugins, cloudflare still works – but it lets you do things like bypass cloudflare (go into dev mode) directly from your site. It also lets you clear the cache etc.

Summary

Now you should have Cloudflare working nicely with fail2ban for the ultimate in performance security.

Chat to me

Dave Hilditch

Founder at WP Intense
Dave has been programming since 6 years old and has been developing WordPress plugins, themes and websites since 2010. In the past he built the browse view technology for Skyscanner and now he helps clients with interesting website challenges.

He is always on at least one of his computers when he's awake, so get in touch and he'll get right back to you.
Chat to me

Latest posts by Dave Hilditch (see all)