3v-Hosting Blog

Setting up Fail2ban protection for a site behind CloudFlare

Administration

8 min read


Many site owners breathe a sigh of relief once they enable Cloudflare. Features like traffic filtering, DDoS mitigation, and caching at the edge make infrastructure more resilient. However, there's a catch: CloudFlare hides the real IP addresses of attackers. When your server only sees CloudFlare’s IP addresses, tools like Fail2ban can't block specific clients.

Imagine your WordPress site is receiving brute-force attacks on the /wp-login.php page. Cloudflare proxies the requests, but your server sees only a handful of Cloudflare nodes making dozens of requests. Fail2ban bans them and accidentally blocks legitimate traffic as well. It's like banning an entire metro station because one pickpocket got in. Not the smartest strategy.

The question then becomes: How can you make Fail2ban useful again when the site is behind CloudFlare?

 

 

 

 

How Fail2ban Works Without CloudFlare

 

Fail2ban is a watchdog that examines your server’s logs. It looks for suspicious patterns, such as failed SSH logins, an excessive number of requests to /xmlrpc.php, and repeated errors in Nginx access logs. If the number of "offenses" exceeds a certain limit, Fail2ban adds the offending IP address to the firewall rules.

For instance, if someone makes 20 failed SSH login attempts within one minute, Fail2ban will insert an iptables rule to block connections from that IP address. This is akin to having a doorman who notices a drunk troublemaker and politely escorts them outside.

However, if you use CloudFlare, the doorman can no longer see the real face — only a mask in the form of CloudFlare’s IP address.

 

 

 

 

The Problem With CloudFlare IPs

 

Every request to your server comes from CloudFlare’s infrastructure. Instead of seeing the attacker’s machine (203.0.113.45), you see CloudFlare’s data center (172.71.150.2) in the logs.

If Fail2ban blocks this address, it blocks CloudFlare itself, cutting off thousands of innocent users along with the attacker. This is the equivalent of shutting down an entire airport terminal because one passenger misbehaved.

The solution is to configure your web server and Fail2ban to identify the real client IP address. This is where HTTP headers and a bit of configuration magic come into play.

 

 

 

 

Restoring the Real IP: Nginx and Apache Setup

 

CloudFlare adds either an X-Forwarded-For or a CF-Connecting-IP header to each request. This header contains the client's actual address. You can restore visibility by configuring your web server to trust this header.

Example with Nginx

In Nginx you need the real_ip module:

    set_real_ip_from 103.21.244.0/22;
    set_real_ip_from 103.22.200.0/22;
    # … add all CloudFlare subnets
    real_ip_header CF-Connecting-IP;


Now logs will show the real visitor’s IP. For accuracy, always use the full list of CloudFlare subnets, available on their documentation page.

 

Example with Apache

In Apache, you can use mod_remoteip:

    RemoteIPHeader CF-Connecting-IP
    RemoteIPTrustedProxy 103.21.244.0/22


After that, both Apache access logs and Fail2ban filters will see attackers as they are, not hidden behind CloudFlare.

 


 

Other useful articles in our Blog:


    - For What Tasks VPS Server Is Suitable

    - How To Install and Use Docker on Ubuntu 22.04

    - How to find out the size of files or folders in Linux

    - Choosing a Web Host for Low Budget Startups

 


 

 

Configuring Fail2ban Filters

 

Once the logs are clean, Fail2ban comes back into play.

Let’s say you want to protect WordPress login:

    [wordpress-login]
    enabled  = true
    port     = http,https
    filter   = wordpress-login
    logpath  = /var/log/nginx/access.log
    maxretry = 5
    findtime = 600
    bantime  = 3600


Here, the filter checks for repeated failed login attempts. With real IPs restored, banning works properly. Attackers get locked out, while CloudFlare keeps serving legitimate visitors.

 

 

 

 

Interaction With CloudFlare Firewall

 

One might ask, why bother with Fail2ban if CloudFlare already provides a firewall?

The answer lies in the layers. CloudFlare protects against large-scale attacks, but it doesn't know the specifics of your application. Fail2ban, on the other hand, can analyze custom logs. For example, it can detect failed admin logins in Joomla or repeated 404 scans for /wp-config.php.

It's like combining city police with a neighborhood watch. CloudFlare handles riots, while Fail2ban takes care of the suspicious person rattling your doorknob.

 

 

 

 

Practical Example: Protecting a Kubernetes Ingress

 

Now, let's consider a DevOps scenario. You have a Kubernetes cluster with an Nginx Ingress behind a CloudFlare firewall. Bots are trying to brute-force your CMS login. Enabling real_ip in the Nginx Ingress configuration and mounting logs to a monitoring pod allows you to deploy Fail2ban as a sidecar container. Fail2ban scans the logs and bans the attacker’s IP address at the node firewall level.

This hybrid approach ensures that you aren't relying only on Cloudflare's rules, but are also adding cluster-level self-defense.

 

 

 

 

SEO and Digital Business Perspective

 

From a business standpoint, failing to protect your site from brute force attacks is about more than just CPU load. Constant attempts generate errors, inflate logs, and can slow down caching layers. Server response times matter for SEO — Googlebot won’t wait forever.

For example, one e-commerce store owner noticed that bots were hitting /wp-login.php hundreds of times per minute. Pages began to load slowly, and customers abandoned their carts. After tuning Fail2ban with Cloudflare headers, the server load normalized, and the conversion rates recovered.

In this case, security directly translates into sales.

 

 

 

 

Best Practices Checklist

 

    - Always configure your web server to restore the real client IP from CloudFlare headers.
    - Keep the list of CloudFlare IP ranges updated — automation with cron and curl helps.
    - Test Fail2ban filters carefully, to avoid banning legitimate users.
    - Combine Fail2ban with CloudFlare rules: for example, block access to /xmlrpc.php entirely at CloudFlare level, and use Fail2ban for login brute force.
    - Monitor logs after deployment — sometimes a misconfigured regex can cause chaos.

 

 

 

 

Conclusion

Fail2ban remains relevant even when your site is moved behind CloudFlare. You just need to ensure that it identifies the real culprits instead of CloudFlare’s proxies. Think of it as cleaning a foggy window; once you wipe it clean, you can see who's standing outside your door.

The combination of CloudFlare’s global shield and Fail2ban’s local defense creates a balanced security system. It’s scalable, customizable, and efficient. For IT specialists and entrepreneurs running serious digital projects, this setup provides peace of mind — your infrastructure will remain fast and your SEO will remain intact while attackers will only find a locked gate.