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
curlandjqinstalled on your system
Step 1: Create a Cloudflare API Token
- Log in to your Cloudflare dashboard
- Navigate to “My Profile” → “API Tokens”
- Click “Create Token”
- Select “Create Custom Token”
- Name your token (e.g., “Domain Redirect Manager”)
- Under “Permissions,” add:
- Zone – Page Rules – Edit
- Zone – Zone – Read
- Under “Zone Resources,” select “Include” → “All Zones” (or specific zones if preferred)
- Click “Continue to Summary” and then “Create Token”
- 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:
- Change the target URL in the
create_redirect_rulefunction from “https://compuweather.com” to your desired destination - Modify the status code (301 for permanent redirects, 302 for temporary)
- 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.