Automated FreeBSD Install
For FreeBSD, the ability to PXE boot BIOS and UEFI systems is not new, but documentation frequently assumes an NFS mounted root file system. In my view NFS is unworkable since file access is not logged, and a hung mount is difficult to diagnose.
By using TFTP to pivot to a minroot, then switching to HTTP the entire process can be audited and tailored for individual hosts. This methodology aims to borrow techniques used by an automated install for OpenBSD and Red Hat Linux.
DHCP Services
To PXE-boot FreeBSD there are three components we will need to three components
-
filename
to be loaded by PXE -
root-path
to be used by the loader -
next-server
for the custom installation script
# /etc/dhcpd.conf subnet 192.168.0.0 netmask 255.255.255.0 { option routers 192.168.0.7; option domain-name-servers 192.168.0.3; range 192.168.0.64 192.168.0.254; next-server 192.168.2.20; host T460S { hardware ethernet c8:5b:76:0d:1c:f3; fixed-address 192.168.0.11; filename "loader.efi"; option root-path "tftp://192.168.2.20/freebsd13"; option host-name "t460s"; } }
HTTP Services
The install media can be copied, or mount the ISO as a read-only file system
vnconfig vnd1 /var/www/htdocs/FreeBSD-13.2-RELEASE-amd64-disc1.iso mount_cd9660 /dev/vnd1c /var/www/htdocs/pub/freebsd13
Distribution files can now be pulled from this
http://${next_server}/pub/freebsd13/usr/freebsd-dist/
.
Copy
loader.efi
to
/tftpboot/
.
Memory File System
Sadly, FreeBSD does not ship a minroot, but we can fetch an image from the mfsBSD project. Mount this ISO in a location where the loader and access boot config and minroot
vnconfig vnd0 /var/www/htdocs/mfsbsd-13.2-STABLE-amd64.iso mount_cd9660 /dev/vnd0c /tftpboot/freebsd13
This provides everything required to boot
|-- boot | |-- defaults | | `-- loader.conf | |-- device.hints | |-- kernel | | |-- acpi_*.ko | | |-- ahci.ko | | |-- kernel.gz | | `-- linker.hints | |-- loader | |-- loader.conf | `-- lua | |-- cli.lua | |-- color.lua | |-- config.lua | |-- core.lua | |-- drawer.lua | |-- gfx-*.lua | |-- hook.lua | |-- loader.lua | |-- menu.lua | |-- password.lua | `-- screen.lua |-- boot.config `-- mfsroot.gz
boot/loader.conf
provides the configuration for switching to a memory file system
mfs_load="YES" mfs_type="mfs_root" mfs_name="/mfsroot" ahci_load="YES" vfs.root.mountfrom="ufs:/dev/md0"
For a standard build
mfsroot.gz
is about 70MB.
Building a Custom Miniroot
The mfsBSD root image can be modifed to kick off a custom install script. In
the mfsbsd root, modify
conf/rc.local.sample
.
The steps are:
- Find http server and host name from dhclient leases
- Fetch sources
- Fetch install configuration by hostname
- Launch bsdinstall in a tmux session
export PATH=/usr/local/bin:$PATH for op in `awk '/^( | option )(next-server|host-name|domain-name) / { gsub("-", "_", $(NF-1)); print $(NF-1)"="$NF }' /var/db/dhclient.leases.*` do eval "$op" done mkdir /usr/freebsd-dist cd /usr/freebsd-dist for dist in MANIFEST kernel.txz base.txz; do fetch http://${next_server}/pub/freebsd13/usr/freebsd-dist/${dist} done cd - fetch http://${next_server}/bsdinstall/${host_name}.cfg echo "Starting autoinstall" tmux new-session -s autoinstall -d tmux send-keys -t autoinstall:0 "bsdinstall script ${host_name}.cfg" C-m
To build:
cd mfbsd-master make clean-all BASE=/home/eradman/13.2-RELEASE/usr/freebsd-dist make BASE=/home/eradman/13.2-RELEASE/usr/freebsd-dist make iso BASE=/home/eradman/13.2-RELEASE/usr/freebsd-dist
Host Configuration
The installation bootstrap is based into the custom miniroot, but the host configuration is fetched from the installer set by the DHCP option
PARTITIONS="nvd0" export BSDINSTALL_DISTSITE="http://192.168.2.20/pub/freebsd13/usr/freebsd-dist/" export BSDINSTALL_DISTDIR="/usr/freebsd-dist" #!/bin/sh cat >> /etc/rc.conf <<CONF ifconfig_DEFAULT=DHCP sshd_enable=YES ntpd_enable=YES CONF # install packages pkg install -y doas echo "permit keepenv nopass :wheel" > /usr/local/etc/doas.conf chmod 600 /usr/local/etc/doas.conf # configure users pw useradd eradman -m -u 1000 -s /bin/sh -G wheel install -d -o eradman -g eradman -m 700 /home/eradman/.ssh echo "ssh-ed25519 AAAA... eradman@t470s.eradman.com" > /home/eradman/.ssh/authorized_keys chown eradman:eradman /home/eradman/.ssh/authorized_keys echo "rebooting in 10 seconds" sleep 10 reboot