This is a pretty geeky thing to do but running your own DNS Server on your intranet does make some sense from a performance and conveience perspective.
Background
The sole purpose of a DNS Server is to provide a look-up service for mapping hostnames e.g. www.google.com to IP addresses 100.101.20.2. By far the most popular DNS Server software out there is a package called bind.
There are essentially 2 reasons to running your own DNS Server.
- Improving the speed of hostname lookups
- Managing your own intranet hostnames & IP addresses in a central location
The first reason is what is commonly called a Caching Name Server. In essence by having one machine provide all hostname look-ups in your intranet, you’re cutting down on every machine in your intranet having to independently look-up names. Additionally once a name is looked up your DNS Server will cache the results for a set period of time so that subsequent queries can come out of your DNS Server’s cache and not have to go and do the look-up on your ISPs DNS Server.
The second reason is actually the cooler one. Since you control the DNS Server you can create your own local domain (called zones in bind lingo) and name all the systems within your intranet. In so doing this it’s much easier to connect to systems using names rather than IP addresses. Plus it’s fun to name all the systems!
Taking this a step further you can create generic hostnames such as imap, mail, smtp, ntp, pop, etc. and manage these in one stop rather than having to manage them throughout your intranet.
Getting started
First things first, install the necessary bind software.
1 | yum install bind bind-utils bind-libs |
Generating a rndc key
NOTE: All the config files we’re going to work on are located in /var/named/chroot
Next you’ll need to create/modify a rndc.conf and/or rndc.key file. This file contains a key which is required in order to manage the bind service once it’s up and running. With this key you can theoretically manage bind either on the host where it’s running or you can manage it on any system that is allowed to do so and knows this key!
1 2 | # command to generate a new 512 byte key rndc-confgen -b 512 |
This command will return the following output which you’ll want to either redirect to a file or copy and paste into a file. The file should be rndc.conf but I like to use this name instead, /var/named/chroot/etc/rndc.key. It just makes more sense to me.
1 2 3 4 5 6 7 8 9 10 11 12 | # Start of rndc.conf key "rndckey" { algorithm hmac-md5; secret "nHFS3WOpdap75IvsYSXVNYWusnAQPT6z5XC8V5YPWXnZ8RN8tdfSFuClZ8nNouWyGhvHB8mETJgwsrvhiYhIhA=="; }; options { default-key "rndckey"; default-server 127.0.0.1; default-port 953; }; # End of rndc.conf |
The rndc-confgen command also returns some additional output below. This goes into the file /var/named/chroot/etc/named.conf. Make sure to remove the comments at the beginning of each line to turn them on.
1 2 3 4 5 6 7 8 9 10 11 | # Use with the following in named.conf, adjusting the allow list as needed: key "rndckey" { algorithm hmac-md5; secret "nHFS3WOpdap75IvsYSXVNYWusnAQPT6z5XC8V5YPWXnZ8RN8tdfSFuClZ8nNouWyGhvHB8mETJgwsrvhiYhIhA=="; }; # controls { inet 127.0.0.1 port 953 allow { 127.0.0.1; } keys { "rndckey"; }; }; # End of named.conf |
named.conf file
Now let’s flesh out that named.conf file a little bit more.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | acl lan { 192.168.1.0/24; 127.0.0.1; }; controls { inet 127.0.0.1 port 953 allow { lan; } keys { "rndckey"; }; }; logging { category default { default_syslog; }; category lame-servers { null; }; }; options { pid-file "/var/run/named/named.pid"; directory "/var/named"; dump-file "named_dump.db"; forward only; forwarders { # the following IP addresses are my ISPs DNS Servers. These will be used for looking up # hostnames that I don't locally manage, i.e. the REST OF THE INTERNET! 24.92.226.40; # my ISPs DNS Server #1 24.92.226.41; # my ISPs DNS Server #2 }; /* * If there is a firewall between you and nameservers you want * to talk to, you might need to uncomment the query-source * directive below. Previous versions of BIND always asked * questions using port 53, but BIND 8.1 uses an unprivileged * port by default. */ query-source address * port 53; allow-query { lan; }; allow-recursion { lan; }; allow-transfer { lan; }; }; zone "bubba.net"{ type master; file "data/db.bubba.net"; }; zone "0.0.127.in-addr.arpa"{ type master; file "data/db.127.0.0"; }; zone "1.168.192.in-addr.arpa"{ type master; file "data/db.192.168.1"; }; zone "." { type hint; file "root.hints"; }; |
Here is a quick rundown of what’s going on here. The acl lan creates an access control list that includes 192.168.1.0/24 and 127.0.0.1 so that only hosts within these IP address ranges can remotely manage and use this bind instance. 192.168.1.0/24 means IP addresses in the range 192.168.1.1 – 192.168.1.255.
The zones, “bubba.net”, “0.0.127.in-addr.arpa”, “1.168.192.in-addr.arpa”, and “.” are all essentially files containing either hostname → IP address mappings or IP address → hostname mappings that this bind server will be responsible for.
Bulding zone files
The first zone: “bubba.net” includes all the hostnames and the IP addresses they point to. So these would be my systems:
- scully.bubba.net
- mulder.bubba.net
- doggett.bubba.net
The second and third zones: “0.0.127.in-addr.arpa” and “1.168.192.in-addr.arpa” are special zones that provide “reverse” name look-ups. These are when you look up a IP address and want to know what name(s) are associated with it. For example:
- 192.168.1.100
- 192.168.1.101
The fourth zone: “.” is a special zone that makes this bind server act as a caching name server, for any hostnames and IP addresses that fall outside of the first 3 zones. These hostname and IP address look-ups will be forwarded to my ISPs DNS Server, and the results cached here for subsequent quereies.
Here is what the zone “bubba.net” looks like.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | $TTL 604800 ; ; Zone file for bubba.net ; ; Mandatory minimum for a working domain ; @ IN SOA ns.bubba.net. hostmaster.bubba.net. ( 2000072802 ; serial 28800 ; refresh 7200 ; retry 3600000 ; expire 86400 ; default_ttl ) @ IN NS ns.bubba.net. @ IN MX 10 mail.bubba.net. @ IN MX 20 mail.bubba.net. ; ; Provide familiar names to services but ; acutally all are coming from XXXXX ; These need to be bound to the address directly, no CNAME's. ; ----------------------------------------------------------- bubba.net. IN A 192.168.1.1 ; hostmaster.bubba.net. IN A 192.168.1.101 ns.bubba.net. IN A 192.168.1.101 ... ... ; Subnet 192.168.1 machines ; ------------------------- mulder.bubba.net. IN A 192.168.1.1 mulder.bubba.net. IN HINFO "AMD Athlon(tm) Dual Core Processor 4850e 2.2GHz" "LINUX" mulder.bubba.net. IN MX 10 mail.bubba.net. mulder.bubba.net. IN TXT "" scully.bubba.net. IN A 192.168.1.2 scully.bubba.net. IN HINFO "Celeron 450" "Windows 2000" scully.bubba.net. IN MX 10 mail.bubba.net. scully.bubba.net. IN TXT "" ... ... |
The first 16 lines are pretty standard. These setup a TTL or Time To Live which means how long any of this data should be cache. Line 14 denotes which machine is the SOA, Start of Authority, ns.bubba.net is the master of this domain is what it’s saying 8-). Lines 15 & 16 state which machine is the mail exchange for this domain. I only have one mail exchange so I just list it twice.
The most important section in this file starts with the declaration of hostnames. Each hostname gets 4 lines. A “IN A” line which tells you the IP address for this hostname. The “IN HINFO“ which is just a description of the host itself. The “IN MX” states who the mail exchange is for this host. And finally the “IN TXT“ line which I’m not going to get into today but it is important later on when you’re setting up you mail server.
Here is what the zone “db.192.168.1″ looks like.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | $TTL 604800 @ IN SOA ns.bubba.net. hostmaster.bubba.net. ( 2000072801 ; serial 28800 ; refresh 7200 ; retry 604800 ; expire 86400 ; default-ttl ) @ IN NS ns.bubba.net. ; 101 IN PTR mulder.bubba.net. 102 IN PTR scully.bubba.net. 103 IN PTR doggett.bubba.net. ... ... |
The first 9 lines are essentially stating how long any Caching DNS Name Server should cache this data before getting a fresh copy. The SOA ns.bubba.net is saying which machine is the authority for this domain. The hostmaster.bubba.net is actually an email address that is responsible for this domain, hostmaster@bubba.net.
Finally the zone “db.127.0.0″ which really serves no purpose other than as a backup in case a host didn’t configure itself correctly with the loopback address. Here is what my zone file looks like:
1 2 3 4 5 6 7 8 9 10 11 | $TTL 604800 @ IN SOA ns.bubba.net. hostmaster.bubba.net. ( 2000031801 ; serial 28800 ; refresh 7200 ; retry 604800 ; expire 86400 ; default_ttl ) @ IN NS ns.bubba.net. ; 1 IN PTR localhost.bubba.net. |
The zone “.” uses a file called root.hints. Here is an example of what this file looks like.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | ; <<>> DiG 9.3.4-P1 <<>> @e.root-servers.net . ns ; (1 server found) ;; global options: printcmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 21247 ;; flags: qr aa rd; QUERY: 1, ANSWER: 13, AUTHORITY: 0, ADDITIONAL: 14 ;; QUESTION SECTION: ;. IN NS ;; ANSWER SECTION: . 518400 IN NS D.ROOT-SERVERS.NET. . 518400 IN NS C.ROOT-SERVERS.NET. . 518400 IN NS G.ROOT-SERVERS.NET. . 518400 IN NS L.ROOT-SERVERS.NET. . 518400 IN NS F.ROOT-SERVERS.NET. . 518400 IN NS I.ROOT-SERVERS.NET. . 518400 IN NS B.ROOT-SERVERS.NET. . 518400 IN NS J.ROOT-SERVERS.NET. . 518400 IN NS M.ROOT-SERVERS.NET. . 518400 IN NS K.ROOT-SERVERS.NET. . 518400 IN NS H.ROOT-SERVERS.NET. . 518400 IN NS A.ROOT-SERVERS.NET. . 518400 IN NS E.ROOT-SERVERS.NET. ;; ADDITIONAL SECTION: A.ROOT-SERVERS.NET. 3600000 IN A 198.41.0.4 A.ROOT-SERVERS.NET. 3600000 IN AAAA 2001:503:ba3e::2:30 B.ROOT-SERVERS.NET. 3600000 IN A 192.228.79.201 C.ROOT-SERVERS.NET. 3600000 IN A 192.33.4.12 D.ROOT-SERVERS.NET. 3600000 IN A 128.8.10.90 E.ROOT-SERVERS.NET. 3600000 IN A 192.203.230.10 F.ROOT-SERVERS.NET. 3600000 IN A 192.5.5.241 F.ROOT-SERVERS.NET. 3600000 IN AAAA 2001:500:2f::f G.ROOT-SERVERS.NET. 3600000 IN A 192.112.36.4 H.ROOT-SERVERS.NET. 3600000 IN A 128.63.2.53 H.ROOT-SERVERS.NET. 3600000 IN AAAA 2001:500:1::803f:235 I.ROOT-SERVERS.NET. 3600000 IN A 192.36.148.17 J.ROOT-SERVERS.NET. 3600000 IN A 192.58.128.30 J.ROOT-SERVERS.NET. 3600000 IN AAAA 2001:503:c27::2:30 ;; Query time: 109 msec ;; SERVER: 192.203.230.10#53(192.203.230.10) ;; WHEN: Fri Feb 20 03:49:01 2009 ;; MSG SIZE rcvd: 500 |
Starting bind up
Once you have all this in place you can start up bind with this command.
1 | /etc/init.d/named start |
Configuring a host to use your DNS server
One final step is to configure your host to use your newly setup DNS Server as it’s name server. You can accomplish this by changing 2 files. /etc/resolv.conf and /etc/nsswitch.conf.
The /etc/resolv.conf should look like this:
1 2 | search bubba.net nameserver 192.168.1.101 |
The /etc/nsswitch.conf should have an entry like this in it:
1 2 3 4 5 | ... ... hosts: files dns ... ... |
Taking it out for a test drive
You can see if it’s working by poking the name server using host, dig, or nslookup. Here are a couple of example quereies.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | # host example % host -l bubba.net bubba.net name server ns.bubba.net. bubba.net has address 192.168.1.1 ... ... # dig example % dig ns.bubba.net ; <<>> DiG 9.3.4-P1 <<>> ns.bubba.net ;; global options: printcmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 54856 ;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 1, ADDITIONAL: 0 ;; QUESTION SECTION: ;ns.bubba.net. IN A ;; ANSWER SECTION: ns.bubba.net. 604800 IN A 192.168.1.101 ;; AUTHORITY SECTION: bubba.net. 604800 IN NS ns.bubba.net. ;; Query time: 1 msec ;; SERVER: 192.168.1.101#53(192.168.1.101) ;; WHEN: Sat Feb 28 20:54:46 2009 ;; MSG SIZE rcvd: 60 # nslookup example % nslookup ns.bubba.net Server: 192.168.1.101 Address: 192.168.1.101#53 Name: ns.bubba.net Address: 192.168.1.101 |

[...] Setup DNS on Centos http://www.lamolabs.org/blog/282/how-to-setup-a-dns-server-on-centos-5/ [...]
Great tutorial. Some notes for those of us that use it:
1) You need to ensure that you install bind-chroot before the setup: yum install bind-chroot
2) Note that the zone files need to be located under /var/named/chroot/var/named/data
3) root.hints needs to be either in the /var/named/chroot directory or better under the /var/named/chroot/var/named/data directory and the named.conf changed to “data/root.hints”.
Thanks for putting this together it was quite useful for me.
D
Hi Dale,
Why do you need to change the named.conf to root.hints?
Isn’t there is one already created ?
Thanks,
Thomas
Thanks for the tutorial, great one. Just some notes for those who are reading this:
– make ‘named’ the owner/userid of /var/named/chroot/var folder otherwise the service will fail to start. Also give that user 7 permission [rwx] for data folder files [db.* and root.hints];
– Turn off your SELinux
Cheers
i didn’t quite understand this note “make ‘named’ the owner/userid of /var/named/chroot/var folder otherwise the service will fail to start” ?? how can i start named without failure ??
Katie’s comment is referring to the directory /var/named/chroot/var. You need to make sure that this directory is owned by the user named. Typically you want to run this type of command to accomplish it:
Also the permissions should be such that this directory is setup so that the owner, now the user named, also has read, write, and execute permissions. Again to accomplish this:
[...] ;; WHEN: Mon Mar 21 10:08:48 2011 ;; MSG SIZE rcvd: 500 I took the above configuration from this tutorial And following is my spudlabs.com.zone file $ttl 38400 spudlabs.com. IN SOA ns.spudlabs.com. [...]
Hi
How do you change the hostmaster address in the SOA? In your example how would I change hostmaster.bubba.net. to support.bubba.net????
I am running centos 6
Simply change hostmaster.bubbba.net to support.bubba.net. That’s an email address. It’s just how you specify it in bind’s config files. So hostmaster.bubba.net is actually the contact email, hostmaster@bubba.net. So I’m assuming you want to change it to support@bubba.net. Is that what you’re after?
Here’s an example from the website, zytrax.com.
example.com. IN SOA ns.example.com. hostmaster.example.com. ( 2003080800 ; sn = serial number 172800 ; ref = refresh = 2d 900 ; ret = update retry = 15m 1209600 ; ex = expiry = 2w 3600 ; min = minimum = 1h )In this example:
The “query-source address * port 53;” line in your named.conf above is not commented, which makes the preceding comment a bit confusing.
At any rate, in my situation, if I left that line as is (i.e. not commented), then my DNS would work for a while (maybe a day or two), and then stop working for external addresses. Then if I stopped the named service for a while (maybe a few hours or a day), then restarted it, it work work… again for a limited time. I was pulling my hair out trying to determine why it stopped working. Running with detailed logs showed that external queries were timing out. But using e.g. dig or nslookup with the forwarder DNS servers worked just fine.
I finally thought to force dig to use a source port of 53 with the forwarder/external DNS servers, and duplicated the timeout.
So I just commented-out that source address config directive in my named.conf, and everything has been working just fine since.
Thanks for a great and helpful tutorial. Just posting this to help anyone else who sees wacky behavior with that “query-source address * port 53;” config line uncommented.
I just came across someone on this CentOS Forum that used my tutorial. I only skimmed the comments but it looks like he (Tom) was having some issues with the syntax of the /etc/named.conf file. There is some useful tips in the replies for debugging that I thought others might like to be aware of. “Here’s the link to the thread.