You get a bonus - 1 coin for daily activity. Now you have 1 coin

Your Own DDNS (Dynamic DNS) Server and Client Based on Debian

Practice



What DDNS is - you can read about it on Google. However, if you came here to read this note - you probably need it. There are plenty of examples - it could be simply the lack of a static IP address at one of an organization's branches (for example, when one of the nodes works over ADSL), or just home equipment that also doesn't have a static IP.

To set up DDNS, external services are usually used - because it's generally simpler. For example, when using DynDNS, you don't need to set up your own domain.

But let's imagine that the organization already has a domain and there's a need for DDNS. But you don't want to use someone else's services for this - they're either paid, or not guaranteed at all (as in the case of DynDNS), or simply don't have a client for the OS you need. Either way, our goal is to set up a DDNS server and DDNS client based entirely on what's built into Linux Debian, without installing any third-party software and using only our own resources.

This note is oriented toward the Linux Debian OS, however with minimal changes the same is true for other OSes, such as CentOS/RedHat


PARAMETERS

In this example, the following parameters will be used - this is just an example:
  • Master DNS server address: ns1.example.com
  • Address of the DDNS zone that will be updated: dynamic.example.com
  • Address of the zone itself: example.com
  • Interface on the client with WAN access: eth0
  • TTL of the dynamic zone: 120 (2 minutes)



CLIENT

Oddly enough, let's start with the client after all.

1) Install the necessary packages (they don't come out of the box).

$ sudo apt-get install bind9utils

We need this action in order to get a little utility called nsupdate.


2) Generate a TSIG key.

This key will allow modifying the necessary DNS zone on the DNS server when the client's IP address is not known in advance.

$ sudo dnssec-keygen -b 512 -a HMAC-MD5 -v 2 -n HOST example.com
here, instead of example.com enter the name of the key (it's preferable that it matches the zone name). Moreover, this name will be needed later.

This procedure will create two files, named something like this:
Kexample.com.+157+49437.key
Kexample.com.+157+49437.private

These files are located wherever you currently are (pwd). Their location doesn't matter though - you can even store them in your home directory.


3) Create a script for auto-updating the address

For example, let's call it ddnsupdate and put it in /usr/local/bin:
#!/bin/sh

IFACE="eth0"
TTL=120
SERVER=ns1.example.com
HOSTNAME=dynamic.example.com
ZONE=example.com
KEYFILE=/path/to/tsig/Kexample.com.+157+49437.private

new_ip_address=`ifconfig $IFACE | grep "inet addr:" | awk '{print $2}' | awk -F ":" '{print $2}'`

nsupdate -v -k $KEYFILE << EOF
server $SERVER
zone $ZONE
update delete $HOSTNAME A
update add $HOSTNAME $TTL A $new_ip_address
send
EOF

Here:
  • IFACE="eth0" : This is the name of the network card from which to read the current IP address (for example, for ADSL this would most likely be ppp0);
  • TTL=120 : This is the lifetime of this zone in the cache of other DNS servers and end-user computers. Don't set it too high - otherwise you'll have to wait a long time before the new IP address becomes available after the change;
  • SERVER=ns1.example.com : This is the FQDN address of your DNS server, which will also act as the DDNS server;
  • HOSTNAME=dynamic.example.com : This is the name of the zone whose IP address (A record) will be updated via DDNS;
  • ZONE=example.com : This is the name of the parent zone (i.e., if dynamic.example.com is part of the example.com zone, then here we write example.com);
  • KEYFILE=... : This is the path to the key file created in step 2.

4) Make this file executable:
$ chmod +x /usr/local/bin/ddnsupdate


5) Open the file Kexample.com.+157+49437.private (or whatever yours is called):
Private-key-format: v1.3
Algorithm: 157 (HMAC_MD5)
Key: vHBX3cjxtS8lM37KZwfnpXFldl9QB/8vs67Rw/xCH+yGXJ9gmj5BVHY87NQMD/vmjHZc8oz38PgINGAYRMrdAA==
Bits: AAA=
Created: 20120216073642
Publish: 20120216073642
Activate: 20120216073642

See the line "Key:......."? We need to copy to the clipboard everything that comes after "Key:" (skipping the space, of course). This is the key that will be needed to configure the server.



SERVER

Now let's move on to configuring the server. It is assumed that the BIND DNS server is already installed and running. Just in case - here's an article on installing it on Debian: link.

So, you have a regular static DNS zone. For example, it looks like this:
$ORIGIN .
$TTL 3600 ; 1 hour
example.com IN SOA ns1.example.com. root.example.com. (
2012021602 ; serial
28800 ; refresh (8 hours)
7200 ; retry (2 hours)
604800 ; expire (1 week)
86400 ; minimum (1 day)
)
NS ns1.example.com.
NS ns2.example.com.
A 111.222.111.222
MX 10 mail.example.com.
$ORIGIN example.com.
mail A 111.222.111.225
www CNAME example.com.

Actually, there's nothing to do in the zone description file - it stays as is.


1) Create (if it doesn't exist) or add to (if it exists) the keys.conf file. Place this file in the directory with the rest of the bind configs (for the non-chroot version of BIND on Debian, this is /etc/bind).

The file will look like this:
key example.com {
algorithm hmac-md5.sig-alg.reg.int;
secret vHBX3cjxtS8lM37KZwfnpXFldl9QB/8vs67Rw/xCH+yGXJ9gmj5BVHY87NQMD/vmjHZc8oz38PgINGAYRMrdAA==;
};

Notice the "secret" line? This is exactly where we put the key copied from the client - the whole string.

And did you also notice the key name "example.com"? It must be exactly the same as the name we specified as the "HOST" parameter in step 2


2) Modify the configuration of the example.com DNS zone (of course, instead of example.com - your zone's name).

For example, originally it looks like this:
zone "example.com" {
type master;
file "/etc/bind/master/example.com";
};

Now let's add the "allow-update" option specifying the key, after which the zone config will look approximately like this:
zone "example.com" {
type master;
file "/etc/bind/master/example.com";
allow-update {
key example.com;
};
};


3) Add a directive to the named.conf file to load keys from keys.conf:

...
include "/etc/bind/keys.conf";


4) Make sure that the bind process can modify the zone file and write files next to it. The thing is, the DNS server will create a journal file next to it, in which it will log changes made via DDNS, and will also periodically modify the zone file itself, applying changes according to the data received from the client.

To do this, make the bind user in the bind group the owner of the master and dynamic directories:
$ sudo chown -R bind:bind /etc/bind/master
$ sudo chown -R bind:bind /etc/bind/dynamic

Without this, if the server can't modify files in the directory where the zone is located, it will simply return SERVFAIL in response to ddnsupdate.


5) Reload the DNS server config:
$ sudo rndc reload


That's it, the server setup is complete.


BACK ON THE CLIENT AGAIN

Let's go back to the client again. Run the ddnsupdate script and watch to make sure everything goes smoothly.

If it's not smooth:
  • If you get "NOTZONE": check that you correctly specified the ZONE and HOSTNAME parameters in ddnsupdate. For example, the HOSTNAME parameter should include everything that's written in ZONE (e.g., ZONE=example.com, HOSTNAME=dynamic.example.com).
  • If you get "NOTAUTH(BAD_KEY)": check that you copied the key correctly from the client to the server and that the key name exactly matches on both the client and the server. The point is you need to do some finagling around the key. And by the way, you shouldn't copy the key from the file with the .key extension - in fact the entries in it and in .private can easily differ - as happened to me.
  • If you get "SERVFAIL": check that the bind daemon has write permissions everywhere possible in the server's config directory (in our case: /etc/bind).


If everything's smooth - then feel free to add running the ddnsupdate script on a schedule by editing /etc/crontab.


PS. If a ddnsupdate error appears - add the -d or -D flag to the nsupdate call - debug information (-d) or a bunch of debug information (-D) will be dumped to the console.

Relevant for: Debian 5, Debian 6; likely ubuntu/kubuntu

Comments

To leave a comment

If you have any suggestion, idea, thanks or comment, feel free to write. We really value feedback and are glad to hear your opinion.
To reply

Lectures and tutorial on "Running server side scripts using PHP as an example (LAMP)"

Terms: Running server side scripts using PHP as an example (LAMP)