# Cloudflare DNS Updater A Bash script that automatically updates Cloudflare DNS A records with your current public IP address. This script demonstrates various advanced Bash programming features while providing a practical tool for dynamic DNS management. ## Features - **Automatic IP Detection**: Retrieves current public IP using external services - **Multi-Domain Support**: Manages DNS records for multiple domains simultaneously - **Smart Updates**: Only updates records when IP changes to avoid unnecessary API calls - **Orphaned Record Cleanup**: Automatically removes unmanaged DNS records - **Protected Records**: Prevents deletion of critical DNS records - **Dry Run Mode**: Test changes without actually modifying DNS records - **Comprehensive Logging**: Detailed output showing all operations performed ## Bash Features Demonstrated This script showcases the following Bash programming features: ### 1. **Shebang and Script Structure** ```bash #!/bin/bash ``` Proper script initialization with bash interpreter specification. ### 2. **Variable Declarations and Constants** ```bash TOKEN="" AUTO_DELETE_ORPHANS=true DRY_RUN=false ``` Use of string constants and boolean flags for configuration. ### 3. **Associative Arrays** ```bash declare -A d0 d1 # Declare associative arrays for domain configuration d0=( ["domain"]="" ["zone_id"]="" ["subdomains"]="@," ["protected_records"]="" ) ``` Key-value data structures for complex domain configurations. ### 4. **Indexed Arrays** ```bash declare -a domains # Declare indexed array to hold domain references domains=( d0 d1 ) ``` Ordered collections for managing multiple domains. ### 5. **Array References (Namerefs)** ```bash declare -n domain="$item" # Create reference to associative array echo "${domain[domain]}" # Access array elements through reference ``` Dynamic array referencing for flexible data access. ### 6. **Functions** ```bash get_current_ip() { curl -s https://ifconfig.me/ip } create_dns_record() { local zone_id="$1" local data="$2" # Function implementation } ``` Modular code organization with local variables and parameters. ### 7. **Advanced Conditional Statements** ```bash if [[ "$DRY_RUN" == true ]]; then echo "⚠️ DRY RUN MODE ENABLED" fi if [[ -n "${existing_a_records[$full_name]}" ]]; then # Record exists logic fi ``` String comparison, variable existence checks, and complex conditions. ### 8. **Loop Constructs** ```bash for item in "${domains[@]}"; do # Process each domain done for subdomain in "${managed_subdomains[@]}"; do # Process each subdomain done ``` Iteration over arrays with proper quoting. ### 9. **String Manipulation and Parsing** ```bash IFS=',' read -ra protected_records <<< "${domain[protected_records]}" IFS=',' read -ra managed_subdomains <<< "${domain[subdomains]}" ``` Field splitting and array population from comma-separated strings. ### 10. **Command and Process Substitution** ```bash current_ip=$(get_current_ip) # Command substitution done < <(echo "$response" | jq -c '.result[] | select(.type == "A")') # Process substitution ``` Capturing command output and feeding output to loops. ### 11. **JSON Processing with jq** ```bash if echo "$response" | jq -e '.success == false' > /dev/null 2>&1; then echo "Error: Failed to get DNS records" fi create_data=$(jq -n \ --arg name "$full_name" \ --arg ip "$current_ip" \ '{ "type": "A", "name": $name, "content": $ip, "ttl": 1, "proxied": true }') ``` Parsing JSON responses and constructing JSON payloads. ### 12. **Error Handling and Exit Codes** ```bash if [ -z "$current_ip" ]; then echo "Error: Could not retrieve current IP" exit 1 fi ``` Input validation and controlled script termination. ### 13. **Arithmetic Operations** ```bash ((records_created++)) ((records_updated++)) ((records_skipped++)) ((records_deleted++)) ``` Counter variables for operation statistics. ### 14. **API Integration with curl** ```bash curl -s "https://api.cloudflare.com/client/v4/zones/$zone_id/dns_records" \ -X POST \ -H 'Content-Type: application/json' \ -H "Authorization: Bearer $TOKEN" \ -d "$data" ``` REST API calls with proper headers and data payloads. ### 15. **Dynamic Variable Management** ```bash unset existing_a_records # Clean up associative arrays unset domain # Clean up nameref ``` Memory management and variable cleanup. ## Usage 1. **Configure Domains**: Edit the domain arrays at the top of the script 2. **Set API Token**: Update the `TOKEN` variable with your Cloudflare API token 3. **Dry Run First**: Test with `DRY_RUN=true` to see what would change 4. **Run Updates**: Set `DRY_RUN=false` to apply actual changes ```bash # Dry run (safe testing) ./update_domain.sh # Apply changes # Edit script: DRY_RUN=false ./update_domain.sh ``` ## Configuration ### Domain Configuration Structure Each domain is configured as an associative array with: - `domain`: The root domain name - `zone_id`: Cloudflare zone identifier - `subdomains`: Comma-separated list of subdomains to manage - `protected_records`: Records that should never be deleted ### Script Parameters - `TOKEN`: Cloudflare API bearer token - `AUTO_DELETE_ORPHANS`: Whether to remove unmanaged records - `DRY_RUN`: Test mode without making actual changes ## Requirements - Bash 4.0+ - curl - jq - Valid Cloudflare API token with DNS edit permissions ## Security Notes - Store API tokens securely (consider environment variables) - Use dry run mode when testing - Review protected records configuration carefully - Monitor script output for any API errors ## Output Example ``` ⚠️ DRY RUN MODE ENABLED - No actual changes will be made ========================================= Current Public IP: 203.0.113.1 ========================================= Processing domain: my-dev.pro Zone ID: 5c9a19af6aeababb78b294844290a7d2 Managed subdomains: @ git ---------------------------------------- Existing A records: - my-dev.pro → 203.0.113.1 (ID: abc123) - git.my-dev.pro → 203.0.113.1 (ID: def456) ---------------------------------------- Checking: my-dev.pro ✓ SKIPPED: IP unchanged (203.0.113.1 = 203.0.113.1) Checking: git.my-dev.pro ✓ SKIPPED: IP unchanged (203.0.113.1 = 203.0.113.1) ========================================= SUMMARY for my-dev.pro: ✓ Created: 0 ✓ Updated: 0 ✓ Skipped (IP unchanged): 2 ✓ Deleted: 0 ========================================= ⚠️ DRY RUN COMPLETED - No actual changes were made Set DRY_RUN=false to apply changes ```