In today’s digital landscape, managing multiple domains is a common scenario for businesses and developers alike. Whether you’re consolidating websites, rebranding, or redirecting traffic from parked domains, doing this manually through a control panel can be tedious and error-prone, especially when dealing with dozens or hundreds of domains.

This tutorial shares my recent experience automating domain redirects using Cloudflare’s API, which saved hours of point-and-click work and created a reusable solution for future projects.

The Challenge

I needed to redirect multiple domains to a single primary domain (compuweather.com). All these domains were already on Cloudflare, but setting up redirects manually would have been time-consuming and repetitive.

The Solution: Bash Scripts + Cloudflare API

Cloudflare offers a comprehensive API that allows you to programmatically manage all aspects of your domains. We’ll use bash scripts to interact with this API and set up Page Rules to handle the redirects.

Prerequisites

  • Domains managed through Cloudflare
  • Basic familiarity with bash scripting
  • A Cloudflare API token with appropriate permissions
  • curl and jq installed on your system

Step 1: Create a Cloudflare API Token

  1. Log in to your Cloudflare dashboard
  2. Navigate to “My Profile” → “API Tokens”
  3. Click “Create Token”
  4. Select “Create Custom Token”
  5. Name your token (e.g., “Domain Redirect Manager”)
  6. Under “Permissions,” add:
    • Zone – Page Rules – Edit
    • Zone – Zone – Read
  7. Under “Zone Resources,” select “Include” → “All Zones” (or specific zones if preferred)
  8. Click “Continue to Summary” and then “Create Token”
  9. Save your token securely – you’ll need it for the scripts

Step 2: Prepare Your Domain List

Create a text file (e.g., domain_list.txt) containing your domains and their Zone IDs in a comma-separated format:

example.com,54a4e2ebeaf99c27726a1934cadb5d1c
myotherdomain.net,2d2a5aaa142fba3bfb41325e857ee02f
parked-domain.org,b63cca4102fa47c6e32a18c2c4056dd4

You can get Zone IDs from the Cloudflare dashboard or via the API.

Step 3: Create the Redirect Script

Save the following as cloudflare-redirect.sh:

#!/bin/bash
# Replace with your actual API token (never share this token)
API_TOKEN="YOUR_API_TOKEN"
# Function to create a redirect rule using the Page Rules API
create_redirect_rule() {
    local zone_id=$1
    local domain=$2
    
    echo "Creating redirect rule for $domain (Zone ID: $zone_id)..."
    
    result=$(curl -s -X POST "https://api.cloudflare.com/client/v4/zones/$zone_id/pagerules" \
        -H "Authorization: Bearer $API_TOKEN" \
        -H "Content-Type: application/json" \
        --data '{
            "targets": [
                {
                    "target": "url",
                    "constraint": {
                        "operator": "matches",
                        "value": "*'$domain'/*"
                    }
                }
            ],
            "actions": [
                {
                    "id": "forwarding_url",
                    "value": {
                        "url": "https://compuweather.com",
                        "status_code": 301
                    }
                }
            ],
            "priority": 1,
            "status": "active",
            "description": "Redirect to compuweather.com"
        }')
    
    success=$(echo $result | jq -r '.success')
    
    if [[ "$success" == "true" ]]; then
        echo "Successfully created redirect rule for $domain"
    else
        echo "Error creating redirect rule for $domain"
        echo "Error message: $(echo $result | jq -r '.errors[0].message // "Unknown error"')"
    fi
}
# Function to process a list of domains with their zone IDs
process_domain_list() {
    local file_path=$1
    
    echo "Processing domains from $file_path..."
    
    while IFS=, read -r domain zone_id || [[ -n "$domain" ]]; do
        # Skip empty lines and lines starting with #
        if [[ -z "$domain" || "$domain" =~ ^# ]]; then
            continue
        fi
        
        # Remove any whitespace
        domain=$(echo "$domain" | tr -d '[:space:]')
        zone_id=$(echo "$zone_id" | tr -d '[:space:]')
        
        if [[ -z "$zone_id" ]]; then
            echo "Error: No zone ID provided for $domain"
            continue
        fi
        
        create_redirect_rule "$zone_id" "$domain"
        
        # Add a small delay between API calls
        sleep 1
    done < "$file_path"
}
# Check if file is provided as argument
if [ "$1" ]; then
    file_path="$1"
else
    file_path="domain_list.txt"
fi
if [ ! -f "$file_path" ]; then
    echo "Error: File $file_path not found"
    echo "Usage: $0 [domain_list_file]"
    echo "File format should be: domain.com,zone_id (one per line)"
    exit 1
fi
echo "=== Processing domains from $file_path ==="
process_domain_list "$file_path"
echo "Done!"

Step 4: Make the Script Executable and Run It

chmod +x cloudflare-redirect.sh
./cloudflare-redirect.sh domain_list.txt

What If Something Goes Wrong?

If you encounter issues or need to clean up incorrect redirects, here’s a bonus cleanup script that can delete problematic page rules:

#!/bin/bash
# Replace with your actual API token (never share this token)
API_TOKEN="YOUR_API_TOKEN"
# Function to get all page rules for a zone
get_page_rules() {
    local zone_id=$1
    local domain=$2
    
    echo "Getting page rules for $domain (Zone ID: $zone_id)..."
    
    rules=$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones/$zone_id/pagerules" \
        -H "Authorization: Bearer $API_TOKEN" \
        -H "Content-Type: application/json")
    
    success=$(echo $rules | jq -r '.success')
    
    if [[ "$success" == "true" ]]; then
        echo "Successfully retrieved page rules for $domain"
        echo $rules | jq -r '.result[] | "\(.id) \(.targets[0].constraint.value)"'
    else
        echo "Error retrieving page rules for $domain"
        echo "Error message: $(echo $rules | jq -r '.errors[0].message // "Unknown error"')"
        return 1
    fi
}
# Function to delete a page rule
delete_page_rule() {
    local zone_id=$1
    local rule_id=$2
    local domain=$3
    
    echo "Deleting page rule $rule_id for $domain..."
    
    result=$(curl -s -X DELETE "https://api.cloudflare.com/client/v4/zones/$zone_id/pagerules/$rule_id" \
        -H "Authorization: Bearer $API_TOKEN" \
        -H "Content-Type: application/json")
    
    success=$(echo $result | jq -r '.success')
    
    if [[ "$success" == "true" ]]; then
        echo "Successfully deleted page rule $rule_id for $domain"
    else
        echo "Error deleting page rule for $domain"
        echo "Error message: $(echo $result | jq -r '.errors[0].message // "Unknown error"')"
    fi
}
# Function to process a list of domains with their zone IDs
process_domain_list() {
    local file_path=$1
    
    echo "Processing domains from $file_path..."
    
    while IFS=, read -r domain zone_id || [[ -n "$domain" ]]; do
        # Skip empty lines and lines starting with #
        if [[ -z "$domain" || "$domain" =~ ^# ]]; then
            continue
        fi
        
        # Remove any whitespace
        domain=$(echo "$domain" | tr -d '[:space:]')
        zone_id=$(echo "$zone_id" | tr -d '[:space:]')
        
        if [[ -z "$zone_id" ]]; then
            echo "Error: No zone ID provided for $domain"
            continue
        fi
        
        # Get all page rules for this zone
        page_rules=$(get_page_rules "$zone_id" "$domain")
        
        # Check each rule and delete incorrect ones
        echo "$page_rules" | while read -r rule_line; do
            if [ -n "$rule_line" ]; then
                rule_id=$(echo "$rule_line" | awk '{print $1}')
                rule_target=$(echo "$rule_line" | awk '{print $2}')
                
                # Check if the rule target contains a comma (indicating incorrect format)
                # Change this condition to match your specific needs
                if [[ "$rule_target" == *","* ]]; then
                    echo "Found incorrect rule target: $rule_target"
                    delete_page_rule "$zone_id" "$rule_id" "$domain"
                fi
            fi
        done
        
        # Add a small delay between domains
        sleep 1
    done < "$file_path"
}
# Check if file is provided as argument
if [ "$1" ]; then
    file_path="$1"
else
    file_path="domain_list.txt"
fi
if [ ! -f "$file_path" ]; then
    echo "Error: File $file_path not found"
    echo "Usage: $0 [domain_list_file]"
    echo "File format should be: domain.com,zone_id (one per line)"
    exit 1
fi
echo "=== Cleaning up incorrect page rules from $file_path ==="
process_domain_list "$file_path"
echo "Done!"

Save this as cloudflare-cleanup.sh and execute it in the same manner as the redirect script.

Real-World Lesson: Handling Errors

During my implementation, I ran into an issue where the script created malformed redirect rules. The problem? The script was treating each entire line (including the comma and zone ID) as a domain name, resulting in redirect patterns like *example.com,54a4e2ebeaf99c27726a1934cadb5d1c/*.

This highlights the importance of proper input parsing in your scripts. The corrected version splits the input line correctly using IFS=, when reading the domain file.

Customizing the Script

To adapt this script for your needs:

  1. Change the target URL in the create_redirect_rule function from “https://compuweather.com” to your desired destination
  2. Modify the status code (301 for permanent redirects, 302 for temporary)
  3. Adjust the URL pattern matching in the “value” field if needed

Beyond Redirects: Other Automation Possibilities

Once you’ve mastered this basic Cloudflare API interaction, you can expand to automate other tasks:

  • DNS record management
  • Security settings configuration
  • Cache purging
  • Worker deployments
  • Analytics retrieval

Conclusion

Using the Cloudflare API for automation saved me considerable time when implementing multiple domain redirects. The initial investment in creating these scripts continues to pay dividends as I can reuse them for future projects.

This approach demonstrates one of the core principles of efficient web development: automating repetitive tasks whenever possible. Especially when managing infrastructure at scale, API-driven automation becomes not just a convenience but a necessity.

By sharing this practical example, I hope to inspire more developers to explore the capabilities of the APIs offered by their service providers and embrace automation as a key productivity tool.


Note: Remember to secure your API tokens and never share them publicly or commit them to version control systems.

Leave a Reply

Your email address will not be published. Required fields are marked *

Post comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.