In a previous post I used FreeBSD 9.2 as a DHCP server. This is basically the sequel of that post. We're going to enable PXE booting by using TFTP and NFS to serve the files from. Let's go ahead and install the dhcpd server package:

pkg install isc-dhcp43-server-4.3.0

Before we continue you'll probably want to change the IP address of your DHCP server machine to static. Edit the file /etc/rc.conf - you'll probably have a line like this:

ifconfig_em0="DHCP"

Change it to static by replacing it with:

ifconfig_em0="inet 192.168.2.99 netmask 255.255.255.0"

While in the same file make sure you manually add your gateway, in my case it's my internet router which is at 192.168.2.1:

defaultrouter="192.168.2.1"

Also add the following lines so the DHCP server starts on boot:

dhcpd_enable="YES"
dhcpd_ifaces="em0"

Add the following lines for NFS:

#NFS SERVER
rpcbind_enable="YES"
nfs_server_enable="YES"
mountd_enable="YES"
mountd_flags="-r"

Add the following lines to fire up the inetd daemon, which we'll use to serve TFTP files from:

#set up INETD for tftp:
inetd_enable="YES"

Now let's quickly configure an NFS export - edit /etc/exports and add the line:

/nfs_share -ro -alldirs

Create that directory:

mkdir /nfs_share

Configure inetd - edit /etc/inetd.conf and add the line:

tftp dgram udp wait root /usr/libexec/tftpd tftpd -l -s /nfs_share

Download the FreeBSD 10 ISO inside the /root directory:

cd /root
fetch ftp.freebsd.org/pub/FreeBSD/releases/i386/i386/ISO-IMAGES/10.0/FreeBSD-10.0-RELEASE-i386-bootonly.iso

Reboot system to enable all the above changes - note that now you'll need to SSH into the static IP you set above - in this case 192.168.2.99

#reboot:
reboot now

After ssh-ing in make sure all processes are running and listening - you should be seeing something like this:

sockstat -4 | egrep 'nfsd|mountd|rpcbind|inetd'

The output should look something like this:

root     inetd      774   5  udp4   *:69                  *:*
root     nfsd       655   5  tcp4   *:2049                *:*
root     mountd     649   7  udp4   *:917                 *:*
root     mountd     649   8  tcp4   *:917                 *:*
root     rpcbind    603   9  udp4   *:111                 *:*
root     rpcbind    603   10 udp4   *:691                 *:*
root     rpcbind    603   11 tcp4   *:111                 *:*

Mount the iso under /mnt in one command: (Got this from `man mdconfig` !)

mount -t cd9660 /dev/`mdconfig -f /root/FreeBSD-10.0-RELEASE-i386-bootonly.iso` /mnt/

Now copy the files to NFS share we created earlier:

cp -R /mnt/ /nfs_share/
umount /mnt

If you're wondering why don't we directly mount the cdrom to /nfs_share because tftp will give us messages like:

tftp localhost
tftp> get docbook.css
tftp: docbook.css: Read-only file system

Test that TFTP works correctly with the command:

tftp localhost

You should get output like this:

tftp> get docbook.css
Received 5955 bytes during 0.0 seconds in 13 blocks

Boom, works :) Now test NFS too:

mkdir /nfs_test
mount -t nfs 192.168.2.99:/nfs_share /nfs_test

You should be getting the following:

mount | grep nfs_test
192.168.2.99:/nfs_share on /nfs_test (nfs)

Let's clean up, unmount the /nfs_test directory and remove it:

umount /nfs_test && rmdir /nfs_test

Add the following dhcpd configuration inside /usr/local/etc/dhcpd.conf

option domain-name "weirdbricks.com";
option domain-name-servers 192.168.2.1;

default-lease-time 600;
max-lease-time 7200;

ddns-update-style none;

subnet 192.168.2.0 netmask 255.255.255.0 {
  range 192.168.2.100 192.168.2.165;
  option routers 192.168.2.1;
}

host pxe_dude {
        hardware ethernet 08:00:27:27:1B:24; #replace with the MAC address of the device you want to PXE boot
        option host-name "temporary.weirdbricks.com";
        fixed-address 192.168.2.166;
        next-server 192.168.2.99;
        filename "boot/pxeboot";
        option root-path "/nfs_share/";
}

Note about the above, which is a direct quote from FreeBSD's dhcpd manual page :

Each BOOTP client must be explicitly declared in the  dhcpd.conf file. A very basic client declaration will specify the client network inter-face's hardware address and the IP address to assign to that client.

Before we're ready to go we'll need to edit out the FreeBSD's installation fstab and comment out the entry for the CDROM - this will result in a nasty error if you don't do it! Edit the file /nfs_share/etc/fstab and comment out this line:

/dev/iso9660/FREEBSD_INSTALL / cd9660 ro 0 0

So it should now look like this:

#/dev/iso9660/FREEBSD_INSTALL / cd9660 ro 0 0

This is the error you'll get if you don't do this: Start the dhcpd server:

service isc-dhcpd start

Now if you were to start a machine on the same network and enable PXE it should boot - this is a screenshot of what the process looks in a VirtualBox machine in the same network which acts as a client: This is based on the following sources: