Lock Down Your Origin with Cloudflare IPs and firewalld
When your server sits behind Cloudflare, anyone who finds your origin IP can bypass the proxy entirely — WAF rules, rate limits, everything — and hit the server directly. The fix is simple: restrict port 443 so only Cloudflare edge IPs can reach it, leaving everything else (SSH, monitoring, etc.) untouched.
Prerequisites
- A Linux server with
firewalldinstalled and active curlavailable
Step 1 — Create a Cloudflare firewalld Zone
firewalld zones let you apply different trust rules based on the source IP. Create a dedicated zone for Cloudflare traffic:
firewall-cmd --permanent --new-zone=cloudflare
Allow only HTTPS (443) in that zone:
firewall-cmd --permanent --zone=cloudflare --add-service=https
Step 2 — Populate the Zone with Cloudflare IP Ranges
Cloudflare publishes their edge IP ranges at cloudflare.com/ips-v4 and cloudflare.com/ips-v6. Add each range as a source in the cloudflare zone:
for ip in $(curl -sf https://www.cloudflare.com/ips-v4); do
firewall-cmd --permanent --zone=cloudflare --add-source="$ip"
done
for ip in $(curl -sf https://www.cloudflare.com/ips-v6); do
firewall-cmd --permanent --zone=cloudflare --add-source="$ip"
done
Step 3 — Remove HTTPS from the Public Zone
Port 443 must not be reachable from non-Cloudflare IPs. Remove it from the public zone:
firewall-cmd --permanent --zone=public --remove-service=https
Then reload:
firewall-cmd --reload
That's it. SSH, port 80, and any other services in the public zone keep working normally. Only port 443 is now restricted to Cloudflare sources.
Verify:
firewall-cmd --zone=cloudflare --list-all
firewall-cmd --zone=public --list-all
Step 4 — Keeping the IP List Current
Cloudflare's IP ranges are stable and change very rarely. That said, it is worth having a script handy to re-apply the list if you ever rebuild the server or if Cloudflare announces a range update.
Save it as /usr/local/bin/update-cloudflare-ips.sh and run it manually when needed:
#!/usr/bin/env bash
set -euo pipefail
ZONE="cloudflare"
echo "Removing existing Cloudflare sources..."
for src in $(firewall-cmd --zone="$ZONE" --list-sources); do
firewall-cmd --permanent --zone="$ZONE" --remove-source="$src"
done
echo "Fetching current Cloudflare IP ranges..."
for ip in $(curl -sf https://www.cloudflare.com/ips-v4); do
firewall-cmd --permanent --zone="$ZONE" --add-source="$ip"
done
for ip in $(curl -sf https://www.cloudflare.com/ips-v6); do
firewall-cmd --permanent --zone="$ZONE" --add-source="$ip"
done
firewall-cmd --reload
echo "Done."
chmod +x /usr/local/bin/update-cloudflare-ips.sh
Verify
From a machine not routed through Cloudflare, try to reach port 443 on the origin IP directly:
curl -v https://YOUR_ORIGIN_IP/
The connection should be refused. SSH and other services on the server remain reachable as normal.