Skip to content

Instantly share code, notes, and snippets.

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

  • Save Sly777/949cd21d6b33f699e79e237d7fd82d72 to your computer and use it in GitHub Desktop.

Select an option

Save Sly777/949cd21d6b33f699e79e237d7fd82d72 to your computer and use it in GitHub Desktop.
Removing UFW Rules by domain-based check
#!/bin/bash
# UFW Domain Rules Remover - Centralized Domain Configuration
# Removes domain-based UFW rules with configurable patterns
# =============================================================================
# CONFIGURATION - UPDATE THIS SECTION TO ADD/REMOVE DOMAINS
# =============================================================================
# Domain patterns to match in UFW rule comments
# Add or remove patterns here - they will be used throughout the script
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" # Matches: CrowdSec API & Hub
)
# Build grep pattern from array (don't modify this)
GREP_PATTERN=$(IFS='|'; echo "(${DOMAIN_PATTERNS[*]})")
# =============================================================================
# SCRIPT VARIABLES - NO NEED TO MODIFY BELOW THIS LINE
# =============================================================================
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
# Global variables
VERBOSE=false
FORCE=false
SCRIPT_NAME=$(basename "$0")
print_color() {
echo -e "${1}${2}${NC}"
}
# Show help information
show_help() {
echo "UFW Domain Rules Removal Script"
echo "Removes domain-based UFW rules matching configured patterns"
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 Delete without interactive confirmation"
echo " -d, --debug Show rules that would be deleted (dry run)"
echo ""
echo "Examples:"
echo " sudo $SCRIPT_NAME # Interactive mode (default)"
echo " sudo $SCRIPT_NAME --verbose # Show all deletion 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 deleted"
echo ""
echo "Notes:"
echo " • Creates automatic backup before deletion"
echo " • Failed deletions are always shown"
echo " • Successful deletions only shown with --verbose"
echo " • Requires root privileges (use sudo)"
echo ""
echo "To add/remove domains: Edit DOMAIN_PATTERNS array at top of script"
}
# 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 deleted
debug_mode() {
print_color "$BLUE" "=== DEBUG MODE - Preview Only ==="
print_color "$YELLOW" "Looking for rules matching patterns: ${DOMAIN_PATTERNS[*]}"
print_color "$YELLOW" "Grep pattern: $GREP_PATTERN"
echo ""
local domain_rules=$(ufw status numbered | grep -E "$GREP_PATTERN")
if [[ -z "$domain_rules" ]]; then
print_color "$GREEN" "No domain-based rules found."
return
fi
print_color "$YELLOW" "Rules that would be deleted:"
echo "$domain_rules"
local rule_count=$(echo "$domain_rules" | wc -l)
print_color "$BLUE" "\nTotal rules that would be deleted: $rule_count"
print_color "$BLUE" "To actually delete 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
}
# Create backup
create_backup() {
local backup_file="/tmp/ufw-backup-$(date +%Y%m%d-%H%M%S).txt"
if [[ "$VERBOSE" == true ]]; then
print_color "$BLUE" "Creating backup..."
fi
ufw status numbered > "$backup_file"
print_color "$GREEN" "Backup saved: $backup_file"
return 0
}
# Show current rules and find domain rules
show_and_find_rules() {
if [[ "$VERBOSE" == true ]]; then
print_color "$BLUE" "=== Current UFW Rules ==="
ufw status numbered
echo ""
fi
print_color "$BLUE" "=== Searching for Domain Rules ==="
print_color "$YELLOW" "Patterns: ${DOMAIN_PATTERNS[*]}"
echo ""
local domain_rules=$(ufw status numbered | grep -E "$GREP_PATTERN")
if [[ -z "$domain_rules" ]]; then
print_color "$GREEN" "No domain-based rules found."
return 1
fi
print_color "$BLUE" "=== Domain Rules Found ==="
echo "$domain_rules"
return 0
}
# Interactive confirmation
get_confirmation() {
if [[ "$FORCE" == true ]]; then
print_color "$YELLOW" "Force mode: Skipping confirmation"
return 0
fi
print_color "$RED" "\n⚠️ WARNING: This will delete the domain rules shown above!"
read -p "Continue? (yes/no): " confirm
if [[ "$confirm" != "yes" ]]; then
print_color "$GREEN" "Operation cancelled."
exit 0
fi
read -p "Type 'DELETE' to confirm: " final_confirm
if [[ "$final_confirm" != "DELETE" ]]; then
print_color "$GREEN" "Operation cancelled."
exit 0
fi
return 0
}
# Perform the deletion
perform_deletion() {
print_color "$BLUE" "\n=== Starting Deletion ==="
# Get the current UFW status and store it (to avoid multiple calls)
local ufw_status=$(ufw status numbered)
# Get rule numbers for domain rules (in reverse order)
local rule_numbers=$(echo "$ufw_status" | grep -E "$GREP_PATTERN" | awk '{print $1}' | tr -d '[]' | sort -nr)
if [[ -z "$rule_numbers" ]]; then
print_color "$GREEN" "No rules to delete."
return 0
fi
local deleted_count=0
local failed_count=0
for rule_num in $rule_numbers; do
if [[ "$rule_num" =~ ^[0-9]+$ ]]; then
# Get rule text for logging
local rule_text=$(ufw status numbered | grep "^$$rule_num$" || echo "Rule $rule_num")
# Always show what we're about to delete in verbose mode
if [[ "$VERBOSE" == true ]]; then
print_color "$YELLOW" "Deleting rule #$rule_num..."
print_color "$BLUE" " $rule_text"
fi
# Delete the rule
if ufw --force delete "$rule_num" >/dev/null 2>&1; then
if [[ "$VERBOSE" == true ]]; then
print_color "$GREEN" " ✓ Deleted successfully"
fi
((deleted_count++))
else
# Always show failures, regardless of verbose mode
print_color "$RED" "✗ Failed to delete rule #$rule_num"
print_color "$RED" " $rule_text"
((failed_count++))
fi
# Brief pause to let UFW update
sleep 0.2
fi
done
# Summary
print_color "$GREEN" "\n=== Deletion Complete ==="
print_color "$GREEN" "Successfully deleted: $deleted_count rules"
if [[ $failed_count -gt 0 ]]; then
print_color "$RED" "Failed to delete: $failed_count rules"
fi
# Show updated rules if we deleted anything
if [[ $deleted_count -gt 0 ]] && [[ "$VERBOSE" == true ]]; then
print_color "$BLUE" "\n=== Updated UFW Rules ==="
ufw status numbered
fi
return 0
}
# Main function
main() {
# Parse arguments first
parse_arguments "$@"
# Check permissions
check_root
# Create backup
create_backup
# Show rules and check if any domain rules exist
if ! show_and_find_rules; then
exit 0
fi
# Get confirmation (unless force mode)
get_confirmation
# Perform deletion
perform_deletion
print_color "$BLUE" "\nBackup location: /tmp/ufw-backup-*.txt"
if [[ "$VERBOSE" != true ]]; then
print_color "$YELLOW" "Tip: Use --verbose flag to see detailed deletion output"
fi
print_color "$YELLOW" "To modify domain patterns, edit DOMAIN_PATTERNS array in script"
}
# 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