Homelab: CloudFlare Dynamic DNS Update Script (cf-ddns.sh)

As a part of my Homelab project, I’ve created a proper bash script to provide dynamic DNS updates for external resources, via CloudFlare. More details on the reasoning behind it can be found in Using CloudFlare for Dynamic DNS, but since that was posted I’ve fleshed the script out quite a bit more.

The new and updated script can be found on GitHub: cf-ddns.sh. It now writes events to syslog when it runs, so you can use VMware Log Insight (or another log solution) to capture the events, and use it to track public IP changes if you want. I’ve also added a -f parameter to it, so you can force an IP update even if the values have not changed since the last run.

It’s pretty self explanatory, just replace your own values from CloudFlare for the variables, and if you want to update more than one record, just copy the update block and edit it for the extra entries.

Hopefully someone will find this useful.

Homelab: Using CloudFlare for Dynamic DNS

In my previous post, I tried to lay out the foundation and reasoning behind requiring a Dynamic DNS Service, and here is how I solved it using CloudFlare.

First of all, I moved my chosen domain name to CloudFlare, and made sure everything resolved ok with static records. Once that was working, I started playing around with the CloudFlare API, using Cocoa Rest Client. I’m no developer (as is probably very apparent my the script below), nor API wizard of any kind, but it was fairly easy figuring out how to craft a request that lists my DNS zone.

By using the List DNS Records query, I found the unique ID for the hostnames I wanted to update, and created a new Update DNS record query to update it with a new IP address. Since the Cocoa Rest Client is pretty clever, it has an option to “Copy Curl Command”, that basically gives you a preformatted  curl command to run the query you just crafted in it. Pasting that into a Terminal window on my Mac, verified that it worked as intended. From there on, I simply wrapped these commands in a little bash script, to avoid hitting the API unless there was an actual public IP change.

In the end, my script ended up looking like this.

UPDATE:
I’ve published a more fleshed out script on GitHub, details here.
NOTE: You will need to fill out your own values for {TOKEN}, {EMAIL}, {DOMAIN}, {ID} and {HOSTNAME} in line 18 and 21 for this to work for you. 

cloudflare-ddns.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
#!/bin/sh

#get public ip

MYIP=$(curl ifconfig.me/ip)
OLDIP=<code>cat oldip.txt</code>

echo "Current public IP is:" $MYIP

if [ "$MYIP" = "$OLDIP" ]
then
echo "No change detected. Exiting"
else

echo "IP change detected, updating CloudFlare"

#WEB01
curl -k -L -X POST -H 'Content-Type: application/x-www-form-urlencoded' -d 'a=rec_edit&tkn={TOKEN}&email={EMAIL}&z={DOMAIN}&id={ID}&type=A&name={HOSTNAME}&ttl=1&content='$MYIP 'https://www.cloudflare.com/api_json.html'

#WEB02
curl -k -L -X POST -H 'Content-Type: application/x-www-form-urlencoded' -d 'a=rec_edit&tkn={TOKEN}&email={EMAIL}&z={DOMAIN}&id={ID}&type=A&name={HOSTNAME}&ttl=1&content='$MYIP 'https://www.cloudflare.com/api_json.html'

echo $MYIP > oldip.txt
fi
Explanation:

First off, the script checks what the current public IP is (line 5), then goes on to compare that with the stored IP address in the oldip.txt file (line 10).

If it matches, it ends execution as there is no need to update the public records. If there is a mismatch between the two, it goes on to execute the request to CloudFlare, replacing the currently configured IP with the new IP address stored in the $MYIP variable (lines 17-21).

It then writes the new IP address to the oldip.txt file (line 23) and exits.

Configure this as a cronjob the runs every 5 – 10 minutes or so and you’re set! Simple, not pretty, but oh-so awesome!

Homelab: Dynamic DNS Requirements

While working on my new Homelab setup, I’ve been investigating ways to provide hostname based access to several web services located in my DMZ zone. Since my provider doesn’t provide static IP addresses, I also need an external Dynamic DNS service, to provide said hostname mappings through the reverse proxy on the inside.

There are loads of Dynamic DNS services available, most of them lets you use some sort of predefined domain name scheme, and point it to your external IP, but I wanted to use a domain name that I own and control. Since I use CloudFlare to provide DNS services (amongst other things) for this very site, it was a natural choice to see if they could fit the bill for my lab needs as well. Turns out, not only can they provide the services I need for free, they also allow me to play around and have fun at the same time!

My setup looks like this:
Logical Web Services Access Diagram
Logical Web Services Access Diagram

As seen in the diagram, the setup is pretty simple. As far as Dynamic DNS requirements go, all I need to be able to do (for now) is to update the IP address for a couple of A records for my domain, if my external IP changes.  This in turn makes the reverse proxy work, since it redirects traffic based on hostname when there is an incoming request.

CloudFlare offers several methods to update the records, including ddclient, but that requires Perl, and frankly that’s no fun at all. What it fun however, is to update A records directly through the CloudFlare API, so that’s the route I headed down.

I moved the domain name I want to use for external access to my lab, to CloudFlare and rolled my own small Dynamic DNS Updater all within an hour or so of actual work.

Not bad at all, especially considering I didn’t even know they provided the possibility to do so, or that they provide a public API you can play with.

In the next post in this series, I’ll show how I solved it with some simple API calls and some bash scripting.