Managing a Domain Using Dynamic DNS

This page outlines how to fully manage your own domain and web server at home when you do not have a static IP address. This is not an in-depth tutorial on DNS, Apache or Linux and assumes a basic to intermediate understanding of these technologies.

Also please note that some of the techniques described in this tutorial are not ‘correct’ in terms of proper DNS management (in fact, they’re downright hacky!) so this approach is only suitable for hobbyist messing about or for testing purposes—I strongly suggest that you do not run any sort of commercial or business website in this fashion!

The advantages to setting this system up are that you will have your own web server which you have full control over—no quotas, no putting up with slow SSH, unlimited sub-domains and so forth. This is an invaluable asset for someone interested in web design or other types of development.

Pre-requisites

For this tutorial you will require:

  • A domain name that you have purchased and have full control over
  • A permanent high speed Internet connection such as DSL
  • A UNIX based machine such as a Linux box or a Mac to act as a DNS server and DDNS client (there’s no reason why this principal won’t work on a Windows server but you’ll have to write your own script!)
  • Any machine to act as a web server (can be the same box as the DNS server)
  • A weak lemon drink

Note that the domain is the only cost involved in this project (around £3/year for a .co.uk) as you are already paying for your Internet connection and OS.

Purchasing a Domain

The first step is to purchase a domain. It does not matter where the domain is purchased from or what the TLD is as long as you have a proper account at a domain registrar which will allow you to modify all of the settings for your domain, such as name servers and MX records. So this does not include any free domain that your ISP may have given you such as www.username.yourisp.co.uk.

I generally buy all my domains from 123-reg and have never had any problems with them; you may use them or anybody else that you choose. For the purposes of this experiment I will use the fake domain ian.co.uk. Anywhere that you see ian.co.uk you should replace this with your own domain.

I have tested this setup with a real domain but will not use that domain here to avoid generating unnecessary interest in my home computers! All command output and configuration files are real just with the real domain substituted for the pretend one.

Proper Hosting

So that we can understand the mechanism that we are using let’s first consider how this would work if it were done ‘properly’.

In real world hosting (rather than DIY hosting as we are going to attempt) dynamic DNS is not an issue. Proper hosting companies have servers with static IP addresses, so in order to host a new website they can simply add a record into their DNS configuration and then pretty much forget about it.

For example, let’s say that I decided to host ian.co.uk with a commercial company. I have chosen a hosting company at www.hostcorp.co.uk (don’t go, I made it up…).

When I set up the account for the hosting they will most likely have some instructions along the lines of “set the primary and secondary name servers to ns1.hostcorp.co.uk and ns2.hostcorp.co.uk”.

In order to do this I would log into my 123-reg control panel and set the name servers as indicated, these name servers will then be submitted to whichever authority governs the domain.

In this case, ian.co.uk is a .co.uk address and is therefore governed by Nominet. So, upon receiving the request Nominet will add data into their DNS servers delegating control for ian.co.uk to ns1.hostcorp.co.uk and ns2.hostcorp.co.uk.

HostCorp will then put an A record into the DNS servers ns1.hostcorp.co.uk and ns2.hostcorp.co.uk for www.ian.co.uk, giving it the static IP address of the web server that the site will live on (1.2.3.4 for the sake of argument).

The web server will then have a virtual host added to it for www.ian.co.uk, so it knows which files to serve when it receives a request.

So, when I enter www.ian.co.uk into my browser, the computer will send off a DNS request for that address (i.e. “what IP address does www.ian.co.uk have”). Ignoring caching, the request will go to the DNS server at the ISP, which will then query the .uk DNS server, which will delegate to the .co.uk server, the .co.uk server will then delegate to ns1.hostcorp.co.uk and that will return the address 1.2.3.4 to the browser.

The browser then sends the request for www.ian.co.uk to 1.2.3.4, the server finds that it has a virtual host entry for the address and serves up the files. Phew!

Crucially the address 1.2.3.4 will change infrequently, if ever. If we had a static address at home then we could solve parts of this hosting at home problem much more simply, but most people don’t.

Some ISPs offer business orientated connections that allow you to pay an extra premium every month for one or more static IP addresses, but this it not what the average person has at home.

Because there is a shortage (subjectively) of IPv4 addresses for the planet, most IPSs do not own enough IP addresses in order to have every customer connected at once. Therefore rather than assigning each customer their own static IP address, IPs are assigned using DHCP.

In other words, each time your Internet connection goes down and comes back up again you get a new IP address.

Piggy-backing Onto DDNS

When you specify the name servers for your new domain, you have to specify two or more unique URLs. This creates a chicken and egg situation if you wish to do your own hosting, since you cannot enter, for example, ns1.ian.co.uk and ns2.ian.co.uk. If you did enter name servers inside the domain in this way you would be asked for an IP address, which you cannot specify since it isn’t static.

For this reason, we will piggy back our DNS setup onto an account from a commercial DDNS (Dynamic DNS) company, in this case no-ip.com.

What these companies do is offer a service to people with dynamic IP addresses so that they can have a domain of their own. The service works via you running a client on your computer which tells the DDNS company every time your IP changes.

The DDNS company then updates their DNS records with your new IP address. The companies set a very short TTL on the records so that they are not cached in other name servers for more than a minute or so.

You may be wondering what the problem is with just using this service? Well, there isn’t a problem apart from the fact that you have to have a domain name specified by the DDNS company and you are also likely to have to pay for a more complex service if you wish to have sub-domains and so forth. However, if you are happy to have a single site at username.no-ip.com for example then you need not go to all this effort!

You should now go to no-ip.com and set up a new account using the free service. Choose one of the domains that they offer (it doesn’t matter which one) and register two URLs to that domain.

For this example let us imagine that we have registered ns1.servebeer.com and ns2.servebeer.com. Wherever you see these URLs used you should substitute them for your own two URLs that you have chosen.

Setting up the Delegation

Once you have chosen your two DDNS controlled URLs you can set them as the name servers for your domain.

Remember how I said that some of the techniques here were hacky? Well this is the worst part of it! In the real world, primary and secondary name servers should be separate servers in different locations and on different networks, for resiliency. They should not be one computer masquerading as two computers, in your house, on your DSL!

Still, as I said this is for the pleasure of hacking the config together, not a business grade solution!

So the next thing to do is log into whichever domain re-seller you purchased the domain from and specify the name servers. All of these companies should have some kind of control panel or web login type of feature where these things are set up. Find the section for the ‘name servers’ or ‘DNS servers’ and enter the two domains that you have chosen in the previous step.

Do not be confused if there is also an option to configure DNS, that will be for configuring the DNS at the re-seller. What we want to do is to change the DNS servers altogether, so the only options you should see are two to four boxes for specifying servers (and probably a lot of warnings!). If you can see options for A, CNAME and MX records then you’re probably in the wrong section.

This configuration change will be submitted to the relevant authority for the domain and may take a couple of days to process; however in reality it often happens within a few hours.

You can check that the name servers have been updated by using the dig command to look up the current name servers for the domain, as follows:

yoda:~ ian$ dig -tns ian.co.uk

; <<>> DiG 9.3.2 <<>> -tns ian.co.uk
;; global options:  printcmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 7791
;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 2

;; QUESTION SECTION:
;ian.co.uk.                 IN      NS

;; ANSWER SECTION:
ian.co.uk.          0       IN      NS      ns1.servebeer.com.
ian.co.uk.          0       IN      NS      ns2.servebeer.com.

;; ADDITIONAL SECTION:
ns1.servebeer.com.     60      IN      A       86.129.37.240
ns2.servebeer.com.     60      IN      A       86.129.37.240

;; Query time: 235 msec
;; SERVER: 192.168.0.1#53(192.168.0.1)
;; WHEN: Fri Jun 29 16:30:44 2007
;; MSG SIZE  rcvd: 112

When you see the NS records in the ANSWER SECTION change from the default ones (these will be the ones belonging to whoever you bought the domain off, so in the case of 123-reg who are owned by Host Europe these were ns.hosteurope.com and ns2.hosteurope.com) to the ones that you specified when you logged in to the control panel, the requested change has occurred.

You can see here that the name servers are ns1.servebeer.com and ns2.servebeer.com which are the ones that we created at noip and specified at 123-reg. Looking good so far!

Note that the numeric value in the line (here 60) is the TTL in seconds, so if you send a request via dig and the number says 600 then the returned value is not likely to change for another 10 minutes, assuming that it is cached.

What this means is that the values for the name servers may have been changed by Nominet (or whoever) but you will not see this change yourself until the TTL runs down to 0 in your ISP’s cache.

Setting up BIND

We now have a domain setup up and DNS requests for that domain will shortly be pointing to our IP address, however we can’t resolve anything yet as we aren’t running a DNS server!

Assuming you are not directly connected to the Internet, you need to set your router up to forward DNS requests to your Linux machine or Mac (ports are tcp.53 and udp.53) and then install BIND on that machine.

Installing BIND is beyond the scope of this tutorial; if you don’t have it already there are loads of tutorials on-line about how to do it. Note that if you have a Mac running OSX then BIND is installed but not activated; again their are tutorials around for activating it. You should set up rndc to go with your BIND installation to make it easy to reload the zone later on when your IP changes.

Once your BIND is up and running you can add in a new zone for your chosen URL. You should first add the relevant entry into the main configuration file:

zone "ian.co.uk" {
        type master;
        file "/Users/ian/dns/db.ian";
};

Substitute your own URL and a path to wherever you want to keep the configuration file.

Finally you need to set up the configuration file for the zone, in my case this is the file db.ian:

$TTL 60S
@       IN      SOA     ns1.servebeer.com. your.email.com. (
                        2007061907      ; serial
                        8H              ; refresh
                        2H              ; retry
                        4W              ; expire
                        60S )           ; minimum

                NS      ns1.servebeer.com. ; name server
                NS      ns2.servebeer.com. ; name server

ns1.servebeer.com.    A          86.129.37.240
ns2.servebeer.com.    A          86.129.37.240
www                   A          86.129.37.240

download        CNAME            www
homepage        CNAME            www

You will need to make sure that the zone file can be re-written by whichever user the noip client runs as, which tends to be nobody. The easiest way to do this is to make it world writable.

At the top we set the short TTL of 60 seconds. This would normally be far too short but we are borrowing the idea from the DDNS companies of using the short TTL to avoid caching problems.

Remember to change all of the values of ns1.servebeer.com and ns2.servebeer.com to your own name servers in lines 2, 9–10 and 12–13. Be careful not to remove the trailing period from the entries, it needs to be there!

Do not worry about the IP address and serial number at the moment, the script will sort those out later on.

The value your.email.com. should be read as your@email.com and is the contact address for the SOA. I wouldn’t bother changing this, it’ll just get spammed.

The last few lines set up the actual hosts that we are going to resolve. We do this by creating a record for www which will allow us to resolve www.ian.co.uk in this case.

Ordinarily if we were configuring hosts they would get an A record each, but since we can only run a single web server (as we can only port forward to one machine) it makes more sense to just use CNAME (alias) records.

You can specify as many CNAME records to www as you like, so here I have created records also for the sub-domains download.ian.co.uk and homepage.ian.co.uk.

Re-start BIND so that it reads the new configuration and then test that your machine is resolving as it should be by digging one of your domains:

yoda:~ ian$ dig www.ian.co.uk @localhost

; <<>> DiG 9.3.4 <<>> www.ian.co.uk @localhost
; (2 servers found)
;; global options:  printcmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 59806
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 2, ADDITIONAL: 0

;; QUESTION SECTION:
;www.ian.co.uk.             IN      A

;; ANSWER SECTION:
www.ian.co.uk.      60      IN      A       86.129.37.240

;; AUTHORITY SECTION:
ian.co.uk.          60      IN      NS      ns1.servebeer.com.
ian.co.uk.          60      IN      NS      ns2.servebeer.com.

;; Query time: 1 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: Sat Jun 30 16:53:57 2007
;; MSG SIZE  rcvd: 100

For now you should see your host resolve to the example IP as above. Quickly drink your weak lemon drink!

Setting up the Script

The next thing we need is the magic Perl script modip.sh! This script that I have written is the crux of the whole operation.

It has a simple purpose: when our IP address changes we need to change the IP address in the zone file to our current IP address, change the serial number for the zone and then re-start BIND.

Luckily the noip client has the option to run a program on successful update and can also be queried for the current IP address. A small querio—the noip client outputs data to stderr not stdout so if you need to capture the output that must be coded appropriately. Can’t really work out why it does that! Anyroad…

You can download the script here, and here it is printed for reference:

#!/usr/bin/perl

my $zoneFile = "/Users/ian/dns/db.ian";
my $ipLog    = "/Users/ian/dns/iplog.txt";

my @ipdata   = `/usr/local/bin/noip2 -S 2>&1`;

# get IP
foreach(@ipdata) {
    if ($_ =~ /\b(?:\d{1,3}\.){3}\d{1,3}\b/) { $ip = $&; }
}

if ($ip eq "") 
{
	print "No IP, bailing out!"; 
	exit(1); 
}

# read zone file
open(ZONE, "$zoneFile");
my @zoneData = <ZONE>;
close(ZONE);

foreach(@zoneData) 
{
    # replace IP references
    $_ =~ s/\b(?:\d{1,3}\.){3}\d{1,3}\b/$ip/g;

    # find zone serial number
    if ($_ =~ m/([0-9]{10}).*serial/g) 
    {
        $serial = $1;

        # get date
        ($Second, $Minute, $Hour, $Day, $Month, $Year)
            = localtime(time);

        $Year = 1900 + $Year;
        $Month++;

        if (length($Day) == 1)   { $Day   = "0" . $Day;   }
        if (length($Month) == 1) { $Month = "0" . $Month; }

        # if date has changed then set new date and version 01
        # else if date is the same then just increment serial

        if (substr($serial, 0, 8) eq "$Year$Month$Day") 
        {
            $serial++;
            $_ =~ s/[0-9]{10}/$serial/g;
        }

        else
        {
            my $newSerial = "$Year$Month$Day" . "01";
            $_ =~ s/[0-9]{10}/$newSerial/g;
        }
    }
}

# write new file
open(ZONE, ">$zoneFile");
print ZONE @zoneData;
close(ZONE);

# write to log

if ($ipLog ne "")
{
    open(LOG, ">>$ipLog");
    print LOG "$Year-$Month-$Day $Hour:$Minute --> changed to $ip\n";
    close(LOG);
}

# kick BIND

`rndc reload`;

You need to change lines 3–4 to suit your own setup. Set the path to the zone file that you made when setting up BIND on line 3 and then if you want a log of IP change activity set that path on line 4. If you do not want to log the activity then just remove line 4. You may need to change the path to noip2 on line 6 as well as it installs to different places on different systems.

Finally the last line must be changed to whatever command you want to use to reload your zone, this is done most easily with rndc as seen above.

Configuring Apache

You should now configure Apache and any virtual hosts ready to serve the sites that you have created. Again, installing and configuring Apache has been covered in depth elsewhere and I will not go into it here. You can choose any machine to run Apache (or IIS), it does not have to be the same machine that is running the BIND and noip client if you don’t want.

Once you have Apache up and running you need to add in virtual hosts for all of the sub-domains that you have set up to resolve, so for our example domains we have a section in the Apache config file as follows:

<VirtualHost *:80>
    DocumentRoot /Users/ian/site1
    ServerName download.ian.co.uk
</VirtualHost>

<VirtualHost *:80>
    DocumentRoot /Users/ian/site2
    ServerName homepage.ian.co.uk
</VirtualHost>

You should add one in for each sub-domain you have and set the path to the correct folder.

If a virtual host is not present then the Apache installation will serve it’s default page, so www.ian.co.uk will run as the default web page and doesn’t need a vhost of its own.

You also need to set up port forwarding on your router (port tcp.80) to whichever machine is running your Apache installation.

Installing the No-IP Client

The last step is to set up the noip client on your computer. This should update your IP at noip and with any luck everything will spring to life!

Download the Linux or Mac version depending on which system you are using and install it (instructions for this can be found on the noip website).

You must then configure the options for the client before it can be run. For this project we are going to specifically exploit the ‘on successful update run’ option which lets us run a program when the IP changes. We will use this option to run the script that we have set up above.

Create a new configuration file using the -C option of noip2:

yoda:~ ian$ sudo /usr/local/bin/noip2 -C

Auto configuration for Linux client of no-ip.com.

Multiple network devices have been detected.

Please select the Internet interface from this list.

By typing the number associated with it.
0       lo0
1       gif0
2       stf0
3       en0
4       en1
5       wlt1
6       fw0
7       en2
8       en3
2
Please enter the login/email string for no-ip.com  foo@bar.com
Please enter the password for user 'foo@bar.com'  *****

2 hosts are registered to this account.
Do you wish to have them all updated?[N] (y/N)  y
Please enter an update interval:[30]  5
Do you wish to run something at successful update?[N] (y/N)  y
Please enter the script/program name  /Users/ian/dns/modip.sh

New configuration file '/usr/local/etc/no-ip2.conf' created.

You need to enter the correct values for your own setup at the first 3 prompts, including the correct web interface (stf0 on my Mac) and your own noip account details.

Then enter y, 5 and y as I have done and then specify the path to modip.sh that you have set up; it’s up to you where you keep it.

Once the configuration is complete I suggest that you change the permissions on the config file so that it can be read by any user. This will allow the update script to work for any user!

You will need to do something along the following lines (substituting in your own path):

yoda:~/dns ian$ sudo chmod 644 /usr/local/etc/no-ip2.conf

Once this configuration is in place you need to run the daemon. Again it’s up to you how you do this—you can run it manually but it’s more sensible to have it starting up on boot from rc.d or similar.

That’s it! Everything should now be up and running. You should test that your machine is correctly resolving your domains from somewhere else on the Internet and that Apache is correctly serving them up. Of course you don’t just have to use the domains for web, you can forward any service on your router and then access the server via SSH or FTP for example as well.