2

I am trying to use Cloudflare API v4 to setup DDNS on my server. But I am new in scripting .sh file. I hope to update multiple DNS records in a single .sh file.

I got a script from the internet (script1.sh):

NEW_IP=`curl -s http://ipv4.icanhazip.com`
CURRENT_IP=`cat /Users/foo/Desktop/cloudflare/current_ip.txt`

if [ "$NEW_IP" = "$CURRENT_IP" ]
then
        echo "No Change in IP Adddress"
else
curl -X PUT "https://api.cloudflare.com/client/v4/zones/{zone_id}/dns_records/{dns_record_id}" \
     -H "X-Auth-Email: {my_email}" \
     -H "X-Auth-Key: {global_api_key}" \
     -H "Content-Type: application/json" \
     --data '{"type":"A","name":"{domain_name}","content":"'$NEW_IP'","ttl":1,"proxied":true}' 
echo $NEW_IP > /Users/foo/Desktop/cloudflare/current_ip.txt
fi

The above script is work fine for single DNS record update instead of multiple record update like below (script2.sh):

NEW_IP=`curl -s http://ipv4.icanhazip.com`
CURRENT_IP=`cat /Users/foo/Desktop/cloudflare/current_ip.txt`

if [ "$NEW_IP" = "$CURRENT_IP" ]
then
        echo "No Change in IP Adddress"
else
#domain-one
curl -X PUT "https://api.cloudflare.com/client/v4/zones/{zone_id_for_domain_one}/dns_records/{dns_record_id_for_domain_one_record_one}" \
     -H "X-Auth-Email: {my_email}" \
     -H "X-Auth-Key: {global_api_key}" \
     -H "Content-Type: application/json" \
     --data '{"type":"A","name":"domain-one.com","content":"'$NEW_IP'","ttl":1,"proxied":true}'
curl -X PUT "https://api.cloudflare.com/client/v4/zones/{zone_id_for_domain_one}/dns_records/{dns_record_id_for_domain_one_record_two}" \
     -H "X-Auth-Email: {my_email}" \
     -H "X-Auth-Key: {global_api_key}" \
     -H "Content-Type: application/json" \
     --data '{"type":"A","name":"subdomain.domain-one.com","content":"'$NEW_IP'","ttl":1,"proxied":true}'
#domain-two
curl -X PUT "https://api.cloudflare.com/client/v4/zones/{zone_id_for_domain_two}/dns_records/{dns_record_id_for_domain_two_record}" \
     -H "X-Auth-Email: {my_email}" \
     -H "X-Auth-Key: {global_api_key}" \
     -H "Content-Type: application/json" \
     --data '{"type":"A","name":"domain-two.com","content":"'$NEW_IP'","ttl":1,"proxied":true}'
echo $NEW_IP > /Users/foo/Desktop/cloudflare/current_ip.txt
fi

Can you please help to explain and solve the problem? Please tell me what's wrong in the script. Thanks!

[edit] I run it once by sh /Users/foo/Desktop/script-name.sh, for the first example (script1.sh), it is ok; for second example (script2.sh), return -bash: fork: Resource temporarily unavailable. As I use automatic run script like cron, it is same result.

Samson
  • 177
  • 1
  • 16
  • Does this still works for you...the first script that only updates 1 record ? –  Mar 22 '21 at 12:13

2 Answers2

1

Every curl request done, needed to add & or && to continue the following function.

More explanation here.

NEW_IP=`curl -s http://ipv4.icanhazip.com`
CURRENT_IP=`cat /Users/foo/Desktop/cloudflare/current_ip.txt`

if [ "$NEW_IP" = "$CURRENT_IP" ]
then
        echo "No Change in IP Adddress"
else
#domain-one
curl -X PUT "https://api.cloudflare.com/client/v4/zones/{zone_id_for_domain_one}/dns_records/{dns_record_id_for_domain_one_record_one}" \
     -H "X-Auth-Email: {my_email}" \
     -H "X-Auth-Key: {global_api_key}" \
     -H "Content-Type: application/json" \
     --data '{"type":"A","name":"domain-one.com","content":"'$NEW_IP'","ttl":1,"proxied":true}' &
curl -X PUT "https://api.cloudflare.com/client/v4/zones/{zone_id_for_domain_one}/dns_records/{dns_record_id_for_domain_one_record_two}" \
     -H "X-Auth-Email: {my_email}" \
     -H "X-Auth-Key: {global_api_key}" \
     -H "Content-Type: application/json" \
     --data '{"type":"A","name":"subdomain.domain-one.com","content":"'$NEW_IP'","ttl":1,"proxied":true}' &
#domain-two
curl -X PUT "https://api.cloudflare.com/client/v4/zones/{zone_id_for_domain_two}/dns_records/{dns_record_id_for_domain_two_record}" \
     -H "X-Auth-Email: {my_email}" \
     -H "X-Auth-Key: {global_api_key}" \
     -H "Content-Type: application/json" \
     --data '{"type":"A","name":"domain-two.com","content":"'$NEW_IP'","ttl":1,"proxied":true}'
echo $NEW_IP > /Users/foo/Desktop/cloudflare/current_ip.txt
fi
Samson
  • 177
  • 1
  • 16
1

After going through many posts on this topic, I've ended up taking parts from a number of posts and settled on the below.

The below will loop through the entries in the array "dnsrecords" and update each with the machine's current external address.

See more info here, run as cronjob here.

#!/usr/bin/bash

## Cloudflare authentication details
## Keep these private
cloudflare_auth_email=Your_Email
cloudflare_auth_key="Your_API_Token"
zoneid="Your_Zone_ID"

## Cloudflare Proxied DNS Records as Array
dnsrecords_proxied=(
    "domain.com"
    "www.domain.com"
    "sub1.domain.com"
    "sub2.domain.com"
    "sub3.domain.com"
    "sub3.domain.com"
    )
    
## Cloudflare Non-Proxied DNS Records as Array
dnsrecords_not_proxied=(
    "vpn01.domain.com"
    "vpn02.domain.com"
    )

## Files to log to (replace "path/to/" with script path)
log=path/to/log.log
log_ip=path/to/previous_ip
## Getting Date/Time
dt=$(date '+%d/%m/%Y %H:%M:%S')
## Get old IP from file
old_ip=$(cat $log_ip)
## Get the current external IP address
ip=$(curl -s -X GET https://api.ipify.org)

## Checking if IP changed since last update
if [[ ! $ip =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]] || [ $ip = $old_ip ]; then
echo -en "$dt - Previous IP:$old_ip\n$dt - Current  IP:$ip\n$dt - No Changes Required....\n" >> $log
echo "$(tail -n 1000 $log)" > $log
  exit
  ## Exit if IP has not changed
else
## If the IP changed, not match the one on file "previous_ip"
echo -en "$dt - Previous IP:$old_ip\n$dt - Current  IP:$ip\n$dt - Starting Updates....\n" >> $log
## Processing Proxied DNS Records
for dnsrecord in "${dnsrecords_proxied[@]}"
do

## For each DNS Record in Array "dnsrecords"

# Getting the DNS Record ID
dnsrecordid=$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones/$zoneid/dns_records?type=A&name=$dnsrecord" \
  -H "X-Auth-Email: $cloudflare_auth_email" \
  -H "Authorization: Bearer $cloudflare_auth_key" \
  -H "Content-Type: application/json" | jq -r  '{"result"}[] | .[0] | .id') &&

# Updating the DNS Record
curl -s -X PUT "https://api.cloudflare.com/client/v4/zones/$zoneid/dns_records/$dnsrecordid" \
  -H "X-Auth-Email: $cloudflare_auth_email" \
  -H "Authorization: Bearer $cloudflare_auth_key" \
  -H "Content-Type: application/json" \
  --data "{\"type\":\"A\",\"name\":\"$dnsrecord\",\"content\":\"$ip\",\"ttl\":1,\"proxied\":true}" | jq
echo -en "$dt - Updated - $dnsrecord \n"  >> $log
done

## Processing Non Proxied DNS Records
for dnsrecord in "${dnsrecords_not_proxied[@]}"
do

## For each DNS Record in Array "dnsrecords"

# Getting the DNS Record ID
dnsrecordid=$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones/$zoneid/dns_records?type=A&name=$dnsrecord" \
  -H "X-Auth-Email: $cloudflare_auth_email" \
  -H "Authorization: Bearer $cloudflare_auth_key" \
  -H "Content-Type: application/json" | jq -r  '{"result"}[] | .[0] | .id') &&

# Updating the DNS Record
curl -s -X PUT "https://api.cloudflare.com/client/v4/zones/$zoneid/dns_records/$dnsrecordid" \
  -H "X-Auth-Email: $cloudflare_auth_email" \
  -H "Authorization: Bearer $cloudflare_auth_key" \
  -H "Content-Type: application/json" \
  --data "{\"type\":\"A\",\"name\":\"$dnsrecord\",\"content\":\"$ip\",\"ttl\":1,\"proxied\":false}" | jq
echo -en "$dt - Updated - $dnsrecord \n"  >> $log
done
echo $ip > $log_ip
echo -en "$dt - Updates Completed.... \n"  >> $log
echo "$(tail -n 1000 $log)" > $log
fi
Nuno Chaves
  • 176
  • 3