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:
- have a working DHCP with PXE boot options
- have a working TFTP server
- customise your pxelinux boot menu
- install a FreeBSD box manually, or use an existing one
- download and install mfsbsd on the FreeBSD system
- download a FreeBSD release iso image on the FreeBSD system
- configure and customise your FreeBSD PXE boot image settings
- build the PXE boot image and copy it to your TFTP server
- 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.
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:
Mount the ISO:
mdconfig -a -t vnode -f /root/FreeBSD-10.1-RELEASE-amd64-disc1.iso mount_cd9660 /dev/md0 /cdrom/
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:
Test the PXE installation
Boot a test machine from PXE and boot your custom generated image.
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.