-
-
Save neuhaus/9f26a85f426d32e9d05c6db9eadc2db2 to your computer and use it in GitHub Desktop.
| #!/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 |
Overall, this script is great and is saving me a goo amount of time in migrating our IONOS records to Cloudflare
One issue I have had that yo may need to look at is that when you use the resultant zone files to import the records, it is appending the domain suffix to all the records - we've specifically seen it on CNAME and MX records and it caused the site to go offline after period of time
So the IONOS MX record would end up looking like this:

I believe this is because the exported BIND files are missing the "." right at the end of the record name
The exported file shows
ourdomain.org IN MX 10 mx00.ionos.co.uk
and not
ourdomain.org IN MX 10 mx00.ionos.co.uk.
Once we edited one of the files to use the "Dotted FQDN" format, the records imported without issue
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.
claude.ai prompt:
"Using the openapi spec file, convert DNS zones retrieved using this API into bind zone files with a shell script using jq"
then paste the openapi spec file from https://developer.hosting.ionos.de/assets/kms-swagger-specs/dns.yaml
only thing to manually fix so far has been the double quoted TXT records.