Skip to content

Instantly share code, notes, and snippets.

@akama-aka
Last active March 22, 2025 22:47
Firewalld nftables CloudFlare IP Whitelisting
#!/usr/bin/env sh
## Check if script is running as Administrator
if [[ $EUID -ne 0 ]]; then
echo "This script needs to be run as Administrator!"
exit 1
fi
# Get CloudFlare IPs from CloudFlare API
## Save the response from the CloudFlare IP into a Variable called "response"
response=$(curl --request GET --url https://api.cloudflare.com/client/v4/ips)
## Get the response Variable and echo it into the ipv4 Variable but just that from the result > ipv4_cidrs[] array
ipv4=$(echo $response | jq -r '.result.ipv4_cidrs[]')
## Get the response Variable and echo it into the ipv6 Variable but just that from the result > ipv6_cidrs[] array
ipv6=$(echo $response | jq -r '.result.ipv6_cidrs[]')
## Set the default Firewall Zone to DMZ
firewall-cmd --permanent --set-default-zone=dmz
## Create a new ipset called "Cloudflarev4".
firewall-cmd --permanent --new-ipset=Cloudflarev4 --type=hash:net
## Loop trough all CloudFlare IPs
echo "$ipv4" | while read ip; do
## And add it into the Cloudflarev4 ipset.
firewall-cmd --permanent --ipset=Cloudflarev4 --add-entry="$ip"
done
## Create a new ipset called "Cloudflarev6" !!! KEEP IN MIND THIS IS JUST FOR IPv6 IPs !!!
firewall-cmd --permanent --new-ipset=Cloudflarev6 --type=hash:net --option=family=inet6
## Create a new ipset called "webAdd" in case someone wants to add more IP Addresses
firewall-cmd --permanent --new-ipset=webAddV4 --type=hash:net
firewall-cmd --permanent --new-ipset=webAddV6 --type=hash:net --option=family=inet6
## Loop trough all CloudFlare IPs
echo "$ipv6" | while read ip; do
## And add it into the Cloudflarev6 ipset.
firewall-cmd --permanent --ipset=Cloudflarev6 --add-entry="$ip"
done
## Add the CloudFlare ipsets to the DMZ Zone
firewall-cmd --permanent --zone=dmz --add-source=ipset:Cloudflarev4
firewall-cmd --permanent --zone=dmz --add-source=ipset:Cloudflarev6
firewall-cmd --permanent --zone=dmz --add-source=ipset:webAddV4
firewall-cmd --permanent --zone=dmz --add-source=ipset:webAddV6
## Drop all http and https requests in the dmz zone and also log it. Also with the lowest priority
firewall-cmd --permanent --zone=dmz --add-rich-rule='rule family="ipv4" priority=32767 source address="0.0.0.0/0" service name="http" log prefix="HTTP-/080-DROP: " drop'
firewall-cmd --permanent --zone=dmz --add-rich-rule='rule family="ipv4" priority=32767 source address="0.0.0.0/0" service name="https" log prefix="HTTPS/443-DROP: " drop'
firewall-cmd --permanent --zone=dmz --add-rich-rule='rule family="ipv6" priority=32767 source address="::/0" service name="https" log prefix="HTTPS/443-DROP: " drop'
firewall-cmd --permanent --zone=dmz --add-rich-rule='rule family="ipv6" priority=32767 source address="::/0" service name="http" log prefix="HTTP-/080-DROP: " drop'
## Accept all http and https requests in the dmz zone for all whitelisted CloudFlare IP Addresses with the highest Priority
firewall-cmd --permanent --zone=dmz --add-rich-rule='rule family="ipv4" priority=1 source ipset="Cloudflarev4" service name="https" accept'
firewall-cmd --permanent --zone=dmz --add-rich-rule='rule family="ipv6" priority=1 source ipset="Cloudflarev6" service name="https" accept'
firewall-cmd --permanent --zone=dmz --add-rich-rule='rule family="ipv4" priority=1 source ipset="Cloudflarev4" service name="http" accept'
firewall-cmd --permanent --zone=dmz --add-rich-rule='rule family="ipv6" priority=1 source ipset="Cloudflarev6" service name="http" accept'
## Additional Space
## Everything is broken below this comment
## WhiteList more IPs
ipv4_regex="^([0-9]{1,3}\.){3}[0-9]{1,3}$"
ipv6_regex="^([0-9a-fA-F]{0,4}:){1,7}[0-9a-fA-F]{0,4}$"
while true; do
echo "Do you want to add additional IPs? (j/n)"
read yn
case $yn in
[Yy]* )
echo "Enter the IP you want to add:"
read ip
if [[ $ip =~ $ipv4_regex ]]; then
echo "IPv4 Address added: $ip"
# Hier können Sie die Variable für IPv4-Adressen setzen oder aktualisieren.
ipv4="$ip"
firewall-cmd --permanent --ipset=webAddV4 --add-entry="$ip"
elif [[ $ip =~ $ipv6_regex ]]; then
echo "IPv6 address added: $ip"
# Hier können Sie die Variable für IPv6-Adressen setzen oder aktualisieren.
ipv6="$ip"
firewall-cmd --permanent --ipset=webAddV6 --add-entry="$ip"
else
echo "Thats not a Valid IPv4- or IPv6-Adress."
fi;;
[Nn]* ) break;;
* ) echo "Answere with y (yes) or n (no).";;
esac
done
## WhiteList more Ports
port_regex="^([1-9][0-9]{0,3}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5])$"
while true; do
echo "Do you want to whitelist extra ports? (y/n)"
read yn
case $yn in
[Yy]* )
echo "Enter port you want to whitelist:"
read input
if [[ $input =~ $port_regex ]]; then
echo "Port added: $input"
port="$input"
## Deny it
firewall-cmd --permanent --zone=dmz --add-rich-rule='rule family="ipv4" priority=32767 source address="0.0.0.0/0" service port port="$port" protocol="tcp" log prefix="Add/$port-DROP: " drop'
firewall-cmd --permanent --zone=dmz --add-rich-rule='rule family="ipv6" priority=32767 source address="::/0" port port="$port" protocol="tcp" log prefix="Add/$port-DROP: " drop'
## Allow it
firewall-cmd --permanent --zone=dmz --add-rich-rule='rule family="ipv4" priority=1 source ipset="Cloudflarev4" port port="$port" protocol="tcp" accept'
firewall-cmd --permanent --zone=dmz --add-rich-rule='rule family="ipv6" priority=1 source ipset="Cloudflarev6" port port="$port" protocol="tcp" accept'
else
echo "Invalid Port."
fi;;
[Nn]* ) break;;
* ) echo "Answere with y (yes) or n (no).";;
esac
done
## Restart Firewalld to apply changes
firewall-cmd --reload
####
# Attribution-NonCommercial-NoDerivatives 4.0 International by Akama Aka and Akami Solutions
####
##
# Thanks to DarkDeviL for his help on the CloudFlare Discord
##
###
# WARNING THIS FIREWALLD SETUP IS NOT TO 100% TESTED! ALSO USE NFTABLES TO PREVENT ISSUES!
# NOTE: MAKE SURE YOU HAVE jq INSTALLED ON YOUR SYSTEM
###
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment