GoDaddy DDNS Updater

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.

GoDaddy.sh
GoDaddy.sh

First you will need is of course your paid domain name, then a GoDaddy “ProductionAPI 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 “ProductionAPI key/secret instead.

GoDaddy API
GoDaddy API

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:

Once the script is in place, schedule a Cron job every 5mins, crontab -e; , examples below on a single line:

a. No logging (recommended):

b. With logging for debugging purposes (you will need to do your own log housekeeping, try logrorate?):

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:

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

189 thoughts on “GoDaddy DDNS Updater”

  1. One thing I would like to point out: the “=~” operator in line 74:

    if [ $? -eq 0 ] && [[ "${PublicIP}" =~ [0-9]{1,3}\.[0-9]{1,3} ]];then
    

    It seems to be bash specific. I personally changed it to “=!” since I only have ash or sh. This shouldn’t be a problem for most people, but I am running this script on Alpine.

    1. Yes it’s bash specific because sh/ash doesn’t support such regular expressions. The line 74 ensure that you have valid IP else something might go wrong when the API returns non-IP results. I’m sure you can have bash easily installed on Alpine, apk add bash or v3.3+ apk add --no-cache bash.

      If you really have no choice but to fallback to sh/ash, then this is correct change for line 74:-
      if [ $? -eq 0 ] && [ "${PublicIP}" != "" ];then

  2. Hello,
    I’ve been trying to get this to work under FreeBSD. pfSense to exact. I can’t get it to run correctly. Currently I have an Ubuntu machine just running this as a cron job with no problems. A waste of resources if you ask me just for a cron.
    This is the error I get:

    Checking current ‘Public IP’ from ‘http://api.ipify.org’…/usr/home/scripts/godaddy.sh: [[: not found
    Fail! my-ip-address

    Now I don’t know if it’s because I don’t have bash installed. I don’t want to install it because of the security issue it has. Instead I’m running sh. Now I’m no coder. Which is one of my biggest regrets not learning it. This is something that I really need help with. And I’m pretty sure other people in the net are interested .

    Thanks,

    1. I believe bash already has its security vulnerability fixed. Just ensure you have the latest version. If you still insist on plain shell, refer to my previous reply to Ion Basa.

      1. Hey,

        I’m still having the same issue.

        Checking current ‘Public IP’ from ‘http://api.ipify.org’…GoDaddy.sh: my.ip.address: not found
        Fail! my.ip.address

        I believe is something in the script difference between sh and bash. I did change where there were [[ ]]to (( ))and that cleared some errors. But that’s as far as I gotten.

        1. Try changing line 74 to this:

          if [ $? -eq 0 ] && [ "${PublicIP}" != "" ];then

              1. Hello again,

                I’m trying to get this to run in cron in pfsense AND opnsense. Both of which are based off of FreeBSD. But it doesn’t run under but it does run under shell with no problems with the change you gave me. I went to the pfsense forum for help. The feedback that I’m getting is that something has to be changed and/or added. I understand that the script works under and that you can wipe your hands clean. But I could REALLY use your help.

                https://forum.pfsense.org/index.php?board=44.0

                  1. And once again, you came through. It was the PATH. You definitely help out a lot of us. Thanks,

  3. Hi Nazaar, Can you help me implement this i am having no luck with it, i am not a programmer just a hobbyist.

    1. Hi Hadi,

      Let me know what’s your system/OS specs in details.

      1. my hosting account is the Deluxe account with Godaddy on Linux platform with the cPanel access

        1. Shouldn’t your DNS/nameservers already pointing to the hosting account Linux server? If yes then you most likely won’t be needing this script at all. This script is only useful for those whose hosting on a dynamic IP address usually home based servers where their ISP doesn’t offer static IPs or at least without additional charges for static IP. Unless you’re planning to move your domain to a dynamic IP, I need to know more details if you have some other complex setups.

          1. Oh Ok thanks, i was under the impression that this script can update my A’record ón my Godaddy DNS to my home IP.

            i am using security cameras at home to have a subdomain like camera1.example.com

            but my ISP does not have a Static IP

            1. Oh I see. Yes this script can do that. You just need to have a Linux machine at home running 24/7, like a NAS box or dd-wrt router, that could schedule this script to check and update that particular subdomain's 'A (host) record' of yours when your ISP's dynamic IP changes. Just simply follow the guide step by step from this post and you should be good to go.

              If you however using a Windows based machine, for Win10, enable BASH (Windows subsystem for Linux) from 'Control Panel->Programs->Programs and Features->Turn Windows features on or off' then enable the developer mode from the 'Settings->Update & Security->For developers' (Google for more details) or for any other Windows version you can install CYGWIN. Then schedule the script to run every 5mins using the Task Scheduler i.e. with CYGWIN: C:\cygwin\bin\bash C:\MyScripts\GoDaddy.sh or BASH: C:\Windows\System32\bash /mnt/c/MyScripts/GoDaddy.sh assuming you placed the script in C:\MyScripts. Just ensure the script's CRLF is being set correctly else you will get errors, use any free Windows based Linux text editor like 'EditPad Lite'.

  4. Many thank bro..

    After much example in google.. finally found something that really work on my ubuntu zentyal server
    Regards

  5. Nazar,
    I’ve had several instances of your script running without issue for over a year now. I’m going to be adding a self-hosted Cloudron to my network and it requires a wildcard A record in order to accommodate the random subdomains created for each user account. Have you ever accomplished this yourself or had anyone message about doing it? I wanted to ask before I began testing with another script.

    Thanks again

    1. I’m also using a wildcard subdomain, sort of a catch-all subdomain if it doesn’t exist. Simply point the main Type=A Name=@ record to an IP which you can use this GoDaddy.sh script to maintain its IP then add another Type=CNAME, Name=* and Value=@. You can also have some other existing static CNAME to point to another external domain which will be treated as an alias. So if your webapp randomly creates a subdomain that doesn’t exist in your DNS records, it will still point to your IP and that particular subdomain will be handled by the webapp itself.

      I’ve never used Cloudron but I would expect it to work similarly to any vhost domain/subdomain recognition method like in Nginx or Apache2 and even those multi-domain aware webapps like multisite WordPress.

      1. I already have the Wildcard A record configured in my zone file. I should have been more specific in my inquiry. Is it possible to change the name variable in your script to Name=* or is there a different method. The Cloudron docs for proper installation unfortunately specify a wildcard A record and not a CNAME. I’m hoping that I can simply replace the record name in the script from @ to * but perhaps it’s not that simple. Any thoughts would be greatly appreciated.

        Thanks again Nazar

        1. Yes you can use Name=* in the GoDaddy.sh script without any issues. The asterisk usually translates to filename expansion which needs to be escaped or quoted but you don’t have to in this case.

          I’ve tried looking up the Cloudron docs but couldn’t find anything mentioning about wildcard A record requirement. I only saw one post from their blog “recommending” wildcard A record so a wildcard CNAME should work too provided it’s being setup properly.

          Since you already have the wildcard A record, you can just continue using it. The only drawback I guess is that, on top of maintaining the wildcard A record IP with GoDaddy.sh, you’ll need another set of GoDaddy.sh script (you’ll need a unique CachedIP variable value for each script if they’re running on the same system) to maintain the origin @ A record IP if you are also using this record. This origin @ A record points to your root domain.

          This is how I have my zone record set up which works with any random subdomain including named subdomain:

          Type    Name    Value     TTL
          ==============================
          # Origin IP maintained by GoDaddy.sh
          A       @       ISP-IP    1 Hour
          
          # Wildcard points to origin @
          CNAME   *       @         1 Hour
          
          # Static points to external
          CNAME   foo     bar.com   1 Hour
          
          1. I appreciate your assistance as usual Nazar. I uploaded a new script with the * in the name variable. I added a new IP cache as well. I have 7 instances of the Godaddy.sh script each with their own IP cache file to update my 7 A records. I can probably use a wildcard CNAME for the Cloudron and it’s something I’ll test at some point. But for now I’ll follow their guidelines:
            https://cloudron.io/blog/2017-02-07-dnssetup.html
            Happy new year!

            1. NP glad it helps (-:

              Wow 7 instances on one system? You could probably benefit from the SuccessExec variable so you can have just one cron scheduled. For the first script, set it to run the rest of your 6 instances only when there’s a successful update e.g. SuccessExec='/path/to/GoDaddy#2.sh;/path/to/GoDaddy#3.sh;#and so on#'. So only if there’s a successful update on the first instance, the rest will run too without probing the same IP change for 7 times every so minutes.

              1. Hmmm…so it would cascade through all the scripts only if the first one had a successful update. Brilliant! Wouldn’t I lose the log function though? I guess I could put that in the last script executed after the entire cascade has completed. Well doing this would make my crontab much smaller. Lol

                Thank You

                1. Ah… for my case I’m not really concerned about the logs, just using the SuccessExec and FailedExec to send out email when necessary.

                  If you need individual logs for each GoDaddy.sh, you’ll need to append stderr/out to each script in the SuccessExec variable. Or better if you just need one log for all, try using grouping {} or subshell () e.g. in your cron for the main script 5 * * * * /path/GoDaddy#1.sh>>/var/log/GoDaddy.log 2>&1 and the rest of the logs goes to SuccessExec variable of the first script SuccessExec='(/path/GoDaddy#2.sh;/path/GoDaddy#3.sh;#and so on#)>>/var/log/GoDaddy.log 2>&1'.

                  So what do we see in the one log for all? If there’s no IP changes, you’ll see only the log of the first script indicating no update required. But when an update is triggered, you’ll see all 7 domains updates in the log. All these examples depends on your needs. Feel free to customize and oh, happy new year to you too!

                  1. I decided to have an email sent to me on SuccessExec= so I installed Postfix and did the proper config and testing. I used the example you have shown on this page above the script (replacing with my own email) but it only sends out locally to /etc/mail/root and not to the external |sendmail address. However if I copy and paste that same example to a terminal prompt it sends out to my external |sendmail address as well as the local /etc/mail/root (without the script variables of course). Is it purposely set up so that it emails to the |sendmail address only when the IP is actually updated? Because as of now now it emails locally to /etc/mail/root every time cron runs the script and it successfully queries the IP cache file.

                    1. The cron by default will send mail for all the scheduled jobs to your localhost spool unless you redirect its stdout/err to null. The SuccessExec variable however is only triggered when there’s a successful update.

                    2. That explains it. I’ll do some digging on where in the script to redirect stdout/err to null.

                      Thanks again.

  6. Hi Nazar,

    I’ve been using this useful script on my debian RPi but after moving to Centos 7 i am receiving the below error message.

    Error: Unable to find ‘curl CLI’.

    I have verified and curl version 7.29.0 is currently installed.

    Thanks

    1. Hi Andreas,

      You’ll need to setup the path environment for both terminal and cron. For terminal set your path in the .profile or .bashrc then relogin. For cron set it up in the crontab before the schedule lines.

      1. echo $PATH gives the below result.
        /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin

        1. Found the problem Nazar.

          The ‘which’ command was missing from my system.
          After ‘yum install which’ the script works.

          Thank you for your help!!

  7. Works great. Thanks. Was having a hard time with the python scripts and modules which broke after a qnap update.
    Thanks

    1. Delete the CacheIP file to force rechecking of CheckURL IP against GoDaddy records.

Leave a Reply

Your email address will not be published. Required fields are marked *

To create code blocks or other preformatted text, indent by four spaces:

    This will be displayed in a monospaced font. The first four 
    spaces will be stripped off, but all other whitespace
    will be preserved.
    
    Markdown is turned off in code blocks:
     [This is not a link](http://example.com)

To create not a block, but an inline code span, use backticks:

Here is some inline `code`.

For more help see http://daringfireball.net/projects/markdown/syntax