Some of us use an dynamic DNS service to access our home server or desktop, but with cheap INTERNET access prices you may think in having your own server (these days you can have 100/10MB fiber connection for 50€), that if you don’t like the cloud concept.

But what if you don’t want do use the domain name that your dynamic DNS provider give you (something like myhome.dyndns.org), lets say that you want www.at-my-domain.com. You have two options:

1 – You buy/rent a custom DNS Service (arround 40€/year/domain)

2 – You build your costom DNS server with BIND or TINYDNS.

I’ll write about the second one, but before we start let me tell you the implications this setup has.

1.º – Need root access to the server.

2.º – If you have a lot of domains you’ll have a big DNS overhead, this because you’ll have to have a small TTL (time to live) on the DNS requests you server, this to keep other DNS servers and clients updated.

3.º – Need to have cron running.

4.º – Need to have BIND installed.

5.º- Need a Dynamic DNS service provider for your initial domain, don’t forget to check use wildcard option, check www.dyndns.org, install and configure the client (following the documentation) and test it afterwards.

6.º- Need direct access to port UDP port 53, check your firewall, and hosts.deny file if you use TCP Wrappers.

7.º – This post is not about DNS security, you should read about it and hard your setup furthermore.

I’m going to set this up in a OpenSuSE 11.0 (X86_64) , but this setup should be suitable for other distros with small changes.

Imagine that you have bough the domain starwars-xpto.com

Lets start by BIND configuration and to do this lets edit /etc/named.conf and add the following lines

zone “starwars-xpto.com” in {
file “master/starwars-xpto.com”;
type master;
allow-transfer { any; };

now lets create and initial setup file by creating the file:


and add some initial content:

$TTL 60

@               IN SOA          yourhost.yourdomain.name.      root.yourhost.yourdomain.name. (

1249459201      ; serial

10800           ; refresh

3600            ; retry

604800          ; expiry

86400 )         ; minimum

starwars-xpto.com.         IN MX           10 mail.starwars-xpto.com.

starwars-xpto.com.         IN NS           ns1

starwars-xpto.com.         IN NS           ns2

mail                    IN A  

ns1                     IN A  

ns2                     IN A  

*.starwars-xpto.com.       IN A  

After this just reload named:

/etc/init.d/named reload

and test it:

dig @your_dns_server_IP www.starwars-xpto.com

you should get something like:

; <<>> DiG 9.6.1 <<>> @localhost www.starwars-xpto.com
; (2 servers found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 55310
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 2, ADDITIONAL: 2

;www.starwars-xpto.com.            IN      A

www.starwars-xpto.com.     60      IN      A

starwars-xpto.         60      IN      NS      ns1.starwars-xpto.com.
starwars-xpto.         60      IN      NS      ns2.starwars-xpto.com.

ns1.starwars-xpto.com.     60      IN      A
ns2.starwars-xpto.com.     60      IN      A

;; Query time: 0 msec
;; WHEN: Mon Aug 17 18:02:31 2009
;; MSG SIZE  rcvd: 120

If you got something like that it’s great, you have your BIND configuration working, if not, check the logs. Bind is really picky with the syntax, and by the way you can’t use # as comment in the config file just the ;

Now lets go to the interesting part, creating the script that will change your ip address on bind configuration whenever it changes. Just create a script wherever you want, my custom system scripts are usually in /root/bin so I’ll keep using it.

Lets create and edit the file /root/bin/update_dns not forgetting to change yourdomain_at_dyndns.org

just copy/past the content bellow:


BIND_DIR=’/var/lib/named/master’ ;



if [ $# -ne 1 ] ; then

echo Usage: update_dns domain ;

echo EX: update_dns domain.com;

exit ;


function get_ip ()


echo `dig yourdomain_at_dyndns.org | grep yourdomain_at_dyndns.org | grep -v ‘;\|CNAME’ | awk ‘{print $5}’` ;


function update_dns ()


DATA_SEGUNDOS=`date +’%s’`;





if [ “$IP_” != “`grep ‘IN.*A’ /var/lib/named/master/$BIND_FILE | grep -v SOA | awk ‘{print $4}’ | uniq`” ] ; then

cat $BIND_WORK_DIR_/$BIND_WORK_FILE_ | sed s/'[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}’/$IP_/ > /tmp/$DOMAIN_ ;

cat /tmp/$DOMAIN_ | sed s/'[0-9]\{10\}’/$DATA_SEGUNDOS/g > /tmp/$DOMAIN_.bind ;

cat /tmp/$DOMAIN_.bind


mv -f /tmp/$DOMAIN_.bind $BIND_WORK_DIR_/$BIND_WORK_FILE_ ;

rm /tmp/$DOMAIN_* ;

echo `date +’%b %d %H:%m:%S’` “Domain: $DOMAIN_ updated to IP: $IP_” >> /var/log/messages ;

chmod -R 755 /var/lib/named/master


echo “No need for update” ;



function restart_dns_server ()


if [ ! -f /tmp/restarting_named ] ; then

touch /tmp/restarting_named;

/etc/init.d/named stop;

sleep 3 ;

pkill -9 named ;

sleep 1 ;

/etc/init.d/named restart ;

rm /tmp/restarting_named


sleep 10 ;

restart_dns_server ;



IP=`get_ip` ;

if [ “$IP” != “`grep ‘[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}’ $BIND_DIR/$BIND_FILE | awk ‘{print $4}’ | uniq`” ] ; then


restart_dns_server ;


Finally you just need to setup cron, just type crontab -e

and add an entrace like

*/5 * * * * root /root/bin/updatedns starwars-xpto.com

Just wait the 5 minutes and check if the ip changed with the dig command as wrote above.

After all this and as the last step of configuration go to the domain provider were you bought your domain (ex: www.godaddy.com) and configure it to use as name server the NS1.yourdomain_at_dyndns.org and NS2.yourdomain_at_dyndns.org.

and your done.

This isn’t a easy setup to do but if you have multiple custom domains it can save a few € every year, I know in my case it does.


Pedro Oliveira