Put Cloudflare in front of a cPanel server and Imunify360 starts behaving badly. Brute-force blocks fire against 172.69.x.x, the WAF grey-list fills with Cloudflare edge ranges, and within a day a single proxy IP is banned — which silently locks out every visitor from that Cloudflare PoP. The cause is the obvious one: Apache and Imunify see the Cloudflare edge as the client, because that's literally what the TCP connection looks like.
The fix is two layers. First, restore the real client IP at the web-server layer so logs and ModSecurity see the actual visitor. Second, enable Imunify360's native Cloudflare integration so blocks are pushed upstream to Cloudflare's firewall rather than landing on the wrong IP at your edge.
Prerequisites
- Cloudflare in front of a cPanel server with Imunify360 6.x or later installed. If you haven't installed it yet, see installing Imunify360 on cPanel.
- Apache with EasyApache 4 or LiteSpeed Enterprise as the web server. The exact module differs between the two.
- A Cloudflare API token with
Zone.Firewall Services:Editpermission on the zones you want Imunify to manage. Global API keys also work but are over-permissioned — use a scoped token. - Root SSH access.
Step 1 — Restore real visitor IPs at the web server
Cloudflare passes the real client IP in the CF-Connecting-IP header (and X-Forwarded-For as a fallback). Apache and LiteSpeed both need a module to read that header and treat the value as the connection IP for the rest of the request lifecycle — logs, mod_security, PHP's $_SERVER['REMOTE_ADDR'], everything.
Apache (EasyApache 4)
EasyApache ships mod_remoteip by default. Verify it's loaded:
httpd -M | grep remoteip
You should see remoteip_module (shared). If not, install it:
yum install ea-apache24-mod_remoteip
Drop the configuration into a global include so it survives EasyApache rebuilds:
nano /etc/apache2/conf.d/includes/pre_main_global.conf
Add:
RemoteIPHeader CF-Connecting-IP
RemoteIPTrustedProxyList /etc/apache2/conf.d/cloudflare-ips.txt
Now populate the trusted-proxy list with Cloudflare's current edge ranges:
{ curl -s https://www.cloudflare.com/ips-v4; echo; curl -s https://www.cloudflare.com/ips-v6; } > /etc/apache2/conf.d/cloudflare-ips.txt
Restart Apache:
/scripts/restartsrv_httpd
Cloudflare updates its IP ranges occasionally — schedule a weekly cron to refresh cloudflare-ips.txt and reload Apache. A short script in /etc/cron.weekly/refresh-cloudflare-ips:
#!/bin/bash
TMP=$(mktemp)
{ curl -fsS https://www.cloudflare.com/ips-v4; echo; curl -fsS https://www.cloudflare.com/ips-v6; } > "$TMP" \
&& mv "$TMP" /etc/apache2/conf.d/cloudflare-ips.txt \
&& /scripts/restartsrv_httpd
Make it executable: chmod +x /etc/cron.weekly/refresh-cloudflare-ips.
LiteSpeed Enterprise
LiteSpeed has built-in support — no module install needed. In WebAdmin, go to Configuration → Server → General → Use Client IP in Header and set to Trusted IP Only. Then under Configuration → Server → IP Access Control → Allowed List, add the Cloudflare ranges from https://www.cloudflare.com/ips-v4 and ips-v6 with a trailing T to mark them trusted, e.g. 173.245.48.0/20T.
Graceful restart:
/usr/local/lsws/bin/lswsctrl restart
Verify real IPs are coming through
Tail the access log and load a page from your phone (or any non-server IP):
tail -f /usr/local/apache/domlogs/example.com
The first column should be the real client IP, not 172.x or 108.x. If you still see Cloudflare ranges, the RemoteIPHeader directive didn't take effect — check httpd -t -D DUMP_INCLUDES to confirm the include is being read.
Step 2 — Enable Imunify360's Cloudflare integration
Now that the web server sees real IPs, Imunify will already start blocking the right addresses at your server. But those blocks happen after the request reaches your edge — wasted bandwidth and CPU. The Cloudflare integration pushes the same blocks one hop upstream so attackers get rejected by Cloudflare's WAF before your server ever sees the packet.
Open Imunify360 in WHM → Plugins → Imunify360 → Settings → Cloudflare. Add your account:
- Email: the Cloudflare account email
- API token: the scoped token from the prerequisites (recommended) or the Global API Key
- Zones: leave blank to manage all zones, or specify a comma-separated list
Save. Imunify validates the credentials and lists managed zones.
To do the same from the CLI:
imunify360-agent cloudflare add \
--email admin@example.com \
--api-key 'YOUR_SCOPED_TOKEN'
Once added, every IP that Imunify decides to block (brute force, WAF event, RBL hit) gets a corresponding firewall rule pushed to the matching Cloudflare zone via the API. Rules are tagged imunify360 in the Cloudflare dashboard so they're easy to audit and revoke.
Step 3 — Lock the origin to Cloudflare-only
With visitor IPs restored and blocks pushed upstream, the last step closes the obvious bypass: an attacker who finds the origin IP can hit it directly and skip Cloudflare entirely. Tighten the origin firewall to accept HTTP/HTTPS only from Cloudflare ranges.
The easiest way is via CSF — install it if you don't already have it, and add to /etc/csf/csfpre.sh:
#!/bin/bash
# Allow HTTP/HTTPS only from Cloudflare
for ip in $(curl -s https://www.cloudflare.com/ips-v4) $(curl -s https://www.cloudflare.com/ips-v6); do
iptables -I INPUT -p tcp -m multiport --dports 80,443 -s "$ip" -j ACCEPT
ip6tables -I INPUT -p tcp -m multiport --dports 80,443 -s "$ip" -j ACCEPT 2>/dev/null
done
iptables -A INPUT -p tcp -m multiport --dports 80,443 -j DROP
ip6tables -A INPUT -p tcp -m multiport --dports 80,443 -j DROP 2>/dev/null
Make executable and reload CSF:
chmod +x /etc/csf/csfpre.sh
csf -r
If you're using Imunify360 alongside CSF, read running Imunify360 alongside CSF without double-blocking before locking down — the two need to be coordinated so CSF doesn't pre-empt Imunify's block decisions.
Common failure modes
Apache logs still show Cloudflare IPs in the first column. The RemoteIPHeader directive didn't load. Check httpd -t for syntax errors, confirm the include path matches your distro (/etc/apache2/conf.d/includes/ on EasyApache 4, /etc/httpd/conf.d/ on stock), and verify with httpd -M | grep remoteip.
Imunify blocks customers in entire regions after enabling Cloudflare integration. You enabled the integration before step 1. Imunify pushed Cloudflare edge IPs to Cloudflare's firewall. Disable the integration in Imunify, log into Cloudflare → Security → WAF → Custom rules, delete all rules tagged imunify360, fix the real-IP restoration, then re-enable.
CF-Connecting-IP header is missing. The request didn't come through Cloudflare. Either the DNS record is greyed (DNS-only, no proxy) or someone hit the origin IP directly. Step 3 closes the second case.
Cloudflare rule limit reached. Free and Pro plans cap WAF custom rules at 5 and 20 respectively. Imunify can easily exceed this on a busy server. Either upgrade the Cloudflare plan or set the integration to only push high-severity blocks — imunify360-agent config update '{"CLOUDFLARE": {"min_severity": "high"}}'.
Does Imunify360's Cloudflare integration work with free Cloudflare plans?+
Will mod_remoteip break sites that already have their own IP-handling code?+
Can I use a Cloudflare scoped token instead of the Global API key?+
What happens to existing Imunify blocks when I enable Cloudflare integration?+
Does Cloudflare's Bot Fight Mode conflict with Imunify360?+
How often should I refresh the Cloudflare IP list?+
Next steps
- If brute-force events keep landing on Cloudflare IPs even after real-IP restoration, walk through tuning Imunify360 WAF to cut false positives.
- Coordinate the firewall stack with running Imunify360 alongside CSF without double-blocking.
- Activate or renew an Imunify360 license for the server.