As I’m running this site itself on my 4TB WDMyCloud home NAS, refer to my post WebHosting on WDMyCloud V4 Firmwares, I will need my DNS to be always pointing to it when my public IP changes.
Although my public IP seldom changes, I’ve been using a Python based script with its ‘pygodaddy’ module for a while to auto update my GoDaddy DDNS pointing to my WDMyCloud NAS. The script is supposed to update my current public IP by parsing GoDaddys DNS update form. But on few occasions when there’s the need to update, the script failed to work because obviously GoDaddy had changed something in their front-end. I’ve also used a similar PHP based script but that too failed to work. And worst still, for as long that I know of, GoDaddy hasn’t provide any means of updating the records other than manually from their site itself.
Like many others with paid GoDaddy domain account, I’ve been looking for permanent solution not until recently and long awaited for, GoDaddy has finally implemented some APIs for developments which now provides the ability to update the DNS records via a REST call. You can see more details at their developer’s site, https://developer.godaddy.com.
Disclaimer: As I’m frequently updating the original guides and installers here on TeaNazaR.com, I will not be responsible for any brick issues if you were to follow my obsolete guides copied elsewhere. Thus subscribe to this post to get latest updates. Modifying any part of a device may void its warranty.
With this API, I’ve written another simple shell script to perform the DDNS update which can be scheduled with a 5mins repeating Cron job. It should work on any Linux based systems. Why shell script? It’s simple, low-resource and does the update faster than any similar Python, PHP, Perl, Java JIT compiler I’ve tested on the NAS. On each run, the script will check for public IP changes against the local cache and GoDaddy records itself using cURL and only attempt to update if necessary. Even though GoDaddy did not specify the minimum update interval, updating too frequently could affect DNS propagation which could cause delay of the DNS being updated across the internet.
First you will need is of course your paid domain name, then a GoDaddy “Production” API key/secret to use with this script. Go to this specific link, log in with your GoDaddy account then generate the API key/secret. Note that the very first time you do this, it will be created as “Test” environment (seen at the time of writing). Go back to the same page again or click on the “Keys” top menu then generate a new “Production” API key/secret instead.
You can place this script anywhere on your server. I’ll explain more for users who’s not familiar with Linux.
Launch the editor i.e. nano /root/scripts/GoDaddy.sh; . Copy & paste the script source from the bottom of this post into the terminal, update the API key/secret , Domain and other desired options, then CTRL+X to save. Test the script if it’s working:
1 | /bin/bash /root/scripts/GoDaddy.sh; |
Once the script is in place, schedule a Cron job every 5mins, crontab -e; , examples below on a single line:
a. No logging (recommended):
1 | */5 * * * * /bin/bash /root/scripts/GoDaddy.sh>/dev/null 2>&1 |
b. With logging for debugging purposes (you will need to do your own log housekeeping, try logrorate?):
1 | */5 * * * * /bin/bash /root/scripts/GoDaddy.sh>>/var/log/GoDaddy.sh.log |
To update a subdomain (second-level domain i.e. subdomain.domain.com) instead of primary domain (top-level domain i.e. domain.com), set
Type=A
Type=CNAME (Updated: CNAME by default can’t point to an IP) and
Name=subdomain where subdomain is your subdomain.domain.com as seen in the GoDaddy DNS setup page.
I’ve also added optional advanced variables to include any custom scripts, programs or commands to execute when the IP update occurs or failed. This is so that you can place this script on top of your other applications i.e. those which requires public IP update cached in /tmp/current_ip or those which triggers upon IP changes. Read the script’s comments for more details. For instance, you can use Postfix‘s sendmail to trigger an email notification upon IP update or failures by setting the SuccessExec or FailedExec values. Those who’s using my WebHosting on WDMyCloud V4 Firmwares mods, you can configure its ESMTP to get similar results. For an example to get notified upon successful IP update, set the SuccessExec value to:
1 | SuccessExec='echo -e "To:myself@mail.teanazar.com\nFrom:alert@mail.teanazar.com\nSubject:GoDaddy.sh IP Updated\n\nGoDaddy.sh IP Updated ${Domain} ${PublicIP} $(date)\n"|sendmail "myself@mail.teanazar.com"' |
This should be the permanent solution for now until GoDaddy decides to make other changes. Need a Windows based DDNS client updater? Not sure why would anyone leave their PC always awaked, unless it’s a Windows based NAS/server. Perhaps I can help to write a simple Windows executable. But you can always run Cygwin to deploy shell scripts also Ubuntu is already runnable in Windows 10 Insider Preview (at the time of writing). For now, only my NAS running 24/7 needs this. Any questions you can post it here, enjoy (-:
GoDaddy.sh
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 | #!/bin/bash # GoDaddy.sh v1.3 by Nazar78 @ TeaNazaR.com ########################################### # Simple DDNS script to update GoDaddy's DNS. Just schedule every 5mins in crontab. # With options to run scripts/programs/commands on update failure/success. # # Requirements: # - curl CLI - On Debian, apt-get install curl # # History: # v1.0 - 20160513 - 1st release. # v1.1 - 20170130 - Improved compatibility. # v1.2 - 20180416 - GoDaddy API changes - thanks Timson from Russia for notifying. # v1.3 - 20180419 - GoDaddy API changes - thanks Rene from Mexico for notifying. # # PS: Feel free to distribute but kindly retain the credits (-: ########################################### # Begin settings # Get the Production API key/secret from https://developer.godaddy.com/keys/. # Ensure it's for "Production" as first time it's created for "Test". Key=fsvVddxVsfe_frhN1SAgfdgCdAfyVdWDdv Secret=FwkUfafh8dgrsdydrdfC1e # Domain to update. Domain=teanazar.com # Advanced settings - change only if you know what you're doing :-) # Record type, as seen in the DNS setup page, default A. Type=A # Record name, as seen in the DNS setup page, default @. Name=@ # Time To Live in seconds, minimum default 600 (10mins). # If your public IP seldom changes, set it to 3600 (1hr) or more for DNS servers cache performance. TTL=600 # Writable path to last known Public IP record cached. Best to place in tmpfs. CachedIP=/tmp/current_ip # External URL to check for current Public IP, must contain only a single plain text IP. # Default http://api.ipify.org. CheckURL=http://api.ipify.org # Optional scripts/programs/commands to execute on successful update. Leave blank to disable. # This variable will be evaluated at runtime but will not be parsed for errors nor execution guaranteed. # Take note of the single quotes. If it's a script, ensure it's executable i.e. chmod 755 ./script. # Example: SuccessExec='/bin/echo "$(date): My public IP changed to ${PublicIP}!">>/var/log/GoDaddy.sh.log' SuccessExec='' # Optional scripts/programs/commands to execute on update failure. Leave blank to disable. # This variable will be evaluated at runtime but will not be parsed for errors nor execution guaranteed. # Take note of the single quotes. If it's a script, ensure it's executable i.e. chmod 755 ./script. # Example: FailedExec='/some/path/something-went-wrong.sh ${Update} && /some/path/email-script.sh ${PublicIP}' FailedExec='' # End settings Curl=$(which curl 2>/dev/null) [ "${Curl}" = "" ] && echo "Error: Unable to find 'curl CLI'." && exit 1 [ -z "${Key}" ] || [ -z "${Secret}" ] && echo "Error: Requires API 'Key/Secret' value." && exit 1 [ -z "${Domain}" ] && echo "Error: Requires 'Domain' value." && exit 1 [ -z "${Type}" ] && Type=A [ -z "${Name}" ] && Name=@ [ -z "${TTL}" ] && TTL=600 [ "${TTL}" -lt 600 ] && TTL=600 echo -n>>${CachedIP} 2>/dev/null [ $? -ne 0 ] && echo "Error: Can't write to ${CachedIP}." && exit 1 [ -z "${CheckURL}" ] && CheckURL=http://api.ipify.org echo -n "Checking current 'Public IP' from '${CheckURL}'..." PublicIP=$(${Curl} -kLs ${CheckURL}) if [ $? -eq 0 ] && [[ "${PublicIP}" =~ [0-9]{1,3}\.[0-9]{1,3} ]];then echo "${PublicIP}!" else echo "Fail! ${PublicIP}" eval ${FailedExec} exit 1 fi if [ "$(cat ${CachedIP} 2>/dev/null)" != "${PublicIP}" ];then echo -n "Checking '${Domain}' IP records from 'GoDaddy'..." Check=$(${Curl} -kLsH"Authorization: sso-key ${Key}:${Secret}" \ -H"Content-type: application/json" \ https://api.godaddy.com/v1/domains/${Domain}/records/${Type}/${Name} \ 2>/dev/null|grep -Eo '\b([0-9]{1,3}\.){3}[0-9]{1,3}\b' 2>/dev/null) if [ $? -eq 0 ] && [ "${Check}" = "${PublicIP}" ];then echo -n ${Check}>${CachedIP} echo -e "unchanged!\nCurrent 'Public IP' matches 'GoDaddy' records. No update required!" else echo -en "changed!\nUpdating '${Domain}'..." Update=$(${Curl} -kLsXPUT -H"Authorization: sso-key ${Key}:${Secret}" \ -H"Content-type: application/json" -w"%{http_code}" -o/dev/null \ https://api.godaddy.com/v1/domains/${Domain}/records/${Type}/${Name} \ -d"[{\"data\":\"${PublicIP}\",\"ttl\":${TTL}}]" 2>/dev/null) if [ $? -eq 0 ] && [ "${Update}" -eq 200 ];then echo -n ${PublicIP}>${CachedIP} echo "Success!" eval ${SuccessExec} else echo "Fail! HTTP_ERROR:${Update}" eval ${FailedExec} exit 1 fi fi else echo "Current 'Public IP' matches 'Cached IP' recorded. No update required!" fi exit $? |
Will this work with several A records in the same domain? I have a few subdomains I use so I can have multiple websites for different reasons. Thanks! This tutorial is great!!!
Hello Will,
This script was made simple and can only update one record. However you can have multiple scripts running or link them together with the
SuccessExec
variable (If the first script updated successfully, it will then run the rest of the scripts defined in this variable). Just ensure you specify a uniqueCachedIP
variable for each script if they’re running on the same system.Hey Nazar.. MANY Thanks for this!
I was previously running the many variations of the pygodaddy scripts on my Synology NAS and the last day it actually worked was May 20, 2016. Every day since.. FAIL FAIL FAIL. heh
Anyways, I got your script working with a few changes because I’m running ash instead of bash. One issue I see (on my system anyways)… This could bomb out (but not actually fail[ERROR]) IF… godaddy IP = 1.2.3.4, cached IP = 4.3.2.1, public IP = 4.3.2.1….
Hello NtegrA,
No problem glad it helps.
As for the potential issue you brought up, this scenario usually happens when the GoDaddy IP has been changed manually or by other means. The script was made simple and will only check the IP at GoDaddy if there is a change between cached and public IP.
If you’re worried about this, the key here is the cached IP file. I placed the cached IP in the tmpfs so when the NAS reboots (obviously tmpfs cleared) it will be forced to check with GoDaddy because of the missing cached IP. You can also schedule to remove this cached IP file say every 1hr to force the checks against GoDaddy at the next 5mins interval.
@NtegrA
What did you change to make it work in ash. I am using a Synology as well. But im haven’t really used ash over bash.
Thanks
I too have least knowledge of the ash, but I recalled quite sometime ago installing this script on one of my donor’s DSM6. Defaulted with ash but there’s bash installed on his Synology (can’t remember which model it was or if it was behind busybox but I remember installing python modules). So I just need to chmod the script then install it to the scheduler and it ran as expected. Try checking bash on your system if it’s available else I think it’s easier to install bash or let’s wait for NtegrA to reply.
Hello,
I have a fresh install of Debian Jessie and have run apt-get install curl, apt-get update, and apt-get upgrade but whenever I run the script I keep getting the “Unable to find curl CLI” error. I can see curl in /usr/bin/curl and when I run /usr/bin/which curl 2 it returns the correct /usr/bin/curl value. Any ideas?
Thanks!
Hi Nate,
That is strange, I have no issues with any of Debian’s wheezy, jessie or sid. Could you try opening a new bash session then retry running the script?
You should see
/usr/bin/curl
when you run this in a single line:Curl=$(/usr/bin/which curl); echo ${Curl}
.Unfortunately still getting the same error running the scripts in a new window. When I run
Curl=$(/usr/bin/which curl); echo ${Curl}
I do get the output you indicated,/usr/bin/curl
.The exact error output is below:
root@*****:/usr/local/bin#
/bin/bash udGDBeagle.sh;
udGDBeagle.sh: line 2: $’\r’: command not found
udGDBeagle.sh: line 16: $’\r’: command not found
udGDBeagle.sh: line 22: $’\r’: command not found
udGDBeagle.sh: line 25: $’\r’: command not found
udGDBeagle.sh: line 29: $’\r’: command not found
udGDBeagle.sh: line 32: $’\r’: command not found
udGDBeagle.sh: line 36: $’\r’: command not found
udGDBeagle.sh: line 39: $’\r’: command not found
udGDBeagle.sh: line 43: $’\r’: command not found
udGDBeagle.sh: line 49: $’\r’: command not found
udGDBeagle.sh: line 56: $’\r’: command not found
Error: Unable to find ‘curl CLI’.
numeric argument requiredt: 1
The issue seems to be with CRLF. Which text editor did you use? Try converting the file with dos2unix or create a new file using vi or nano from the console then paste the entire script then edit your variables and save.
Thanks Nazar, copying it directly into nano fixed it. My first attempt I copied the script into Notepad to edit my variables and then copied it into nano. Works perfectly now!
No problem glad it helps (-:
Thanks for sharing!
i also run this script at boot to have faster response time in any WAN disconnect event.
Maybe in can be incorporated?
Hi Timson,
No problem. My public IP seldom change on reconnects and my WAN seldom disconnects only in an event of a power trip. I also added this script to the cron @reboot and ifplugd service so the DDNS restore time if necessary is minimal.
I prefer to have lesser stuffs running in background due to my underpowered NAS but yeah of course you can wrap your script around this script. Your script method is useful for those whose having frequent disconnects or IP changes. Thanks for sharing (-:
Hi , thanks for the great script, But I have some problem while updating subdomain.
I already add a CNAME record in DNS manager named z point to @
and modify the script , domain=mc4.us , TYPE=CNAME,Name=z , but there`s some error messages like this
please help , thanks
I can’t remember if CNAME pointing to an IP used to work with GoDaddy. Actually by right it shouldn’t and it doesn’t work now, I’ll updated the guide. Can you setup Type=A, then Name=z both on GoDaddy and in the script?
Hey!
My ISP only provide me a IPv6 Address. What do I need to change in the script to make it work with IPv6? Thanks!
Hi Rolf,
I haven’t tried because I don’t have an IPv6 but this should work. The
CheckURL
variable should return an IPv6 in your case. If it doesn’t, change the URL toCheckURL=http://v6.ipv6-test.com/api/myip.php
.Then change the followings in the script:
Set
Type=AAAA
Replace the script in line 73 to:
if [ $? -eq 0 ] && [ "${PublicIP}" != "" ];then
Let me know how it goes.
Thanks so much! It works!! 🙂 Um, maybe I can ask another question?
My router from ISP only has Port Range Triggering (and no Port Forwarding). I entered port 22, but it is not open. I think SSH don’t trigger port 22 by itsown. Is there a way I can trigger this port on my raspberry pi so it will be open by the firewall? The only other way it would work is to disable the firewall 🙁
No problem glad it helps (-:
About your router, which make/model it is? Does it support UPnP? If yes you can install miniupnpc then setup a cronjob hourly (0 * * * * /usr/bin/upnpc …) and on startup (@reboot /usr/bin/upnpc…):-
Forward to a specific IP:
/usr/bin/upnpc -a ip port external_port protocol [duration]
Forward directly to the Raspberry Pi:
/usr/bin/upnpc -r port1 protocol1 [port2 protocol2] [...]
Just type
upnpc
to see more options.Utterly Awesome. I’m a Dad with some low level bash and python and I think you’ve done a generous thing by sharing this. Works perfectly, I’m going to move from a static IP plan to a dynamic IP plan over our NBN and your script has made it possible for me to keep my servers running without a hassle. Thank you.
Hello Simon,
No problem glad it helps (-:
The same applies here .. works excellent
One additional remark
My touch sometimes needs an different location and use
perhaps it is nice to add flexibility in the environment ^_^
TPATH=$(which touch)
Hello jan,
I’ve made changes to the touch command 🙂
Lovely and useful work! Got it running on MacOS Sierra in 5 minutes, just needed to change a couple paths and a few permissions. MacOS has deprecated cron in favor of launchd, and I wasn’t up to crafting a launchd daemon script, but cron is still available. Thanks much, I’ve been grumbling about this problem for too long.
Hello M.Daguerre,
No problem glad it helps (-: