Skip to content

Instantly share code, notes, and snippets.

@neuhaus
Last active August 29, 2025 17:36
Show Gist options
  • Select an option

  • Save neuhaus/9f26a85f426d32e9d05c6db9eadc2db2 to your computer and use it in GitHub Desktop.

Select an option

Save neuhaus/9f26a85f426d32e9d05c6db9eadc2db2 to your computer and use it in GitHub Desktop.
retrieve all domain zones from IONOS using the API and convert them into bind zone files.
#!/bin/bash
# Check if API key is provided
if [ -z "$IONOS_API_KEY" ]; then
echo "Error: IONOS_API_KEY environment variable must be set"
exit 1
fi
# Base API URL
API_BASE="https://api.hosting.ionos.com/dns/v1"
# Function to convert records to BIND zone format
convert_zone_to_bind() {
local zone_name="$1"
local records="$2"
local output_file="${zone_name}.zone"
# Generate zone file header
cat > "$output_file" << EOL
\$ORIGIN ${zone_name}.
\$TTL 3600
@ IN SOA ns1.${zone_name}. hostmaster.${zone_name}. (
$(date +%Y%m%d%H) ; Serial
3600 ; Refresh
1800 ; Retry
604800 ; Expire
86400 ) ; Minimum TTL
; Nameservers
@ IN NS ns1.${zone_name}.
@ IN NS ns2.${zone_name}.
EOL
# Process each record
echo "$records" | jq -c '.[]' | while read -r record; do
local name=$(echo "$record" | jq -r '.name')
local type=$(echo "$record" | jq -r '.type')
local content=$(echo "$record" | jq -r '.content')
local ttl=$(echo "$record" | jq -r '.ttl // 3600')
local prio=$(echo "$record" | jq -r '.prio // ""')
# Strip zone name from the record name if present
name="${name%%.$zone_name}"
# Convert record types to BIND format
case "$type" in
A)
echo "${name:-@} IN A $content" >> "$output_file"
;;
AAAA)
echo "${name:-@} IN AAAA $content" >> "$output_file"
;;
CNAME)
echo "${name:-@} IN CNAME $content." >> "$output_file"
;;
MX)
echo "${name:-@} IN MX $prio $content." >> "$output_file"
;;
NS)
echo "${name:-@} IN NS $content." >> "$output_file"
;;
TXT)
echo "${name:-@} IN TXT $content" >> "$output_file"
;;
SRV)
# SRV record format: _service._protocol.name TTL class SRV priority weight port target
echo "$name IN SRV $prio 1 $(echo "$content" | cut -d' ' -f2-)" >> "$output_file"
;;
CAA)
echo "${name:-@} IN CAA $content" >> "$output_file"
;;
esac
done
echo "Generated zone file for $zone_name: $output_file"
}
# Retrieve list of zones
zones=$(curl -s -X GET "$API_BASE/zones" \
-H "X-API-Key: $IONOS_API_KEY" \
-H "Accept: application/json")
# Process each zone
echo "$zones" | jq -c '.[]' | while read -r zone; do
zone_id=$(echo "$zone" | jq -r '.id')
zone_name=$(echo "$zone" | jq -r '.name')
# Retrieve zone details with all records
zone_details=$(curl -s -X GET "$API_BASE/zones/$zone_id" \
-H "X-API-Key: $IONOS_API_KEY" \
-H "Accept: application/json")
# Extract and convert records
records=$(echo "$zone_details" | jq '.records')
convert_zone_to_bind "$zone_name" "$records"
done
@neuhaus
Copy link
Author

neuhaus commented Aug 29, 2025

Thanks for the feedback. While i haven't had this issue, i've added the trailing dot to NS, CNAME and NS records in the script. SRV records are a bit more tricky so i leave that as an exercise for the reader.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment