#!/usr/bin/env bash # Allow web ports (80/443) ONLY from Cloudflare IP ranges, so the origin # is reachable only THROUGH the WAF. SSH (22) stays open. Idempotent — # also used by a weekly systemd timer to track CF's IP list. set -uo pipefail v4=$(curl -fsSL https://www.cloudflare.com/ips-v4) || true v6=$(curl -fsSL https://www.cloudflare.com/ips-v6) || true if [ -z "${v4:-}" ] || [ -z "${v6:-}" ]; then echo "ABORT: could not fetch Cloudflare IP ranges — no firewall changes made." exit 1 fi # Drop any broad web allows (keep OpenSSH / 22 untouched!) ufw delete allow 80/tcp >/dev/null 2>&1 || true ufw delete allow 443/tcp >/dev/null 2>&1 || true ufw delete allow 443/udp >/dev/null 2>&1 || true # Allow 80/443 only from Cloudflare for ip in $v4 $v6; do ufw allow from "$ip" to any port 80 proto tcp >/dev/null ufw allow from "$ip" to any port 443 proto tcp >/dev/null ufw allow from "$ip" to any port 443 proto udp >/dev/null done ufw reload >/dev/null echo "CF ranges applied: $(echo "$v4 $v6" | wc -w) ranges" echo "SSH(22) still allowed: $(ufw status | grep -c '22/tcp')"