Backup and Bulk Deletion of Route 53 Records
Route 53 requires all DNS records to be deleted before a hosted zone can be removed. For large zones with thousands of records, manual deletion is impractical due to API constraints. This article provides automated AWS CLI bash scripts that handle pagination, batching, and rate limiting to efficiently bulk-delete all records from any hosted zone, regardless of size.
Introduction
Amazon Route 53 is a highly scalable Domain Name System (DNS) web service that enables organizations to route end users to internet applications. While Route 53 excels at managing DNS records at scale, situations arise where you need to decommission hosted zones containing thousands of records.
Route 53 requires all records (except the mandatory NS and SOA records) to be deleted before a hosted zone can be removed. For hosted zones with tens of thousands of records, manual deletion through the AWS Console is impractical. This article provides automated solutions using the AWS CLI to efficiently delete all records from a large hosted zone.
The Challenge
Deleting a hosted zone with a large number of DNS records presents several technical constraints:
- Route 53 API limits a single ChangeResourceRecordSets request to up to 1,000 changes per batch (a practical limit for reliable batch processing)
- The ListResourceRecordSets API returns a maximum of 300 resource record sets per page
- NS (Name Server) and SOA (Start of Authority) records cannot be deleted as they are mandatory for the hosted zone
- For hosted zones with more than 1,000 records, multiple batched API calls are required
Prerequisites
- AWS CLI installed and configured with appropriate permissions
jqcommand-line JSON processor installed- IAM permissions for
route53:ListHostedZones,route53:ListResourceRecordSets, androute53:ChangeResourceRecordSets
Step 1: Back Up Your Records
Before deleting any records, take a backup of the hosted zone. This is critical in case you need to restore records later.
For hosted zones with fewer than 300 records, a single CLI command works:
aws route53 list-resource-record-sets --hosted-zone-id <your-zone-id> > backup.json
For hosted zones with more than 300 records, the API paginates the results. Use the --paginate option with the AWS CLI to automatically handle pagination and retrieve all records:
aws route53 list-resource-record-sets --hosted-zone-id <your-zone-id> --output json --no-paginate > backup.json
Alternatively, you can use the built-in AWS CLI paginator:
aws route53 list-resource-record-sets --hosted-zone-id <your-zone-id> \ --query "ResourceRecordSets" --output json > backup.json
Verify the backup contains all records:
cat backup.json | jq 'length'
Replace <your-zone-id> with your actual hosted zone ID (e.g., Z1234567890ABC).
Step 2: Choose Your Deletion Approach
Option A: Single-Command Approach (For Zones with Fewer Than 300 Records)
For small hosted zones where all records fit in a single ListResourceRecordSets response (fewer than 300 records), you can delete all records with a single command:
ZONE_ID="<your-zone-id>" aws route53 change-resource-record-sets --hosted-zone-id "$ZONE_ID" \ --change-batch "$(aws route53 list-resource-record-sets --hosted-zone-id "$ZONE_ID" | \ jq -c '{Changes: [.ResourceRecordSets[] | select(.Type != "SOA" and .Type != "NS") | {Action: "DELETE", ResourceRecordSet: .}]}')"
How it works:
- Lists all resource record sets in the hosted zone
- Filters out NS and SOA records using
jq - Creates a DELETE action for each remaining record
- Submits all deletions in a single batch
Note: This approach does not handle pagination. If your hosted zone has more than 300 records, use Option B below.
Option B: Batched Deletion Script (For Large Hosted Zones)
For hosted zones with more than 300 records, use the following script that handles pagination and batching automatically(make sure to add "." after your domain name):
#!/bin/bash # Configuration - replace with your domain name DOMAIN="example.com." # Get the hosted zone ID ZONE_ID=$(aws route53 list-hosted-zones \ --query "HostedZones[?Name==\`${DOMAIN}\`].Id" \ --output text | sed 's/\/hostedzone\///') if [ -z "$ZONE_ID" ]; then echo "Error: Hosted zone not found for domain ${DOMAIN}" exit 1 fi echo "Found hosted zone ID: $ZONE_ID" echo "" echo " WARNING: This will delete all records except NS and SOA records." echo "" echo " RECOMMENDATION: Take a backup first using:" echo " aws route53 list-resource-record-sets --hosted-zone-id \"$ZONE_ID\" --output json > backup.json" echo "" read -p "Have you taken a backup? Do you want to proceed? (yes/no): " confirmation if [ "$confirmation" != "yes" ]; then echo "Deletion cancelled." exit 0 fi echo "" echo "Starting deletion process..." batch_count=0 while true; do # Fetch records and create delete changes (excluding NS and SOA) changes=$(aws route53 list-resource-record-sets \ --hosted-zone-id "$ZONE_ID" --max-items 1000 | \ jq -c '{Changes: [.ResourceRecordSets[] | select(.Type != "SOA" and .Type != "NS") | {Action: "DELETE", ResourceRecordSet: .}]}') # Check if there are any records left to delete record_count=$(echo "$changes" | jq '.Changes | length') if [ "$record_count" -eq 0 ]; then echo "" echo "All records deleted successfully." break fi # Submit the batch deletion batch_count=$((batch_count + 1)) echo "Processing batch $batch_count ($record_count records)..." aws route53 change-resource-record-sets \ --hosted-zone-id "$ZONE_ID" --change-batch "$changes" if [ $? -ne 0 ]; then echo "Error processing batch $batch_count. Exiting." exit 1 fi echo "Batch $batch_count completed." # Wait between batches to avoid rate limiting sleep 5 done echo "" echo "Hosted zone $ZONE_ID is now ready for deletion." echo "To delete the hosted zone, run:" echo " aws route53 delete-hosted-zone --id $ZONE_ID"
How to Use the Script
- Create the script file:
nano delete-route53-records.sh
-
Paste the script content and save (Ctrl+X, then Y, then Enter in nano)
-
Make it executable:
chmod +x delete-route53-records.sh
-
Update the
DOMAINvariable in the script to match your hosted zone name (include the trailing dot) -
Run it:
./delete-route53-records.sh
How the Script Works
- Finds the hosted zone ID for the specified domain
- Displays a safety warning and waits for confirmation before proceeding
- Loops through all records in batches of up to 1,000 at a time
- Filters out NS and SOA records (which are required and cannot be deleted)
- Submits each batch as a
ChangeResourceRecordSetsDELETE request - Waits 5 seconds between batches to avoid API rate limiting
- Continues until no deletable records remain
- Outputs the command to delete the hosted zone once all records are removed
Technical Considerations
- API Pagination: The
--max-items 1000parameter is a client-side pagination control. The underlying API returns a maximum of 300 records per page, but the AWS CLI handles the pagination internally and returns up to the specified max-items count. - Rate Limiting: Route 53 has a default limit of 5
ChangeResourceRecordSetsrequests per second per account. The 5-second sleep between batches keeps the script well within this limit. - Record Filtering: The
jqfilterselect(.Type != "SOA" and .Type != "NS")preserves the mandatory NS and SOA records. Note that this also preserves NS records for delegated subdomains — if you need to delete those, adjust the filter to only preserve NS records matching the zone apex. - Idempotency: The script can be safely re-run if interrupted. It will pick up where it left off since already-deleted records will no longer appear in the list.
- Alias Records: Alias records are included in the deletion. No special handling is needed as they are deleted the same way as standard records.
Step 3: Delete the Hosted Zone
After all records have been deleted (only NS and SOA remain), you can delete the hosted zone:
aws route53 delete-hosted-zone --id <your-zone-id>
Summary
By understanding Route 53's API limitations and implementing a batched deletion strategy, you can efficiently clean up hosted zones containing any number of records. The key points are:
- Always back up your records before deletion
- Use batched API calls to stay within safe limits (up to 1,000 changes per request)
- Filter out NS and SOA records which cannot be deleted
- Include delays between batches to respect API rate limits
- The script is idempotent and can be re-run safely if interrupted
Related Resources
- Tags
- Amazon Route 53
- Language
- English
Relevant content
- asked 2 years ago
- Accepted Answerasked a year ago
AWS OFFICIALUpdated 2 months ago