DNS and DHCP for the homelab

I keep threatening to set up a homelab. I want to keep it away from the devices that I already have on the network, and I want it to ‘just work’. That means I need a reliable DNS and DHCP setup.

Firstly I set up a new VLAN and allocated an IP address range to it. I’ve gone with VLAN 4 and 172.16.4.0/24. My Operating System of choice is FreeBSD with the latest supported release being 14.1, so I downloaded the 14.1 bootable ISO, mounted it in my virtual machine and began the install.

I didn’t do anything exciting during the install. Once the install had completed, I did a quick freebsd-update fetch followed by a freebsd-update install to get the system up to date, then it was time to go.

I looked in to what DHCP and DNS servers to install, and kept coming back to ISC BIND and ISC DHCP. They’re both tried and tested and simply work. I did look at PowerDNS, but I couldn’t get it to behave in the way I wanted.

Installing packages

I could have compiled them both from the ports tree, but this adds complexity that I don’t want for the ongoing maintenance of the system. So I installed them using the packages system pkg install bind918 isc-dhcp44-server. A few minutes later and it’s all done. Each package had a pkg-message after the install.


Based on the bind918 pkg-message, I ran rndc-confgen -a which outputted the keyfile to /usr/local/etc/namedb/rndc.key. I need to note this location for later.

I also added some bits to /etc/rc.conf.local to ensure that services started up if the system is rebooted.

ben@ns01:~ $ cat /etc/rc.conf.local

named_enable="YES"

dhcpd_enable="YES"
dhcpd_flags="-q"
dhcpd_conf="/usr/local/etc/dhcpd.conf"
dhcpd_ifaces="vmx0"
dhcpd_withumask="022"

dhcpd_withuser="dhcpd"
dhcpd_withgroup="dhcpd"
dhcpd_devfs_enable="YES"
dhcpd_rootdir="/var/db/dhcpd"
ben@ns01:~ $

Configuring BIND

There were only a couple of parameters I needed to modify in /usr/local/etc/namedb/named.conf

listen-on  { 127.0.0.1; 172.16.4.10; };
forwarders { 192.168.0.115; };
include "/usr/local/etc/namedb/named.conf.local";

listen-on was updated to include the host IP address, so the server will listen for queries from the network. forwarders has been set to the IP address of the pi.hole that I have running (adverts have ruined the internet, making it mostly unusable unless you block them). And I added the include line so I can modify local config for BIND – This makes file merges easier to read if the package is updated.

Everything else was left as default. As you can see, I created a new file /usr/local/etc/namedb/named.conf.local. That’s a pretty simple file, with the content simply being:

key "rndc-key" {
        algorithm hmac-sha256;
        secret "generated-earlier";
};

zone "internal.benquick.me" {
        type master;
        file "/usr/local/etc/namedb/primary/internal.benquick.me-forward.db";
        allow-update { key rndc-key; };
};

zone "4.16.172.in-addr.arpa" {
        type master;
        file "/usr/local/etc/namedb/primary/internal.benquick.me-reverse.db";
        allow-update { key rndc-key; };
};

I’ve defined the forward and reverse zones I’m going to use, and have said that they can be updated if the DHCP server sends the same secret that is specified in the rndc-key – The location of this was noted earlier and the content used above. That’s basically DNS done for my needs right now.

Configuring DHCPD

Next it was time to configure DHCP to perform two tasks:
1) Issue IP addresses from a DHCP pool
2) Update DNS with the hostname of the client
/usr/local/etc/dhcpd.conf is fairly well documented and pretty straight forward to manage. I simply added a couple of lines at the bottom of the file.

authoritative;
default-lease-time 3600;
max-lease-time 14400;
ping-check true;
update-static-leases on;
ddns-updates on;
ddns-update-style standard;
ddns-ttl 300;
ddns-domainname "internal.benquick.me";
allow unknown-clients;

include "/usr/local/etc/dhcpd/rndc.key";

zone internal.benquick.me {
  primary 172.16.4.10;
  key rndc-key;
}

zone 4.16.172.in-addr.arpa. {
  primary 172.16.4.10;
  key rndc-key;
}

subnet 172.16.4.0 netmask 255.255.255.0 {
  option domain-name-servers 192.168.0.115;
  option domain-name "internal.benquick.me";
  option domain-search "internal.benquick.me";
  option routers 172.16.4.254;
  option subnet-mask 255.255.255.0;
  option broadcast-address 172.16.4.255;

  pool {
    range 172.16.4.50 172.16.4.70;
  }
}

The file /usr/local/etc/dhcpd/rndc.key is simply a copy of the one we created earlier. This allows the DHCP server to use the secret that the DNS server is expecting, and therefore allows the DNS zone to be updated.

Testing

Testing was just a case of powering on a server on the VLAN that I had created.

ben@ns01:~ $ cat "/usr/local/etc/namedb/primary/internal.benquick.me-forward.db"
[...]
testbox01               A       172.16.4.50
                        DHCID   ( AAEBqS5elK344hZ7aReMzWaYol+yvgXp9o/cewffE1zk
                                lIM= ) ; 1 1 32
ben@ns01:~ $

Next steps

That was remarkably easy! The next things to do are:
1) Create a second nameserver so I have a primary/secondary set up
2) Implement DHCP failover

After that, I want to see about automating as much of this as possible.

Leave a Reply

Your email address will not be published. Required fields are marked *