This script automates the process of restricting access to specified ports on Docker containers, allowing connections only from Cloudflare's IP ranges. It directly modifies the iptables (and ip6tables if enabled) DOCKER-USER chain.
When running services behind Cloudflare (e.g., web servers, APIs in Docker containers), you typically want to ensure that direct access to your origin server (your Docker host) is blocked for IPs other than Cloudflare's proxies. This script helps achieve that by dynamically:
- Fetching the latest official Cloudflare IPv4 and IPv6 address ranges.
- Adding
iptables/ip6tablesrules to theDOCKER-USERchain to:- ACCEPT traffic from Cloudflare IPs destined for your specified container ports.
- DROP all other traffic destined for those specific ports.
- Configuration: You define the Docker container ports to protect (
PORTS_TO_PROTECT) in the script. - Prerequisites Check: Verifies if the
DOCKER-USERchain exists (indicating Docker is likely running and managing iptables). Checks for both IPv4 (iptables) and IPv6 (ip6tables). - Cleanup: Removes any rules previously added by this specific script (identified by a unique comment:
CF_SCRIPT_) before applying new ones. This makes the script safe to re-run (idempotent). - IP Fetching: Downloads the current lists of Cloudflare IPv4 and IPv6 ranges from their official URLs.
- Rule Application:
- Iterates through each port specified in
PORTS_TO_PROTECT. - For each port:
- Inserts
ACCEPTrules intoDOCKER-USERfor every Cloudflare IP range targeting that specific port. - Inserts a
DROPrule below theACCEPTrules for any other IP targeting that specific port.
- Inserts
- This logic is applied separately for IPv4 (
iptables) and IPv6 (ip6tables), if the IPv6 chain exists.
- Iterates through each port specified in
Why DOCKER-USER?
Docker uses iptables extensively for network management. The DOCKER-USER chain is specifically provided as a hook for users to add custom rules that are evaluated before Docker's own rules for forwarding traffic to containers. This makes it the ideal place to filter incoming traffic based on source IP before it reaches your containers.
Note on Interface Matching: This script intentionally does not match rules based on the incoming network interface (-i eth0 etc.) within the DOCKER-USER chain. Such matching is often unreliable in this context because the traffic is being FORWARDed, not hitting the INPUT chain directly in the same way. Rules correctly rely only on source IP and destination port.
- Linux Host running Docker.
bashshell.iptablescommand-line tool.ip6tablescommand-line tool (optional, script will skip IPv6 if not found orDOCKER-USERchain is missing).curlfor fetching IP lists.gawk(GNU awk),grep,sort(usually standard).sudoaccess to modify iptables rules.
Edit the apply_cf_rules.sh script and modify the following variable:
PORTS_TO_PROTECT=(80 443 8443): Replace the example ports with the actual TCP ports your Docker containers expose that you want to protect.
- Save the Script: Save the code as
apply_cf_rules.sh. - Make Executable:
chmod +x apply_cf_rules.sh - Run the Script:
sudo ./apply_cf_rules.sh- The script requires
sudobecause it modifies iptables rules. - It will output the steps it's taking (cleanup, fetching, applying rules).
- The script requires
- Verify the Rules: Carefully check the resulting rules:
Ensure that for each protected port, there are
sudo iptables -L DOCKER-USER -v -n --line-numbers # If IPv6 was processed: sudo ip6tables -L DOCKER-USER -v -n --line-numbersACCEPTrules for Cloudflare IPs followed by a finalDROPrule for that port. - Persist the Rules (IMPORTANT!):
iptablesrules are volatile and disappear on reboot by default. To make them permanent, use a persistence tool. On Debian/Ubuntu systems:- Install the tool:
sudo apt-get update && sudo apt-get install iptables-persistent - During installation, it may ask if you want to save current IPv4/IPv6 rules. Choose yes if you've just successfully run the script.
- After running the script and verifying the rules are correct, save them:
sudo netfilter-persistent save
- Rules will now be loaded automatically on boot.
- Install the tool:
Cloudflare IP ranges can change over time. You should run this script periodically to ensure your whitelist stays up-to-date. Use cron to schedule it.
- Edit crontab:
sudo crontab -e - Add a cron job: Add a line like the following to run the script daily at, for example, 3:05 AM and log output:
5 3 * * * /full/path/to/your/apply_cf_rules.sh > /var/log/apply_cf_rules.log 2>&1
- Replace
/full/path/to/your/apply_cf_rules.shwith the actual absolute path to the script. - Ensure the script is executable by root.
- Replace
- "Error: iptables chain 'DOCKER-USER' does not exist": Docker might not be running, or its iptables integration might be disabled or malfunctioning. Ensure Docker is installed and running correctly.
- "Warning: ip6tables chain 'DOCKER-USER' does not exist": Your system might not have IPv6 enabled,
ip6tablesinstalled, or Docker might not have created the IPv6 chain. The script will safely skip IPv6 rules. - "Error: Failed to fetch Cloudflare IPs": Check internet connectivity from the host. Verify the URLs (
CF_IPV4_URL,CF_IPV6_URL) in the script are still valid. - Containers Unreachable: Double-check the
PORTS_TO_PROTECTlist in the script matches the ports your containers actually use. Verify theiptables -L DOCKER-USERoutput carefully.
Modifying firewall rules can impact network connectivity. Understand the rules being applied before running the script in a production environment. Use with caution.