Stack Guides & Tips

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

Published · Last updated

This guide gives you the exact Nginx config to restore the original visitor IP behind Cloudflare – set_real_ip_from entries for every Cloudflare IP range plus real_ip_header CF-Connecting-IP – so fail2ban bans real attackers instead of Cloudflare’s proxies, and WordPress logs real addresses.

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 are serious about your site you should have fail2ban installed. For the wider picture of hardening a WordPress server, see my complete guide to WordPress security.

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 vectors, 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.

Performance Tip

With fail2ban the attack traffic is dropped at the firewall before it reaches Nginx, PHP or MySQL, so it costs you nothing. Wordfence and Sucuri can only block after the request has already consumed those resources.

The Cloudflare Fail2ban problem

So we want to use Cloudflare AND fail2ban since they both improve performance, but there is 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 Nginx to include the realip module. Second, you need to configure Nginx to set the real IP from the Cloudflare addresses.

Note

Modern Nginx builds already include the realip module. Run nginx -V first and look for –with-http_realip_module in the output; the official nginx.org packages and the Nginx package on Ubuntu 24.04 LTS ship with it, so you can usually skip the recompile below entirely.

If your build genuinely lacks the module, you can recompile Nginx using the following on your server (substitute the current Nginx version for 1.x.x):

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;
Note

Cloudflare publishes its authoritative, current IP ranges at https://www.cloudflare.com/ips/. The list above is a snapshot, so pull the latest ranges from there when you set this up and keep them updated.

This last line ensures the connecting IP address 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 client 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 wp-config.php file somewhere before wp-settings.php is loaded. This is an option if you do not have fail2ban, so you do not care about that possibly blocking wide swathes of Cloudflare traffic instead of the single targeted IP address.

//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. For the full set of Cloudflare settings I recommend for WordPress and WooCommerce, see configuring Cloudflare for WordPress and WooCommerce.

If you are 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 they let you do things like bypass Cloudflare (go into dev mode) directly from your site, and clear the cache.

Summary

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

Further reading

The full Cloudflare settings to pair with this real-IP setup
Harden the whole server beyond fail2ban and Cloudflare

3 comments

  1. Alex

    Hi Dave, and they said its support Nginx with Cloudflare: https://wordpress.org/plugins/cf-littlebizzy/

    because, real IP script in the PHP plugin. thanks

    1. Dave Hilditch

      Thanks - looks like a good plugin. I'll try and get a review of it done as soon as I can.

  2. John Caza

    Thanks for the tutorial. For more information on how to compile nginx I found this online: https://www.vultr.com/docs/how-to-compile-nginx-from-source-on-ubuntu-16-04

    I was having a hard time following the compilation instructions above because it would put nginx in /usr/local/nginx/sbin instead of /usr/sbin.

▲
▼
1/1