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:
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
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
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 🙂
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.
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”].
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)
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.
any chance of the full listings?
please, please, please
The listings are complete.
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 ..
Well, that’s it. Python code is short 🙂
ok .. sorry .. thought there would be an end to the for loop .. and if statement ..
many thanks ..
will experiment ..
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!
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? 😦
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 🙂
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 🙂
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
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.
Python script worked without a hitch. Cheers
you are a god!! issue was driving me nuts, this worked like a fkin charm!!
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 ————-
I think at this point it would make sense to load the user/pass Combo and other data Form a separate config file.
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…
Having opted to no longer use a hosting service, this was exactly the starter I needed to get going managing my GoDaddy domains. Thanks very much.
I created a little lib to among other things log DNS updating status to syslog to make more suitable for cron.
https://github.com/ccheetham/pyfooware/blob/master/ddns.py
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!
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.
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.
The server is running Windows and the Screenconnect app is installed in there. What do a I have to install in there?
Brilliant script, thank you. I was in the middle of writing one in Java, this is a a lot more elegant 🙂
How about running from DDWRT?
What would that change?
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.
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
I use an unmodified FritzBox Router, thus it’s deployed on a Server behind.
anybody tried to do it for Mikrotik router?
The idea of “rolling your own” for dynamic DNS is so tempting; I think I’m going to give it a try. Thanks for the idea!
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.
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.
Yes, would be awesome to have running on my ddwrt wrt54g router. Any luck to report?
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…
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)?
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
I have the same problem as chris
it seems to work for me after replacing the client.py with the actualized one you could find here
https://github.com/observerss/pygodaddy/blob/master/pygodaddy/client.py
You could also modify godaddy.sh to download pygodaddy directly from its git repo
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 🙂
Oh, I can do that. Its just that proper config file loading for user/pass would be nessecary 🙂 Will do tomorrow
There you go: https://github.com/saschpe/godaddy-dyndns
Currently depends on my pygodaddy fork for Python3 support. Feel free to enhance the README. I guess I’m gonna do a PyPI release later on…
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)
Hi, I uploaded the script on Github a while ago and did some improvements. Feel free to check it out and send your improvements as a pull request: https://github.com/saschpe/godaddy-dyndns TIA!
how would I add this to a router for use?
Well it depends but you obviously need shell access, likely via ssh
clever, works great. Any idea how to set the forwarding, rather than the ip address?
Is it just me or has godaddy changed their log-in so this no longer works?
*Update* There is an (unofficial) update you can apply to client.py in the pygodaddy package to make it work again.
https://github.com/BryceGough/pygodaddy
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?
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?
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.
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…
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.
thankss
[…] 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 […]
I’ve created an (extremely) updated version of this script. It should work out of the box on any *nix. Please check it out, star it. clone it, hack it. all that stuffs!
http://dyndns.kindling.me
Nice! However, I switched to namecheap.com and got rid of that little script 🙂
Just tried Tyler’s version and the default_url dns.godaddy.com can’t be found. Anyone else having this issue with the script?
I have to say that I am getting increasingly frustrated with GoDaddy. There seems to be no way to update the A record any more. I figured out a free solution using nameceap as well:
http://kiwiweb.org/2016/05/28/ddns-with-godaddy-and-freedns/
hope this helps.
@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.
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.
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
+1 for cname option. I use the same setup with duiadns.net.