Mohamed Youssef bf49ccf53c first commit
2026-04-17 18:56:21 +02:00
2026-04-17 18:56:21 +02:00
2026-04-17 18:56:21 +02:00

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

#!/bin/bash

Proper script initialization with bash interpreter specification.

2. Variable Declarations and Constants

TOKEN=""
AUTO_DELETE_ORPHANS=true
DRY_RUN=false

Use of string constants and boolean flags for configuration.

3. Associative Arrays

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

declare -a domains  # Declare indexed array to hold domain references
domains=( d0 d1 )

Ordered collections for managing multiple domains.

5. Array References (Namerefs)

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

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

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

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

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

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

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

if [ -z "$current_ip" ]; then
    echo "Error: Could not retrieve current IP"
    exit 1
fi

Input validation and controlled script termination.

13. Arithmetic Operations

((records_created++))
((records_updated++))
((records_skipped++))
((records_deleted++))

Counter variables for operation statistics.

14. API Integration with curl

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

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
# 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
S
Description
Controller Cloudflare Proxy Domain Records
Readme 29 KiB
Languages
Shell 100%