How to Block Attackers on a cPanel Server Behind Cloudflare
By Josh Comstock · Updated June 2026 · ~8 min read
Your cPanel box is behind Cloudflare, the load's spiking from a credential brute-force or a wave of /.env probes, and you reach for fail2ban — the tool everyone reaches for. Then it does nothing. Or it works once, and a week later half your client sites go dark. Behind Cloudflare, blocking abuse isn't "install fail2ban and walk away." Here's what actually goes wrong — and how to block attackers on the right firewall plane without taking your own sites down.
Why fail2ban Misfires Behind Cloudflare
fail2ban watches your logs, extracts the offending IP, and bans it in iptables. That loop breaks the moment Cloudflare sits in front of your server — quietly, which is the dangerous part.
With mod_remoteip (or mod_cloudflare) installed, your Apache logs show the real visitor IP from the CF-Connecting-IP header — good for analytics, fatal for fail2ban's default action. Because the actual TCP socket your firewall sees isn't the visitor; it's a Cloudflare edge server. So fail2ban reads a real attacker IP from the log and adds an iptables drop for it — but no traffic ever arrives at your origin from that IP directly, so the ban does nothing.
But there's a worse failure mode — the one where it "works." If you haven't set up mod_remoteip, every log line shows a Cloudflare edge IP. fail2ban dutifully bans those — and since all your traffic flows through that handful of edge IPs, you've just firewalled Cloudflare and blackholed every site on the box. That's the single most common Cloudflare + fail2ban incident there is. (For the related problem of attackers who skip Cloudflare entirely, see how attackers bypass Cloudflare and hit your origin directly.)
The Key Idea: Two Planes, One Decision
Here's the thing that untangles all of it. Every offender is on one of two planes, and each plane has a different correct response:
- Via Cloudflare (proxied). The request came through the edge. Blocking it at your server firewall is pointless — you must block it at Cloudflare, through the API, so the edge stops it before it reaches you.
- Direct-to-origin. The attacker found your raw IP and connected straight to it, bypassing Cloudflare. Here the socket really is the attacker, so a server-level firewall drop (CSF or iptables) is exactly right.
Get the plane wrong in either direction and you either accomplish nothing or cause an outage. There's no third option. Everything below is about routing each offender to the correct plane.
Step 1 — See the Real IP Without Breaking the Firewall
Install Cloudflare's IP restoration so logs carry the true client address:
# On cPanel/Apache: EasyApache 4 ships mod_remoteip; enable it, then in Apache:
RemoteIPHeader CF-Connecting-IP
# (Cloudflare's edge ranges are the trusted proxies — keep that list current.)
Now your logs are accurate. But — and this is the part people skip right past — that does not make it safe to feed those IPs to iptables. It just means you can finally tell who's who.
Step 2 — Block Proxied Attackers at Cloudflare (Not iptables)
For abuse that arrives through the proxy, the block belongs at the edge. fail2ban ships a cloudflare action for exactly this — point it at a scoped API token and it adds an IP Access Rule via the Cloudflare API instead of touching iptables:
# jail.local
[apache-badbots]
enabled = true
action = cloudflare[cfuser=%(cfemail)s]
logpath = /var/log/apache2/domlogs/*
maxretry = 5
Create the token with only Zone → Firewall Services → Edit — a different product from the WAF Rulesets, so it never collides with your managed rules. The edge can now answer the offender with a managed challenge or block, before the request ever reaches your origin. Two limits to keep in mind, though: it's one API call per IP (so don't let a log-parsing bug fire thousands), and it does nothing for direct-to-origin traffic — which is the next step.
Step 3 — Block Direct-to-Origin Attackers at CSF
For raw-IP scanners and floods that skip Cloudflare, CSF (ConfigServer Security & Firewall) is the right tool — its lfd daemon watches for login failures and can block offenders at iptables, where a direct socket is genuinely stopped. The discipline that keeps CSF safe on a Cloudflare box:
- Never let CSF block a Cloudflare range. Put Cloudflare's published v4/v6 ranges in
csf.allow(or "ignore") so a misread log line can never deny the edge. - Only send genuinely-direct offenders here. A request that came through the proxy must never be routed to a CSF deny — that deny also cuts the customer's mail and cPanel access if they share the IP.
- Require failure evidence for auth paths. Hitting
wp-login.phpisn't a crime; your clients do it daily. Only escalate on repeated failed attempts.
Step 4 — Decide the Plane Automatically
Steps 2 and 3 only work if something decides, per offender, which plane it's on — and that's the hard part to hand-build. Doing it properly means: detecting whether each request came through Cloudflare (the CF-Ray header is present on proxied requests, absent on direct ones), inspecting the live socket to catch a valid-Host flood that bypasses the edge, keeping Cloudflare's range list fresh, failing closed if that list goes stale, and never tripping on a site owner's own logins. That's a real amount of glue, scoring, and safety rail to write — and then maintain, on every server, forever.
The Shortcut: Let a Tool Route the Planes for You
This is exactly what we built Swatter to do — a free, open-source abuse blocker for cPanel + CSF servers. It reads your web logs, scores every IP on weighted behavioral signals plus optional threat-intel, and then classifies each offender direct-vs-proxied — from the logs and the live socket — before blocking it on the correct plane: CSF for direct-to-origin, a Cloudflare managed challenge via the API for proxied. Cloudflare's own ranges are a hardcoded never-block set, re-checked before every block, and it fails closed if that list ever goes stale. It ships report-only, so you watch what it would do for a week before you ever let it act, and the brute-force floor requires failure evidence — so an owner working in wp-admin is never banned. It's plain Bash + awk on a cron. No daemon, no agent, no phone-home.
If you'd rather wire it by hand, the four steps above are the blueprint. If you'd rather not maintain that glue on every box, Swatter is the same logic, packaged and safety-railed.
Related: How attackers bypass Cloudflare and hit your origin directly · CrowdSec vs Swatter vs fail2ban.