GoDaddy DynDNS for the poor

Recently, I bought a fresh new domain from godaddy.com for my personal homepage that hosted on a server at home. Admittedly, I didn’t really spend any time on customer satisfaction or the stuff they support, they just had the cheapest offer for a .me domain 🙂 So after getting used to their cluttered web interface, I discovered they don’t support dynamic DNS in any way. In such a case, you have several options:

1. Transfer the domain to a registrar that offers dynamic DNS service

The obvious though costly solution if you just bought the domain. It can also take months to complete so that usually a non-option.

2. Use a CNAME and point it do a your DynDNS provider-supplied domain

However, this means only a subdomain (usually www) would point to your dynamic DNS domain. As an example, this is how it would look in my case:

www.peilicke.me -> duff.i324.me

There’s a simple guide in the GoDaddy forum to achieve that with their web interface. But that means wasting the actual domain, not nice.

3. Use the name servers of your DynDNS provider

GoDaddy (and other registrars) allow to replace the name servers and you could use those from your DynDNS provider given they allow it. This is how you could do it with dyndns.org. However, they started charging for that a while ago, to bad.

4. Do it yourself

You only need a script that discovers the public IP assigned to you by your ISP and write a little screen-scraper that logs into go GoDaddy’s ZoneFile Editor ™ fills and submit the A record form. Turns out that other people already had (and solved) those issues, so this is how it could look like:

#!/usr/bin/env python

import logging
import pif
import pygodaddy

logging.basicConfig(filename='godaddy.log', format='%(asctime)s %(message)s', level=logging.INFO)
GODADDY_USERNAME="@USERNAME@"
GODADDY_PASSWORD="@PASSWORD@"
client = pygodaddy.GoDaddyClient()
client.login(GODADDY_USERNAME, GODADDY_PASSWORD)

for domain in client.find_domains():
    dns_records = client.find_dns_records(domain)
    public_ip = pif.get_public_ip()
    logging.debug("Domain '{0}' DNS records: {1}".format(domain, dns_records))
    if public_ip != dns_records[0].value:
        client.update_dns_record(domain, public_ip)
        logging.info("Domain '{0}' public IP set to '{1}'".format(domain, public_ip))

Depending on where you want to run the script, you may need to fetch the dependencies. In my case it’s running on a Synology DiskStation 213. Underneath it’s amazing software stack is an embedded Linux with Busybox. Luckily, it already has a Python interpreter, so for me a wrapper script looks like:

#!/bin/sh
OLD_PWD=$PWD
ROOT_DIR=$(dirname $0)
cd $ROOT_DIR
if [ ! -d .venv27 ] ; then
  curl -O https://pypi.python.org/packages/source/v/virtualenv/virtualenv-1.9.tar.gz
  tar xvfz virtualenv-1.9.tar.gz
  python virtualenv-1.9/virtualenv.py .venv27
fi
source .venv27/bin/activate
pip install -q --upgrade pif pygodaddy
./godaddy.py
deactivate
cd $OLD_PWD

Since your ISP will cut your connection every 24 hours (usually during the night), you would want to continuously run this script by putting it into /etc/crontab. On the DiskStation, you have to use tabs, not spaces and you have to restart crond after editing (It’s explained in the German wiki):

<br />*/5 * * * * root /path/to/godaddy.sh<br />

That’s it.

UPDATE: The code is now versioned on github: https://github.com/saschpe/godaddy-dyndns

69 thoughts on “GoDaddy DynDNS for the poor

  1. Would you be able to expand on your DYI option and provide other examples. I don’t have programming background and I would like to use this following subdomain vpn.xyz.com and update above script. What info would I have change and what script would I run on Suse server? Thx

  2. It heavily depends. Some services provide an API which one can use. Godaddy does not so I use a screenscraper. The virtualenv approach for Python software should work out of the box but openSUSE provides very comprehendive Python packages which one could use. Currently the script is rather godaddy-specific. For extending it to other domain registrars, I likely need some credentials and a test domain. Some donation wouldnt hurt either 🙂

  3. In my case I have my own domain on Godaddy and I would like to do exactly what you did for my subdomain (ex. vpn.xyz.com). If I were to run this on SuSe box (which I have) what script should I use and what modification should I made in order for this script to obtain my ISP IP and log in to my GoDaddy account to update A record? Looking at at script wrapper I don’t see any info related to GoDaddy credentials.

  4. Ah, now i understand. Just put replace @USERNAME@ and @PASSWORD@ with your credentials. The script updates all domains. To update only a specific one replace client.find_domains() with [“my.sub.domain”].

  5. When I execute script I am getting following output. I have replaced client.find_domains() with vpn.xyz.com (my subdomain).

    linux-5swp:/etc/cron.hourly # sh godaddy
    godaddy: line 2: $’\r’: command not found
    godaddy: line 3: import: command not found
    godaddy: line 4: import: command not found
    godaddy: line 5: import: command not found
    godaddy: line 6: $’\r’: command not found
    godaddy: line 7: syntax error near unexpected token `filename=’godaddy.log’,’
    ‘odaddy: line 7: `logging.basicConfig(filename=’godaddy.log’, format=’%(asctime)s %(message)s’, level=logging.INFO)

  6. it seems you tried to invoke the Python script with Bash. Use “# python godaddy” instead or simply “# ./godaddy” (assuming executable bits set accordingly). Sorry for the late reply, been traveling for a while.

  7. 19 lines for the first and 14 for the second ..

    thought may not have been browser problem, so also tried ie, but simply cannot get whole listing ..

  8. ok .. sorry .. thought there would be an end to the for loop .. and if statement ..

    many thanks ..

    will experiment ..

  9. Hello, thanks for this post, this would be very useful for me too, however, for some reasons, it does not work for me. I’m also trying to get it work with only one specific domain (a subdomain to be precise) like Rafal. I replaced client.find_domains() with my domain like:
    for domain in [“mysub.mydomain.com”]:

    But I get the following error:

    Traceback (most recent call last):
    File “./godaddy.py”, line 17, in
    if public_ip != dns_records[0].value:
    IndexError: list index out of range

    I haven’t learned python, but I guess the dns_records[0] is empty/null? Maybe client.find_dns_records(domain) couldn’t fetch it? Do you have any idea what could be the cause of this? (Now I tried, and when giving a main domain – not a subdomain of it-, it works!)

    Thanks in advance!

  10. Ok, I figured out that I need to use the main domain, and the dns_records[n] will point to the needed A entry (like my subdomains). But when I use the “client.update_dns_record(domain, public_ip)” it will update every dns_records[] element I guess. So modifying only one specific dsn record is not possible? 😦

  11. Not with the current script. However, if you want to share your modifications I could upload the code to github and wait for pull requests 🙂

  12. Well, I could finally manage it. I needed to use my main domain in the for statement. Then check on godaddy dns zone file, which A line is for my subdomain (this is only needed for the comparison with the actual IP). It was the 3rd line, stored in “dns_records[2]”. In the “client.upgrade_dns_record()” you can use a subdomain only in “client.find_dns_record()” you can’t. So this is how it worked:

    for domain in [“mydomain.com”]:
    dns_records = client.find_dns_records(domain)
    public_ip = pif.get_public_ip()
    logging.debug(“Domain ‘{0}’ DNS records: {1}”.format(domain, dns_records))
    if public_ip != dns_records[2].value:
    client.update_dns_record(“sub.mydomain.com”, public_ip)
    logging.info(“Domain ‘{0}’ public IP set from ‘{1}’ to ‘{2}'”.format(domain, dns_records[2].value, public_ip))

    I hope it’s understandable 🙂

  13. hi there,
    anywhere that i could find a detailed instruction to install ur DIY option on my DSM plz.
    sorry I am not neither linux or programming expert

  14. Can you be more specific about the issues you are facing? This script is supposed to work only with GoDaddy DynDNS. In general you have to put both scripts into any directory, replace the dummy credentials with yours and run the wrapper script. That should update your public IP in GoDaddy’s web interface. For that to happen regularly, you need to set up a cron job.

  15. you are a god!! issue was driving me nuts, this worked like a fkin charm!!

  16. Thanks this is exactly what I was looking for!
    I’ve written a version based on what you and agocska have done that will loop through multiple domains and host names to change whichever ones you choose. I’m not a programmer and have never played with Python before. Can you check this over and offer corrections? (fully commented)
    ————— CODE ————————
    #!/usr/bin/env python
    import logging # creates a log file
    import pif # public address checker
    import pygodaddy # “… a 3rd-party client library … to make GoDaddy suck less.”
    logging.basicConfig(filename=’godaddy.log’, format=’%(asctime)s %(message)s’, level=logging.INFO) #setup the log file
    GODADDY_USERNAME=”@USERNAME@” # replace @USERNAME@ with godadday login id
    GODADDY_PASSWORD=”@PASSWORD@” # ditto for password
    client = pygodaddy.GoDaddyClient() # set client as pygodaddy
    client.login(GODADDY_USERNAME, GODADDY_PASSWORD) # login
    domains_list = [“@DOMAIN_NAME@”, “@DOMAIN_NAME@”, “@DOMAIN_NAME@”] # replace @DOMAIN_NAME@ with domain names i.e. “linux.com”
    hosts_list = [“@HOST_NAME@”, “@HOST_NAME@”, “@HOST_NAME@” ] # replace @HOST_NAME@ with just the host names i.e. “www” use “@” for bare domain name
    public_ip = pif.get_public_ip() # set public_ip to the internet routeable address
    for target_domain in domain_list: # loop through the list of domain names
    for target_host in hosts_list: # loop through the list of host names that may be under the current domain
    for subdomain in client.find_dns_records(target_domain): # loop through all the A-Records for current domain
    if subdomain.hostname == target_host: # if the current hostname matches our target then
    fq_subdomain = (“{0}.{1}”.format(subdomain.hostname,domain)) #concatinate the host name with the domain
    loggin.info(“Found subdomain ‘{0}’ as ‘{1}’”.format(fq_subdomain,subdomain.value) # log the current IP
    if public_ip != subdomain.value: # if the current ip value is not the same as the public IP then
    client.update_dns_record(fq_subdomain, public_ip) # change it
    loggin.info(“Changed subdomain ‘{0}’ to ‘{1}’”.format(fq_subdomain,public_ip) # log the new IP
    else: # no change needed
    logging.info(“No change to subdomain ‘{0}’ address needed”.(fq_subdomain) # log no change made
    # end of if-then – Python does not use conditional end
    # end of if-then
    # end of subdomain for-loop – Python does not use a loop end
    #end of target_host for-loop
    #end of target_domain for-loop
    # end of script – Python does not like to talk about endings.
    —————— End Code ————-

  17. Hi,

    What would you name these scripts, and which folders to place them in linux like Ubuntu. And how would you run it like any default index.php a simple instruction on configuring the files on the server would greatly appreciated… Very interesting code cheers…

  18. Do you have a bitcoin wallet address? I was hoping to make a small donation for the “Do It Yourself DynDNS” python script that I am now using. Works great!

  19. Hi,

    I have a domain and subdomain in Godaddy. I’m using a remote desktop application to access my clients PC’s named ScreenConnect that works like TeamViewer but it is installed on a server at home. To access the application I go to my subdomain. My problem is that every time my ISP changes my IP, I have to access the server via TeamViewer, check the public IP, go to Godaddy and change the subdomain “POINTS TO” section.

    Long story short… I HAVE NO CLUE how to run your Script or where to run it. Could you please help me? I’m not an expert on PHP nor other programming language.

  20. Since the script updates to the public IP (assigned by your ISP) of the machine it’s running on, you have to run it on the server you want to expose to the internet. On that server, you need at least a Python interpreter and bash (for the wrapper script). That means something Unix-like (Linux, Mac OS, you name it). If you’re running a Windows server, you would need to change the bash script into a Windows batch script. Either way, the Python skript needs to be invoked regularly. That’s easiest on Linux with cron. But if you’re in a (para)virtualized LAMP-Stack environment, a pure-PHP solution is probably an easier choice.

  21. The server is running Windows and the Screenconnect app is installed in there. What do a I have to install in there?

  22. Brilliant script, thank you. I was in the middle of writing one in Java, this is a a lot more elegant 🙂

  23. I have a DDWRT router with cron window in the setup area would this just work as a copy paste and run from that environment or what would need be changed to make this work under the DDWRT environment? Figure this device would be the first appliance on the network so the best place to run this from not from a linux box.

  24. I have a DDWRT router with cron window in the setup area would this just work as a copy paste and run from that environment or what would need be changed to make this work under the DDWRT environment? Figure this device would be the first appliance on the network so the best place to run this from not from a linux box. Opps forgot the notify options boxes

  25. It does have the little srawback that godaddy ist meant for dyndns. Modfifying DNS values takes some time (10-20 mins) until everything is propagated to DNS Servers. That means a regular downtime. For your own Server its likely OK though.

  26. Any idea on how to call the dependencies with windows? i’ve been looking for a few hours and have only found linux commands, but i am running my server off a windows 7 system for ease of remote desktop.

  27. Yes, would be awesome to have running on my ddwrt wrt54g router. Any luck to report?

  28. For that, you need to install a recent Python interpreter first. The default install puts it to c:\Python3. Then you have to add this path to your Windows installation’s PATH environment variable. When logged in to the machine, simply open up the start menu (win key) and type ‘env’. Windows search should bring you to the respective dialog. Afterwards you have to mimic what’s in the bash script, i.e. create a virtualenv (comes with python 3.4 these days) and install dependencies into it and activate it. It’s likely easier to convert the bash script into a batch file instead…

  29. The script worked well for a couple of month. Thanks for this great tutorial.
    But now it seems the ip changes are not recognized by godaddy any longer. The servers logfile tells me the IP has been changed, but the a-record-file at godaddy.com keeps has the old ip-adress. Has something changed within the godaddy-api (or web-interface)?

  30. Godaddy changed the web form. However a fix was merged recently into pygodaddy. Please ask the author to do a new release. My script will pick that up and work again

  31. Have you put this up on a git repo? I was thinking of doing it / adding more to it, but I’m not sure what license you want this under.

    Thanks by the way 🙂

  32. First, thanks a lot for the script =)

    Based on it I wrote a version of my own, to avoid spamming godaddy every 5 min, it writes the ip in the conf, and only when public_ip != of the written ip it connects to godaddy and changes the host (and doesnt bother checking if it`s the same ip or not).
    Only if there`s no error while updating the domain it changes the ‘ip’ variable on the config file.

    on the config:

    [godaddy]
    username=xxxx
    password=xxx
    host=sub.domain.com
    ip=just_write_something_here(later the script will change it)

    ———————————————————————————————————

    #!/usr/bin/env python3

    import configparser
    import logging
    import sys

    import pif
    import pygodaddy

    public_ip = pif.get_public_ip()
    logging.basicConfig(filename=’ddns.log’,
    format=’%(asctime)s %(message)s’,
    level=logging.INFO)
    config = configparser.ConfigParser()
    config.read(‘ddns.conf’)

    if config.get(‘godaddy’,’ip’) != public_ip:

    client = pygodaddy.GoDaddyClient()
    is_logged_in = client.login(config.get(‘godaddy’, ‘username’),
    config.get(‘godaddy’, ‘password’))
    if not is_logged_in:
    logging.error(‘Login failed!’)
    sys.exit(1)
    client.update_dns_record(config.get(‘godaddy’, ‘host’), public_ip)
    logging.info(“Domain ‘{0}’ set to ‘{1}'”.format(config.get(‘godaddy’, ‘host’), public_ip))
    config.set(‘godaddy’,’ip’, public_ip)
    with open(‘ddns.conf’, ‘w’) as saveconf:
    config.write(saveconf)

  33. Script does not work for me since last week.
    Seems that something has changed at the login-procedure. So that’s what the logfile says.
    Is there any script adjustment already done?

  34. tried it today but got this in my log file:
    2015-09-19 21:43:03,519 Starting new HTTPS connection (1): dns.godaddy.com
    2015-09-19 21:43:04,547 Starting new HTTPS connection (1): idp.godaddy.com
    2015-09-19 21:43:05,576 Starting new HTTPS connection (1): sso.godaddy.com
    2015-09-19 21:43:06,608 Login routine broken, godaddy may have updated their log in mechanism
    Something on my side or are you also getting this?

  35. So the full error message i get is:

    2015-09-19 21:55:22,764 Starting new HTTPS connection (1): dns.godaddy.com
    2015-09-19 21:55:23,821 Starting new HTTPS connection (1): idp.godaddy.com
    2015-09-19 21:55:24,868 Starting new HTTPS connection (1): sso.godaddy.com
    2015-09-19 21:55:25,845 Login routine broken, godaddy may have updated their login mechanism Traceback (most recent call last):
    File “/root/.venv/lib/python3.4/site-packages/pygodaddy/client.py”, line 101, in login
    viewstate = re.compile(r’id=”__VIEWSTATE” value=”([^”]+)”‘).search(r.text).group(1)
    AttributeError: ‘NoneType’ object has no attribute ‘group’
    2015-09-19 21:55:25,882 Login failed!

    Worth to know, i edited the .py file to have only one of my domains since i have several so now the line looks like this:
    for domain in [‘mydomain.com’]:

    Not sure that’s the correct format and if so it’s whats causing the error.

  36. Thank you soo much for your effort. I don’t have any python programming experience; therefore it caused a lot of trouble for me to install it on my system. My system is an embedded arm-linux board, which run Debian7 wheezy. First problem was, this script needs to run under python3. Because python2.7 in my system fails to find pif . Also, the github repository for the pygodaddy library is rather old, so it fails to login to godaddy. Third, I had to use https://github.com/BryceGough/pygodaddy to avoid login issue. However, in this library, in check.py file at line 108 and 110 have TAB. Therefore it causes runtime error. When you delete TABs and put spaces there, script works perfectly. Thank you soo much for all your helps. May be in future we could do something better. Also, I think somebody must write steps 1) virtualenv .venv 2) source .venv/bin/activate 3) ./godaddy.sh… And also, I forget to mention… You must login to your DNS Zone File editor in your godaddy account, and add one IP manually at first. Otherwise script fails again… I hope other people can use it for this purpose…

  37. There is an (unofficial) update you can apply to client.py in the pygodaddy package to make it work again.

    I manually changed the files (according to the above link), and it all started to work again.

  38. […] GoDaddy DynDNS for the poor | Sascha’s Hideout – Nov 12, 2013  · Transfer the domain to a registrar that offers dynamic DNS service. … check the public IP, go to Godaddy and change the subdomain “POINTS TO” section […]

  39. Just tried Tyler’s version and the default_url dns.godaddy.com can’t be found. Anyone else having this issue with the script?

  40. @Raj, If you can submit a bug report I’ll check it out. I’fe had my script running on a RasperryPi since I wrote that post and it’s still working properly for me.

  41. I have left this script running successfully in a cron job for some months now. I checked in on it today and it has been issuing the following error for the last few months now.
    Traceback (most recent call last):
    File “godaddy-dyndns.py”, line 19, in
    config.get(‘godaddy’, ‘password’))
    File “/usr/local/lib/python3.4/dist-packages/pygodaddy/client.py”, line 99, in login
    r = self.session.get(self.default_url)
    File “/usr/local/lib/python3.4/dist-packages/requests/sessions.py”, line 487, in get
    return self.request(‘GET’, url, **kwargs)
    File “/usr/local/lib/python3.4/dist-packages/requests/sessions.py”, line 475, in request
    resp = self.send(prep, **send_kwargs)
    File “/usr/local/lib/python3.4/dist-packages/requests/sessions.py”, line 585, in send
    r = adapter.send(request, **kwargs)
    File “/usr/local/lib/python3.4/dist-packages/requests/adapters.py”, line 477, in send
    raise SSLError(e, request=request)
    requests.exceptions.SSLError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:600)
    After researching this issue I have seen that you should add verify=False to the call if you choose not to use a ssl cert. This is not a production service and I don’t care if it’s less secure than it could be but I cannot seem to find where to put the setting and after attempting to reinstall godaddy-dyndns.py from scratch it still issues the same warning. I have updated the script (clean) and updated python just in case. Any help troubleshooting this issue would be greatly appreciated.

  42. The cname option is the best, specially because yourdomain.com is NOT wasted. You just create a subdomain redirect in godaddy’s dns to redirect yourdomain.com to http://www.yourdomain.com. This way yourdomain.com isn’t dead. If someone types it in, it redirects to http://www.yourdomain.com in a very satisfying and professionally appearing manner.
    If you need to forward ports in your home router, and want to access them via your domain name, just use one of the hosts you have set up with a cname that points to your ddns service (noip.com for instance), and your good.
    I even have a mail server set up using this method, complete with autodiscover record, mx records, SSL certs, and an spf record pointing to a cname host that I have pointing to noip.com’s ddns service which I have updating in my router.
    And it’s all done in dns. No script to break when godaddy changes their website.
    By far the best option.
    – Pete

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.