Nerdsense

Web Security: Blocking Bots from the Edge with Fail2Ban + Cloudflare

Greg Heffner June 25, 2025
Web Security Blog Post Image

When you're running a public-facing web application—especially one routed through a Cloudflare Tunnel—security is paramount. While tunnels hide your server’s IP, bots and malicious actors still hammer away at exposed endpoints. That’s where Fail2Ban helps reinforce your defenses.

What Is Cloudflare?

Cloudflare is a global network platform that sits between your website visitors and your web server. When you use Cloudflare, your website’s DNS is pointed to Cloudflare’s servers. This means all incoming web traffic first passes through Cloudflare’s network before reaching your actual server.

  • Content Delivery: Cloudflare caches static content (like images, CSS, and JavaScript) on its worldwide edge servers. When a user visits your site, Cloudflare serves cached content from the nearest location, making your site load faster.
  • Security: Cloudflare blocks malicious traffic, such as DDoS attacks and bad bots, before it can reach your server. It also hides your server’s real IP address, making it harder for attackers to target you directly.
  • SSL/TLS Encryption: Cloudflare provides free SSL certificates, ensuring that data between your users and your site is encrypted, even if your server doesn’t have its own certificate.
  • Firewall and Rules: You can set up custom firewall rules and rate limiting to control who can access your site and how often.

Cloudflare Tunnel (formerly Argo Tunnel) provides a secure, outbound-only connection from your internal server to Cloudflare’s global network. It acts as a first line of defense by masking your server’s true IP and minimizing the attack surface.

When you combine Cloudflare with tools like Fail2Ban, you get layered protection: Cloudflare filters and blocks threats at the network edge, while Fail2Ban monitors your application for suspicious activity and can trigger Cloudflare to block abusive IPs in real time. This synergy helps keep your web application secure, fast, and reliable.

So... What Is Fail2Ban?

Fail2Ban is an intrusion prevention tool that helps protect your server from brute-force attacks and other malicious activity. It works by continuously monitoring log files generated by services like SSH, web servers, or mail servers.

Fail2Ban uses a set of configurable filters—regular expressions that match specific patterns in log entries, such as repeated failed login attempts, suspicious HTTP requests, or known attack signatures. When a filter detects a pattern that matches its rules, Fail2Ban considers it a trigger event.

Each filter is paired with a jail, which defines what action to take when a trigger event occurs. Common actions include updating firewall rules to block the offending IP address for a set period, sending notifications, or, as in this setup, calling Cloudflare’s Firewall API to block the IP at the network edge.

  • Example: If someone tries to log in with the wrong password multiple times, Fail2Ban will see these failed attempts in the log file, match them with its filter, and then ban the attacker’s IP.
  • Customization: You can create custom filters for any log-based event, allowing you to tailor Fail2Ban’s protection to your specific application or threat model.

By automating the detection and response to suspicious activity, Fail2Ban helps reduce the risk of successful attacks and minimizes manual intervention.

Detecting Tunnel Abuse and Acting Fast

Even with your origin hidden behind a Cloudflare Tunnel, bots can reach exposed routes via your public hostname. I saw repeated scraping attempts and malformed requests hitting my endpoints. Here’s how I automated the blocking process using Fail2Ban and Cloudflare’s API. You can find these examples on Github.

1. The Cloudflare Firewall Script


                                IP="$1"
                                ZONE_ID=$(cat /etc/cloudflare/ZONE_ID)
                                API_TOKEN=$(cat /etc/cloudflare/API_TOKEN)
                                DATE_MMDDYY=$(TZ=America/New_York date +"%m/%d/%y")
                                TIME_HHMMSS=$(TZ=America/New_York date +"%H:%M:%S")
                                
                                ASN=$(whois "$IP" | grep -iE 'origin:|OriginAS:' | grep -Eo 'AS[0-9]+' | head -n1)
                                
                                curl -s -X POST "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/firewall/access_rules/rules" \
                                  -H "Authorization: Bearer $API_TOKEN" \
                                  -H "Content-Type: application/json" \
                                  --data '{
                                    "mode": "block",
                                    "configuration": {
                                      "target": "ip",
                                      "value": "'"$IP"'"
                                    },
                                    "notes": "Blocked by fail2ban on '"$DATE_MMDDYY $TIME_HHMMSS"' (ASN: '"$ASN"')"
                                  }'
                                

2. Custom Fail2Ban Action

[Definition]
                                actionstart =
                                actionstop =
                                actioncheck =
                                actionban = /usr/local/bin/fail2ban-cloudflare-ban.sh <ip>
                                actionunban =
                                

3. Sample jail.local for Tunnel-Exposed Service

[cloudflared-endpoint]
                                enabled = true
                                port    = http,https
                                filter  = cloudflared-abuse
                                logpath = /var/log/nginx/access.log
                                action  = cloudflare-ban[name=cloudflare-ban]
                                maxretry = 10
                                findtime = 86400         # 1 day
                                

This configuration ensures that persistent abuse against your tunneled service results in an IP block—enforced at the Cloudflare edge before malicious requests touch your server.

Here’s how it works in detail: Fail2Ban continuously monitors your service’s log files for suspicious patterns, such as repeated failed logins or malformed requests. When it detects an IP address that matches these patterns, it triggers a jail—a set of rules specifying what to look for and what action to take.

In this setup, the jail is configured to call a custom script whenever a rule is triggered. The script receives the offending IP address as an argument. It then uses the Cloudflare API to add a firewall rule that blocks this IP at the Cloudflare edge. This means any future requests from that IP are stopped by Cloudflare and never reach your server or tunnel.

  • Detection: Fail2Ban uses filters (regular expressions) to scan logs for specific events, like too many failed logins from the same IP.
  • Action: When a filter matches, the jail executes the script, passing the attacker’s IP.
  • Blocking: The script uses Cloudflare’s API to block the IP, preventing further abuse at the network edge.

This automated process helps protect your service by quickly identifying and blocking abusive IPs, reducing the risk of successful attacks and minimizing manual intervention.

Conclusion From CoPilot

Imagine your website is like a treehouse with a secret ladder. You want your friends to visit, but you don’t want sneaky robots or strangers climbing up when you’re not looking. So, you use Cloudflare, like a friendly robot gatekeeper, who checks everyone before they get to your ladder. Then, you also use Fail2Ban, which is like a watchful owl sitting in the tree—if it sees someone doing something suspicious over and over, like shaking the ladder or poking at the door, it hoots and triggers a trap that blocks them from coming back. Together, they help you keep your treehouse safe, fun, and only for the people you trust.

About Me

I served in the U.S. Army, specializing in Network Switching Systems and was attached to a Patriot Missile System Battalion. After my deployment and Honorable discharge, I went to college in Jacksonville, FL for Computer Science. I have two beautiful and very intelligent daughters. I have more than 20 years professional IT experience. This page is made to learn and have fun. If its messed up, let me know. Im still learning :)

Weather Loop

Animated radar loop of Southeast US weather from NOAA