Using kea DHCP server for netbooting
Table of content
Recently, I’ve been playing around with PXE booting using iPXE and various DHCP servers: dnsmasq, isc-dhcp, pfsense, opnsense (yes the last 2 are not only DHCP servers).
Since isc-dhcp has reached EOL, ISC recommended switching to Kea dhcp server. So that’s what we’re going to setup today.
Prerequisites
I’m using 2 VMs for this: 1 VM running Ubuntu Server 24.04, and 1 blank VM for netbooting.
The Ubuntu 24.04 VM has 2 network interface, connect to 2 different networks. Make sure 1 of those network has Internet access. Here’s what it looks like in VMWare:

The setup looks like this:
Installed softwares on the Ubuntu 24.04 server:
keapostgresql(for storing hosts and leases)tftpd-hpa
Install them with this command:
For other OSes and platforms, check out Kea installation docs.
If the installer asks to setup control agent, just say no. We won’t go into using control agent to configure kea here, but you can check the docs on how to use the agent.
Setup networking
In my Ubuntu VM, the network adapter connected to NAT is named ens33, and the other adapter is named ens37.
We’re going to use netplan to configure the ens37 network. Use your distro tool if you’re using other OSes.
Open /etc/netplan/20-netboot.yaml and paste this in:
network:
ethernets:
ens37:
addresses:
- 10.10.10.1/24 # You can use any network here
version: 2
Then apply the configuration and check the result:
Next, we’re going to enable IPv4 forwarding and NAT on the VM. You can use iptables or nftables. I’m using nftables here.
Edit /etc/nftables.conf and add the NAT configuration:
#!/usr/sbin/nft -f
Save the file, then restart nftables.service:
Finally, enable IPv4 forwarding:
Setup the database
Kea supports using a database to store its leases and host reservations. This is what we’re going to setup first.
First, change user to postgres and create a user for Kea:
# We're running bash under user postgres now
Then, create 2 seperate databases for Kea: kea-leases and kea-hosts:
# Still running under user postgres
# Exit out of postgres user
Now, initialize both databases. There are 2 ways you can do this:
- You can do it manually, with the script at
/usr/share/kea/scripts/pgsql/dhcpdb_create.pgsql:
- You can do it using
kea-admin. This is simpler:
We’ve finished setting up the database. For more information, check out the database administration docs.
Configuring Kea
We’re only configuring DHCPv4 in this post. DHCPv6 should be quite similar.
Kea is using JSON for its configuration. Our Kea installation on Ubuntu has 4 files in /etc/kea: kea-ctrl-agent.conf, kea-dhcp4.conf, kea-dhcp6.conf, kea-dhcp-ddns.conf. Since we’re only using DHCPv4, the only file we need to edit is kea-dhcp4.conf
If you check the kea-dhcp4.conf file, you might be whelmed with the amount of options you can tweak. Let’s make a backup first:
Now use your favourite editor and open /etc/kea/kea-dhcp4.conf. Delete everything in it, we’re starting from scratch.
All configuration for DHCPv4 must be under Dhcpv4 key. Paste in the configuration below, we’re going through each of them:
interfaces-configconfigure DHCPv4 server to listen on specific network interfaces. Here we only wants it to listen on the interface connected to the local network segment,ens37:... "interfaces-config": , ...- You can use an asterisk
*to make it listen on all interfaces. Multiple IP addresses can also be listened on. You can read more at https://kea.readthedocs.io/en/kea-2.6.0/arm/dhcp4-srv.html#interface-configuration.
- You can use an asterisk
lease-databaseandhosts-databaseconfigure Kea on how to connect to Postgres. Here we’re using the database we’ve configured in the previous section.... "lease-database": , "hosts-database": , ...The following configures validity of DHCP leases. Here we sets it to 3600s (1h).
renew-timerandrebind-timerare optional, you can let Kea automatically calculate them withcalculate-tee-times. More info at https://kea.readthedocs.io/en/kea-2.6.0/arm/dhcp4-srv.html#dhcp4-t1-t2-times.... "renew-timer": 900, "rebind-timer": 1800, "valid-lifetime": 3600, ...option-dataspecifies the global DHCPv4 options which will be sent to all subnets.... "option-data": ...- Note that there are more options. The full configuration might look like this:
Either
nameorcodeis required.spacedefaulted todhcpv4, andcsv-formatdefaulted totrue. These can be omitted, resulting in our configuration above. See https://kea.readthedocs.io/en/kea-2.6.0/arm/dhcp4-srv.html#standard-dhcpv4-options for more details.You can see the list of DHCP option names and codes here: https://kea.readthedocs.io/en/kea-2.6.0/arm/dhcp4-srv.html#dhcp4-std-options-list
client-classesis how we can chain load iPXE. It specifies what to send to clients, based on their packets to our PXE server. We can classify clients into different classes, and define what to send to those classes. This is quite complicated, so if you want to know more you can check the docs: https://kea.readthedocs.io/en/kea-2.6.0/arm/classify.html- List of all tests you can use can be viewed here: https://kea.readthedocs.io/en/kea-2.6.0/arm/classify.html#id3.
... "client-classes": , ...A client class definition must have
nameparameter, which must be unique. Other parameters are optional. See https://kea.readthedocs.io/en/kea-2.6.0/arm/classify.html#configuring-classes for the list of all parameters.In our configuration above, we have 3 classes:
iPXE,UEFI clientsandBIOS clients. Client classes in Kea follow the order in which they are specified in the configuration. If two or more classes include the same class information, the value from the first assigned class is used. So, we must put theiPXEclass definition first, to prevent boot loop.The architecture is sent in DHCP option 93, and of type
uint16in Kea. So we test the value of option 93, matching the value defined in https://www.iana.org/assignments/dhcpv6-parameters/dhcpv6-parameters.xhtml#processor-architecture. Then we send a corresponding iPXE boot file for either BIOS or UEFI client arch.After iPXE loaded, it sends option 175 to our PXE server. We test for that option existence, then chain our clients to
http://boot.netboot.xyz. iPXE then load thenetboot.xyzmenu from that URL, and we’re done! 11The boot files downloaded from
https://boot.ipxe.org/were not compiled with HTTPS support, so we’re using HTTP here. See https://ipxe.org/crypto on how to manually compile iPXE with HTTPS.
Finally, the subnet configuration:
... "subnet4": , ...idmust be unique.subnetspecifies the CIDR for your network. Non-canonical subnet address is allowed, so10.10.10.10/24is valid too.poolsconfigures the range of address Kea will give out to clients. Multiple pools are accepted. You can specify range ina.b.c.d - e.f.g.hformat ora.b.c.d/eformat. More details can be found here: https://kea.readthedocs.io/en/kea-2.6.0/arm/dhcp4-srv.html#configuration-of-ipv4-address-pools
We also configure some logging options for debugging:
... "loggers": ...- All loggers in Kea has a
name. List of logger names can be found here: https://kea.readthedocs.io/en/kea-2.6.0/arm/logging.html#id3 - We set
severitytoDEBUGto troubleshoot our class classification. You can set this back toINFOif everything runs fine. debuglevelis set to60to also troubleshoot class expressions. This is explained in https://kea.readthedocs.io/en/kea-2.6.0/arm/classify.html#debugging-expressions.- We won’t go too deep into
output_optionshere. In our configuration we set logs tostdoutforsystemd.patternis set to<LOG LEVEL> <LOG MESSAGE>. More patterns are in the docs.
- All loggers in Kea has a
We’ve finished configuring Kea! Now restart kea-dhcp4-server.service and check its log output:
; ; )
) ;
)
)
)
)
Get the iPXE boot files
By default, tftpd-hpa TFTP root is at /srv/tftp. Change directory into that and download the boot files from https://boot.ipxe.org/:
Test drive
Now, connect the blank VM to the same internal network as the Ubuntu VM. Boot that VM up, and it should chain load iPXE, then boot into netboot.xyz.
Further reading
- Kea Administrator Reference Manual: https://kea.readthedocs.io/en/kea-2.6.0/index.html
- Kea Training Series: https://www.youtube.com/playlist?list=PLUwyH0o3uuIBv1-CJQaM9_L4_wrI0Jatb