Free DDNS using ddclient and Cloudflare

I was on the hunt for a suitable Dynamic DNS solution. There’s a whole bunch of paid and free services that can do this. Although… I’m not too keen on paying or having a free account to some random service. That’d mean making yet another account and then probably updating it every month to keep it active. Instead I can bleed time into setting up and maintaining my own stuff!

I use Cloudflare to manage my DNS (and get a whole bunch of fun perks as a result) which means I can leverage their API to automagically update my DNS for me. Kinda.

Enter ddclient. I stumbled upon this super helpful post written by Jens Segers. As it turns out, there’s this purpose built utility to update Cloudflare DNS entries with dynamic IP addresses, and this purpose built blog post to tell me how to mash everything together and it will work seamlessly.

Just kidding, could you imagine?

At the time of writing:

  • Cloudflare uses v4 of their API.
  • ddclient updated from Cloudflare’s API v1 to v4 from version 3.8.3.
  • The Ubuntu repository will install ddclient version 3.8.3.
  • The latest ddclient version is 3.9.0.

Here’s how I got DDNS working on Ubuntu 18.04.1 LTS with Cloudflare and ddclient running as a daemon.

Install ddclient

Make sure our repository is up to date.

1
sudo apt update

Download and install ddclient, and all the other pieces we need.

1
sudo apt install ddclient libdata-validate-ip-perl

While ddclient is getting installed, you’ll get asked a whole host of questions. We mostly don’t care as we’re going to change everything anyway. The point is, installing it this way puts most of the stuff where it needs to be.

  • Dynamic DNS service provider: select “other”.
  • Dynamic DNS server: leave blank.
  • Dynamic DNS update protocol: select “dyndns2” (it just happens to be the first entry).
  • Username for dynamic DNS service: leave blank.
  • Password for dynamic DNS service: leave blank.
  • Re-enter password to verify: leave blank.
  • Network interface used for dynamic DNS service: leave blank.
  • DynDNS fully qualified domain names: leave blank.

Curiously, there’s some specific options I didn’t get asked until I reconfigured the package. It’ll ask you the same questions as above so just provide the same answers, but the additional questions are what we need to pay attention to.

1
sudo dpkg-reconfigure ddclient
  • Run ddclient on PPP connect?: select “No” (the default is “Yes”).
  • Run ddclient as a daemon: select “Yes” (the default is “No”).
  • Interval between ddclient runs: leave as “300” (if you want a 5 minute interval).

Just so you know why we’re installing libdata-validate-ip-perl as well as ddclient, it prevents you from doing something like:

1
sudo ddclient -help

Then witnessing everything immediately detonate inside your shell:

Can't locate Data/Validate/IP.pm in @INC (you may need to install the Data::Validate::IP module) (@INC contains: /etc/perl /usr/local/lib/x86_64-linux-gnu/perl/5.26.1 /usr/local/share/perl/5.26.1 /usr/lib/x86_64-linux-gnu/perl5/5.26 /usr/share/perl5 /usr/lib/x86_64-linux-gnu/perl/5.26 /usr/share/perl/5.26 /usr/local/lib/site_perl /usr/lib/x86_64-linux-gnu/perl-base) at /usr/sbin/ddclient line 27.
BEGIN failed--compilation aborted at /usr/sbin/ddclient line 27.

Update ddclient

Since the Ubuntu repository will install ddclient version 3.8.3 (released 2015-05-30), and the latest version is 3.9.0 (released 2018-08-09), we should probably update it. Strictly speaking, 3.8.3 will work with Cloudflare. However I’ve done this based on 3.9.0, and it’s nice to have the latest software.

The below steps mostly come from the purpose built blog post linked earlier: Dynamic DNS for CloudFlare with ddclient.

Since the latest version isn’t in our standard repositories, we’ll need to download and extract it.

1
2
wget https://sourceforge.net/projects/ddclient/files/ddclient/ddclient-3.9.0/ddclient-3.9.0.tar.gz
tar -xvf ddclient-3.9.0.tar.gz

Then we overwrite the existing Perl script with the new one.

1
sudo cp -f ddclient-3.9.0/ddclient /usr/sbin/ddclient

The ddclient.config file location has changed in 3.9.0, so we need to resolve that issue.

1
2
sudo mkdir /etc/ddclient
sudo mv /etc/ddclient.conf /etc/ddclient

It’s always a good idea to tidy up and remove things we don’t need or that are toxic to us in life.

1
2
rm ddclient-3.9.0.tar.gz
rm -R ddclient-3.9.0

Configure ddclient

Since we blazed through our setup phase, our configuration file is mostly empty and completely useless. We can take a peek at the wasteland cat /etc/ddclient/ddclient.conf:

# Configuration file for ddclient generated by debconf
#
# /etc/ddclient.conf

protocol=dyndns2

server=
login=
password=''

Now we need to actually get ddclient to talk to Cloudflare. We have to edit ddclient.conf and put in some useful information. This is where we will deviate as your details are going to be different to mine. If you want more information around what the variables are, there’s a good example file in the 3.9.0 download called sample-etc_ddclient.conf. Additionally, the ddclient usage wiki has some good information around the ddclient options. Between the example configuration file and the ddclient usage wiki, you can find out what all the options actually are in the below ddclient configuration.

You’ll want to update the values on each line that have ## Update Me at the end. The commented out parts naturally don’t actually change anything, but it’s just to keep structure. Design your configuration file such that it brings you joy.

In the below configuration example, we’ve signed up to Cloudflare using the email address “[email protected]”. We’ve then copied our Cloudflare Global API Key, which happens to be “abcredactedxyz”. Somehow, we own the domain “domain.tld” and we are updating the “sub.domain.tld” A Record with our dynamic IP address.

My redacted working ddclient.conf looks like cat /etc/ddclient/ddclient.conf:

# Configuration file for ddclient

##
## Global Config
##
daemon=300
ssl=yes

##
## sub.domain.tld - Cloudflare ## Update Me
##
protocol=cloudflare
use=web
[email protected] ## Update Me
password=abcredactedxyz ## Update Me
zone=domain.tld ## Update Me
sub.domain.tld ## Update Me

Testing

#1 - Public IP

Our first test is to see if ddclient is actually able to get our public IP address. First google what your IP is, then run:

1
sudo ddclient -query

You’ll see your local IP address, your loopback address, and then your public IP address (in this case it’s shown as “1.1.1.1”) from a few different services. You might have some warnings from certain sites not resolving, that’s fine.

use=if, if=ens160 address is 192.168.1.1
use=if, if=lo address is 127.0.0.1
WARNING:  cannot connect to ipdetect.dnspark.com:80 socket: IO::Socket::INET: Bad hostname 'ipdetect.dnspark.com'
WARNING:  found neither ipv4 nor ipv6 address
use=web, web=dnspark address is NOT FOUND
use=web, web=dyndns address is 1.1.1.1
use=web, web=loopia address is 1.1.1.1

#2 - Connection to Cloudflare

Our second test is to make sure we can successfully take our public IP and update our Cloudflare A record with it. A quick test which will use our configuration file and attempt to update our IP is basically just running ddclient now and asking for some verbosity. Fair warning, this will literally update your DNS records if it works, so, you know.

1
sudo ddclient -daemon=0 -verbose -noquiet

We should get something nice and easy to read like:

CONNECT:  checkip.dyndns.org
CONNECTED:  using HTTP
SENDING:  GET / HTTP/1.0
SENDING:   Host: checkip.dyndns.org
SENDING:   User-Agent: ddclient/3.9.0
SENDING:   Connection: close
SENDING:
SENDING:
RECEIVE:  HTTP/1.1 200 OK
RECEIVE:  Content-Type: text/html
RECEIVE:  Server: DynDNS-CheckIP/1.0.1
RECEIVE:  Connection: close
RECEIVE:  Cache-Control: no-cache
RECEIVE:  Pragma: no-cache
RECEIVE:  Content-Length: 107
RECEIVE:
RECEIVE:  <html><head><title>Current IP Check</title></head><body>Current IP Address: 1.1.1.1</body></html>
SUCCESS:  sub.domain.tld: skipped: IP address was already set to 1.1.1.1.

The last line there tells us everything we need to know: SUCCESS: sub.domain.tld: skipped: IP address was already set to 1.1.1.1. You might have another message like a failure, or a success in actually updating the IP. As long as it makes the good words.

If you do have problems, you can get a lot more information by running:

1
sudo ddclient -daemon=0 -debug -verbose -noquiet

#3 - Running Daemon

Our third test is to make sure that the ddclient daemon is running and actually checking for a changed IP every five minutes. If we run htop then we should see one process running, and it’ll probably be sleeping. The maximum amount of time it should sleep is 300 seconds, as that’ll be 5 minutes (or whatever threshold you set). You might also see it updating. It also doesn’t hurt to restart the guest to make sure the daemon resumes after a reboot.

PID		USER	...		CPU	MEM	TIME	Command
1622	root	...		0.0	1.9	0:10.69	ddclient - sleeping for 80 seconds

Bugs and Errors

PID City

I noticed a lot of PIDs running while inspecting in htop which was super odd. I’m not sure what I did that caused this behavior, but this is a known bug that has already been resolved in the Debian Bug #652298, as well as the related and merged Debian Bug #761505. I killed all the process with killall -r ddclient, however I couldn’t intentionally reproduce the issue.

PID		USER	...		CPU	MEM	TIME	Command
15563	root	...		0.0	4.5	0:00.31	ddclient - sleeping for 300 seconds
15575	root	...		0.0	4.5	0:00.30	ddclient - sleeping for 150 seconds
15607	root	...		0.0	4.5	0:00.31	ddclient - sleeping for 230 seconds
15671	root	...		0.0	3.0	0:00.14	ddclient - sleeping for 280 seconds
15742	root	...		0.0	4.5	0:00.29	ddclient - sleeping for 160 seconds
15745	root	...		0.0	5.1	0:00.43	ddclient - sleeping for 190 seconds
15750	root	...		0.0	3.0	0:00.11	ddclient - sleeping for 230 seconds
16345	root	...		0.0	2.9	0:00.03	ddclient - sleeping for 200 seconds

Literally Nothing

Swank, now you can run ddclient but… it just runs and then doesn’t actually do anything. That’s likely because it’s actually hitting a 301 and not following the redirect. It’s also likely that is happening because you’re using server=www.cloudflare.com. That server location is the problem as per this link Cloudflare Community - CF Returning 301. You can specify server=api.cloudflare.com/client/v4 instead, however you can just remove the server= variable.

Other Crimes

Good luck, here’s some other crimes you can solve: mcblum Github - Can’t locate Data/Validate/IP.pm Error.

Also a quick hint, if it’s not running as a daemon, the file /etc/default/ddclient will probably need to be adjusted and you might need to make a Unit File. Check out running ddclient as a service.