3v-Hosting Blog
Setting up Fail2ban protection for a site behind CloudFlare
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.