FreeBSD 10.1 Unattended Install Over PXE & HTTP (No NFS)

January 16, 2015 Category: FreeBSD

To gain some more experience with FreeBSD, I decided to make a PXE-based unattended installation of FreeBSD 10.1.

My goal is to set something up similar to Debian/Ubuntu + preseeding or Redhat/CentOS + kickstart.

Getting a PXE-based unattended installation of FreeBSD 10.1 was not easy and I was unable to automate a ZFS-based install using bsdinstall.

I would expect someting like the netboot install

Below, I've documented what I've done to do a basic installation of FreeBSD using only DHCP, TFTP, no NFS required.

Overview of all the steps:

  1. have a working DHCP with PXE boot options
  2. have a working TFTP server
  3. customise your pxelinux boot menu
  4. install a FreeBSD box manually, or use an existing one
  5. download and install mfsbsd on the FreeBSD system
  6. download a FreeBSD release iso image on the FreeBSD system
  7. configure and customise your FreeBSD PXE boot image settings
  8. build the PXE boot image and copy it to your TFTP server
  9. PXE boot your system and boot the FreeBSD image

Setting up a DHCP server + TFTP server

Please take a look at another article I wrote on setting up PXE booting.

Configuring the PXE boot menu

Add these lines to your PXE Menu:

LABEL FreeBSD10
kernel memdisk
append initrd=BSD/FreeBSD/10.1/mfsbsd-10.1-RC3-amd64.img harddisk raw

Setup or gain access to a FreeBSD host

You need to setup or gain access to a FreeBSD system, because the mfsbsd tool only works on FreeBSD. You will use this system to generate a FreeBSD PXE boot image.

Installing mfsbsd

First we download mfsbsd.

fetch http://mfsbsd.vx.sk/release/mfsbsd-2.1.tar.gz
tar xzf mfsbsd-2.1.tar.gz

Then we get a FreeBSD ISO:

fetch http://ftp.freebsd.org/pub/FreeBSD/releases/ISO-IMAGES/10.1/FreeBSD-10.1-RELEASE-amd64-disc1.iso

Mount the ISO:

mdconfig -a -t vnode -f /root/FreeBSD-10.1-RELEASE-amd64-disc1.iso
mount_cd9660 /dev/md0 /cdrom/

setup rc.local

Enter the mfsbsd-2.1 directory. Put the following content in the conf/rc.local file.

fetch http://<yourwebserver>/pxe/installerconfig -o /etc/installerconfig
tail -n 7 /etc/rc.local > /tmp/start.sh
chmod +x /tmp/start.sh
/tmp/start.sh 
exit 0

#!/bin/csh
setenv DISTRIBUTIONS "kernel.txz base.txz"
setenv BSDINSTALL_DISTDIR /tmp
setenv BSDINSTALL_DISTSITE
ftp://ftp.freebsd.org/pub/FreeBSD/releases/amd64/10.1-RELEASE

bsdinstall distfetch 
bsdinstall script /etc/installerconfig

As you can see there is a script within a script that is executed separately by rc.local. That's a bit ugly but it does work.

setup installerconfig (FreeBSD unattended install)

The 'installerconfig' script is a script in a special format used by the bsdinstall tool to automate the installation. The top is used to control variables used during the unattended installation. The bottom is a script executed post-install chrooted on the new system.

Put this in 'installerconfig'

PARTITIONS=da0
DISTRIBUTIONS="kernel.txz base.txz"
BSDINSTALL_DISTDIR=/tmp
BSDINSTALL_DISTSITE=ftp://ftp.freebsd.org/pub/FreeBSD/releases/amd64/10.1-RELEASE

#!/bin/sh
echo "Installation complete, running in host system"
echo "hostname=\"FreeBSD\"" >> /etc/rc.conf
echo "autoboot_delay=\"5\"" >> /boot/loader.conf
echo "sshd_enable=YES" >> /etc/rc.conf
echo "Setup done" >> /tmp/log.txt
echo "Setup done."
poweroff

As you can see, the post-install script enables SSH, sets the hostname and reduced the autoboot delay.

Please note that I faced an issue where the bsdinstall program would not interpret the options set in the installerconfig script. This is why I exported them with 'setenv' in the rc.local script.

With Debian preseeding or Redhat kickstarting, you can host the preseed or kickstart file on a webserver. Changing the PXE-based installation is just a matter of edditing the preseed or kickstart file on the webserver.

Because it's not fun having to generate a new image every time your want to update your unattended installation, it's recommended to host the installerconfig file on a webserver, as if it is a preseed or kickstart file.

This saves you from having to regenerate the PXE-boot image file every time.

You can still put the installer config in the image itself. If you want a fixed 'installerconfig' file containing the bsdinstall instructions, put this file also in the 'conf' directory. Next, edit the Makefile. Search for this string:

.for FILE in rc.conf ttys

For me, it was at line 315. Change it to:

.for FILE in rc.conf ttys installerconfig

Building the PXE boot image

Now everything is configured, we can generate the boot image with mfsbsd. Run 'make'. Then when it fails with this error:

Creating image file ...
/root/mfsbsd-2.1/tmp/mnt: write failed, filesystem is full
*** Error code 1

Stop.
make: stopped in /root/mfsbsd-2.1

just run 'make' again. In my experience, make worked the second time, consistently. I'm not sure why this happens.

The end result of this whole process is a file like 'mfsbsd-se-10.1-RC3-amd64.img'.

You can copy this image to the appropriate folder on your TFTP server. In my example it would be:

/srv/tftp/BSD/FreeBSD/10.1/mfsbsd-10.1-RC3-amd64.img

Test the PXE installation

Boot a test machine from PXE and boot your custom generated image.

Final words

I'm a bit unhappy about how difficult it was to create an PXE-based unattended FreeBSD installation. The bsdinstall installation software seems buggy to me. However, it could be just me: that I have misunderstood how it al works. However, I can't seem to find any documentation on how to properly use the bsdinstall system for an unattended installation.

If anyone has suggestions or ideas to implement an unattended bsdinstall script 'properly', with ZFS support, I'm all ears.

This is the recipe I tried to use to get a root-on-zfs install:

ZFSBOOT_POOL_NAME=TEST_ROOT
ZFSBOOT_VDEV_TYPE=mirror
ZFSBOOT_POOL_SIZE=10g
ZFSBOOT_DISKS="da0 da1"
ZFSBOOT_SWAP_SIZE=2g
ZFSBOOT_CONFIRM_LAYOUT=1

The installer would never recognise the second disk and the script would get stuck.

I'm aware that mfsbsd has an option to use a custom root-on-zfs script, but I wanted to use the 'official' FreeBSD tools.

Comments