Skip to content

Instantly share code, notes, and snippets.

@Sly777
Last active August 11, 2025 15:39
Show Gist options
  • Select an option

  • Save Sly777/08fa7e454e5643cf78dc75f10a0607eb to your computer and use it in GitHub Desktop.

Select an option

Save Sly777/08fa7e454e5643cf78dc75f10a0607eb to your computer and use it in GitHub Desktop.
Adding UFW rules based on domains (Cloudflare, github and debian)
#!/bin/bash
# UFW Domain Rules Updater - Enhanced Version
# Updates UFW rules for domains with current IPs and timestamps
# =============================================================================
# CONFIGURATION - UPDATE THIS SECTION TO ADD/REMOVE DOMAINS
# =============================================================================
# Domain patterns to match in UFW rule comments (for cleanup)
DOMAIN_PATTERNS=(
"GitHub" # Matches: GitHub HTTPS, GitHub API, GitHub Raw Content, etc.
"Debian" # Matches: Debian Repo, Debian Security, Debian FTP, etc.
"Cloudflare" # Matches: Cloudflare Tunnel, Cloudflare API, etc.
"Pushover" # Matches: Pushover API
"Crowdsec"
)
# Build grep pattern from array (don't modify this)
GREP_PATTERN=$(IFS='|'; echo "(${DOMAIN_PATTERNS[*]})")
# =============================================================================
# SCRIPT VARIABLES
# =============================================================================
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Global variables
VERBOSE=false
FORCE=false
SCRIPT_NAME=$(basename "$0")
LOG_FILE="/var/log/ufw-domain-updater.log"
CURRENT_DATE=$(date '+%Y-%m-%d %H:%M')
REMOVE_SCRIPT="/usr/local/bin/remove-domain-rules.sh"
print_color() {
echo -e "${1}${2}${NC}"
}
# Logging function
log_message() {
echo "[$CURRENT_DATE] $1" | tee -a "$LOG_FILE"
}
# Show help information
show_help() {
echo "UFW Domain Rules Updater"
echo "Updates UFW rules for domains with current IPs and timestamps"
echo ""
echo "Current domain patterns:"
for pattern in "${DOMAIN_PATTERNS[@]}"; do
echo " • $pattern"
done
echo ""
echo "Usage: sudo $SCRIPT_NAME [OPTIONS]"
echo ""
echo "OPTIONS:"
echo " -h, --help Show this help message"
echo " -v, --verbose Show detailed output for all operations"
echo " -f, --force Skip confirmation prompts"
echo " -d, --debug Show what domains/IPs would be added (dry run)"
echo ""
echo "Examples:"
echo " sudo $SCRIPT_NAME # Interactive mode (default)"
echo " sudo $SCRIPT_NAME --verbose # Show all operation details"
echo " sudo $SCRIPT_NAME --force # No confirmation prompts"
echo " sudo $SCRIPT_NAME --force --verbose # Force with detailed output"
echo " sudo $SCRIPT_NAME --debug # Preview what would be added"
echo ""
echo "Notes:"
echo " • Automatically removes old domain rules before adding new ones"
echo " • Creates UFW rules with timestamps in comments"
echo " • Supports both IPv4 and IPv6 addresses"
echo " • Requires root privileges (use sudo)"
echo ""
echo "To modify domains: Edit DOMAIN_PATTERNS array at top of script"
echo "To manually remove domain rules: remove-domain-rules.sh"
}
# Parse command line arguments
parse_arguments() {
while [[ $# -gt 0 ]]; do
case $1 in
-h|--help)
show_help
exit 0
;;
-v|--verbose)
VERBOSE=true
shift
;;
-f|--force)
FORCE=true
shift
;;
-d|--debug)
debug_mode
exit 0
;;
*)
print_color "$RED" "Unknown option: $1"
echo "Use --help for usage information"
exit 1
;;
esac
done
}
# Debug mode - show what would be added
debug_mode() {
print_color "$BLUE" "=== DEBUG MODE - Preview Only ==="
print_color "$YELLOW" "This would resolve and add UFW rules for these domains:"
echo ""
print_color "$BLUE" "GitHub domains:"
echo " • github.com:443 (HTTPS)"
echo " • api.github.com:443 (API)"
echo " • raw.githubusercontent.com:443 (Raw Content)"
echo " • objects.githubusercontent.com:443 (Objects)"
echo " • ghcr.io:443 (Container Registry)"
print_color "$BLUE" "\nDebian domains:"
echo " • deb.debian.org:443/80 (Repository)"
echo " • security.debian.org:443/80 (Security)"
echo " • ftp.debian.org:443/80 (FTP)"
print_color "$BLUE" "\nCloudflare domains:"
echo " • region1-4.v2.argotunnel.com:443/7844 (Tunnel Regions)"
echo " • us-region1-4.v2.argotunnel.com:443/7844 (Tunnel Regions)"
echo " • api.cloudflare.com:443 (API)"
echo " • dash.cloudflare.com:443 (Dashboard)"
echo " • update.argotunnel.com"
echo " • cftunnel.com"
echo " • h2.cftunnel.com"
echo " • quic.cftunnel.com"
echo " • _v2-origintunneld._tcp.argotunnel.com"
echo " • cfd-v4.argotunnel.com:7844 (Edge Servers)"
print_color "$BLUE" "\nPushover domains:"
echo " • api.pushover.net:443"
print_color "$YELLOW" "\nOld domain rules matching patterns: ${DOMAIN_PATTERNS[*]}"
local existing_rules=$(ufw status numbered | grep -E "$GREP_PATTERN" || echo "None found")
if [[ "$existing_rules" != "None found" ]]; then
echo "$existing_rules"
else
print_color "$GREEN" "No existing domain rules found"
fi
print_color "$BLUE" "\nTo actually update these rules, run without --debug"
}
# Check if running as root
check_root() {
if [[ $EUID -ne 0 ]]; then
print_color "$RED" "This script must be run as root"
print_color "$YELLOW" "Usage: sudo $SCRIPT_NAME [OPTIONS]"
print_color "$YELLOW" "Use --help for more information"
exit 1
fi
}
# Check dependencies
check_dependencies() {
local missing_deps=()
if ! command -v dig >/dev/null 2>&1; then
missing_deps+=("dnsutils")
fi
if ! command -v ufw >/dev/null 2>&1; then
missing_deps+=("ufw")
fi
if [[ ${#missing_deps[@]} -gt 0 ]]; then
print_color "$RED" "Missing dependencies: ${missing_deps[*]}"
print_color "$YELLOW" "Install with: apt install ${missing_deps[*]}"
exit 1
fi
if [[ ! -f "$REMOVE_SCRIPT" ]]; then
print_color "$RED" "Required script not found: $REMOVE_SCRIPT"
print_color "$YELLOW" "Please ensure remove-domain-rules.sh is installed"
exit 1
fi
}
# Function to resolve domain and add UFW rules
add_domain_rule() {
local domain=$1
local port=$2
local protocol=${3:-tcp}
local description=$4
local added_count=0
if [[ "$VERBOSE" == true ]]; then
print_color "$BLUE" "Processing domain: $domain"
fi
log_message "Processing domain: $domain"
# Resolve domain to IPs (both A and AAAA records)
local ipv4_ips=$(dig +short $domain A 2>/dev/null | grep -E '^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$' | head -10)
local ipv6_ips=$(dig +short $domain AAAA 2>/dev/null | grep -E '^[0-9a-fA-F:]+$' | head -5)
if [[ -z "$ipv4_ips" && -z "$ipv6_ips" ]]; then
print_color "$RED" "✗ No IPs resolved for $domain"
log_message "WARNING: No IPs resolved for $domain"
return 0
fi
# Add IPv4 rules
if [[ -n "$ipv4_ips" ]]; then
for ip in $ipv4_ips; do
local comment="$description - $domain ($CURRENT_DATE)"
if [[ "$VERBOSE" == true ]]; then
print_color "$YELLOW" " Adding IPv4: $ip:$port"
fi
if ufw allow out to "$ip" port "$port" proto "$protocol" comment "$comment" >/dev/null 2>&1; then
if [[ "$VERBOSE" == true ]]; then
print_color "$GREEN" " ✓ Added successfully"
fi
log_message "Added IPv4 rule: $ip:$port - $comment"
((added_count++))
return 0
else
print_color "$RED" " ✗ Failed to add rule for $ip:$port"
log_message "Failed to add rule for $ip:$port"
fi
done
fi
# Add IPv6 rules
if [[ -n "$ipv6_ips" ]]; then
for ip in $ipv6_ips; do
local comment="$description - $domain IPv6 ($CURRENT_DATE)"
if [[ "$VERBOSE" == true ]]; then
print_color "$YELLOW" " Adding IPv6: $ip:$port"
fi
if ufw allow out to "$ip" port "$port" proto "$protocol" comment "$comment" >/dev/null 2>&1; then
if [[ "$VERBOSE" == true ]]; then
print_color "$GREEN" " ✓ Added successfully"
fi
log_message "Added IPv6 rule: $ip:$port - $comment"
((added_count++))
return 0
else
print_color "$RED" " ✗ Failed to add IPv6 rule for $ip:$port"
log_message "Failed to add IPv6 rule for $ip:$port"
fi
done
fi
if [[ "$VERBOSE" != true && $added_count -gt 0 ]]; then
print_color "$GREEN" "✓ $domain ($added_count rules added)"
fi
return $added_count
}
# Remove old domain rules
cleanup_old_rules() {
print_color "$BLUE" "=== Cleaning up old domain rules ==="
if [[ "$VERBOSE" == true ]]; then
print_color "$YELLOW" "Using removal script: $REMOVE_SCRIPT"
fi
log_message "Calling $REMOVE_SCRIPT --force to remove old rules..."
# Use appropriate flags for the removal script
local remove_flags="--force"
if [[ "$VERBOSE" == true ]]; then
remove_flags="--force --verbose"
fi
if "$REMOVE_SCRIPT" $remove_flags; then
print_color "$GREEN" "✓ Successfully removed old domain rules"
log_message "Successfully removed old domain rules"
else
print_color "$YELLOW" "⚠ Domain removal script reported issues (continuing anyway)"
log_message "Warning: Domain removal script reported issues (continuing anyway)"
fi
# Wait a moment for cleanup to complete
sleep 2
}
# Get confirmation from user
get_confirmation() {
if [[ "$FORCE" == true ]]; then
print_color "$YELLOW" "Force mode: Skipping confirmation prompts"
return 0
fi
print_color "$YELLOW" "\nThis will:"
print_color "$YELLOW" " • Remove all existing domain-based UFW rules"
print_color "$YELLOW" " • Resolve current IPs for configured domains"
print_color "$YELLOW" " • Add new UFW rules with current timestamps"
echo ""
read -p "Continue with domain rules update? (yes/no): " confirm
if [[ "$confirm" != "yes" ]]; then
print_color "$GREEN" "Operation cancelled."
exit 0
fi
return 0
}
# Main update process
perform_update() {
ufw disable
sleep 2
local total_rules=0
print_color "$BLUE" "\n=== Adding GitHub rules ==="
add_domain_rule "github.com" 443 tcp "GitHub HTTPS"
total_rules=$((total_rules + $?))
add_domain_rule "api.github.com" 443 tcp "GitHub API"
total_rules=$((total_rules + $?))
add_domain_rule "raw.githubusercontent.com" 443 tcp "GitHub Raw Content"
total_rules=$((total_rules + $?))
add_domain_rule "objects.githubusercontent.com" 443 tcp "GitHub Objects"
total_rules=$((total_rules + $?))
add_domain_rule "ghcr.io" 443 tcp "GitHub Container Registry"
total_rules=$((total_rules + $?))
print_color "$BLUE" "\n=== Adding Pushover rules ==="
add_domain_rule "api.pushover.net" 443 tcp "Pushover API HTTPS"
total_rules=$((total_rules + $?))
print_color "$BLUE" "\n=== Adding Debian repository rules ==="
add_domain_rule "deb.debian.org" 443 tcp "Debian Repo HTTPS"
total_rules=$((total_rules + $?))
add_domain_rule "deb.debian.org" 80 tcp "Debian Repo HTTP"
total_rules=$((total_rules + $?))
add_domain_rule "security.debian.org" 443 tcp "Debian Security HTTPS"
total_rules=$((total_rules + $?))
add_domain_rule "security.debian.org" 80 tcp "Debian Security HTTP"
total_rules=$((total_rules + $?))
add_domain_rule "ftp.debian.org" 443 tcp "Debian FTP HTTPS"
total_rules=$((total_rules + $?))
add_domain_rule "ftp.debian.org" 80 tcp "Debian FTP HTTP"
total_rules=$((total_rules + $?))
print_color "$BLUE" "\n=== Adding Cloudflare Tunnel rules ==="
add_domain_rule "api.cloudflare.com" 443 tcp "Cloudflare API"
total_rules=$((total_rules + $?))
add_domain_rule "update.argotunnel.com" 443 tcp "Cloudflare Update"
total_rules=$((total_rules + $?))
# Add Cloudflare edge servers (main ones)
add_domain_rule "_v2-origintunneld._tcp.argotunnel.com" 7844 tcp "Cloudflare Tunnel Origin"
total_rules=$((total_rules + $?))
add_domain_rule "cftunnel.com" 7844 tcp "Cloudflare Tunnel TCP"
total_rules=$((total_rules + $?))
add_domain_rule "cftunnel.com" 7844 udp "Cloudflare Tunnel UDP"
total_rules=$((total_rules + $?))
add_domain_rule "h2.cftunnel.com" 7844 tcp "Cloudflare Tunnel H2"
total_rules=$((total_rules + $?))
add_domain_rule "quic.cftunnel.com" 7844 udp "Cloudflare Tunnel QUIC"
total_rules=$((total_rules + $?))
# Cloudflare global tunnel endpoints
for region in region1 region2 region3 region4; do
add_domain_rule "$region.v2.argotunnel.com" 443 tcp "Cloudflare Tunnel $region"
total_rules=$((total_rules + $?))
add_domain_rule "$region.v2.argotunnel.com" 7844 tcp "Cloudflare Tunnel $region"
total_rules=$((total_rules + $?))
add_domain_rule "$region.v2.argotunnel.com" 7844 udp "Cloudflare Tunnel $region UDP"
total_rules=$((total_rules + $?))
add_domain_rule "us-$region.v2.argotunnel.com" 7844 tcp "Cloudflare Tunnel US $region"
total_rules=$((total_rules + $?))
add_domain_rule "us-$region.v2.argotunnel.com" 7844 udp "Cloudflare Tunnel US $region UDP"
total_rules=$((total_rules + $?))
done
print_color "$BLUE" "\n=== Adding Crowdsec Tunnel rules ==="
add_domain_rule "api.crowdsec.net" 443 tcp "Crowdsec Hub API"
total_rules=$((total_rules + $?))
add_domain_rule "cti-api.crowdsec.net" 443 tcp "Crowdsec Community API"
total_rules=$((total_rules + $?))
add_domain_rule "hub.crowdsec.net" 443 tcp "Crowdsec Hub"
total_rules=$((total_rules + $?))
add_domain_rule "hub-data.crowdsec.net" 443 tcp "Crowdsec Hub data"
total_rules=$((total_rules + $?))
add_domain_rule "cdn-hub.crowdsec.net" 443 tcp "Crowdsec Hub CDN"
total_rules=$((total_rules + $?))
add_domain_rule "version.crowdsec.net" 443 tcp "Crowdsec Version API"
total_rules=$((total_rules + $?))
add_domain_rule "crowdsec.net" 443 tcp "Crowdsec Services"
total_rules=$((total_rules + $?))
print_color "$GREEN" "\n=== Update Summary ==="
print_color "$GREEN" "Total UFW rules added: $total_rules"
log_message "Domain rules update completed. Total rules added: $total_rules"
sleep 2
ufw enable
return $total_rules
}
# Show final status
show_final_status() {
local rules_added=$1
if [[ $rules_added -gt 0 ]] && [[ "$VERBOSE" == true ]]; then
print_color "$BLUE" "\n=== Current UFW Status (last 20 rules) ==="
ufw status numbered | tail -20
fi
print_color "$BLUE" "\n=== Operation Complete ==="
print_color "$GREEN" "✓ Domain rules updated successfully!"
print_color "$BLUE" "Last updated: $CURRENT_DATE"
if [[ "$VERBOSE" != true ]]; then
print_color "$YELLOW" "Tip: Use --verbose flag to see detailed operation output"
fi
print_color "$BLUE" "\nUseful commands:"
print_color "$BLUE" " View log: tail -f $LOG_FILE"
print_color "$BLUE" " Remove rules: $REMOVE_SCRIPT"
print_color "$BLUE" " View UFW status: ufw status numbered"
}
# Main function
main() {
# Parse arguments first
parse_arguments "$@"
# Start logging
log_message "=== Starting UFW Domain Rules Updater ==="
# Check permissions and dependencies
check_root
check_dependencies
print_color "$BLUE" "=== UFW Domain Rules Updater ==="
print_color "$YELLOW" "Configured domains: ${DOMAIN_PATTERNS[*]}"
# Get confirmation (unless force mode)
get_confirmation
# Remove old domain rules
cleanup_old_rules
# Perform the update
perform_update
local rules_added=$?
# Show final status
show_final_status $rules_added
log_message "=== UFW Domain Rules Updater finished ==="
}
# Run main function with all arguments
main "$@"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment