I’d like to start setting up a PXE boot environment for Raspberry Pis on my network. Essentially, I should be able to boot a Raspberry just by plugging in the Ethernet cable and the power cable, and if everything is set up properly, the thing will boot with NO LOCAL MEDIA–no SD card, no USB drives, or no NVMe HAT!
The first part of this will be setting up a server that will provide NFS and TFTP. The NFS will offer the /root partition to each of the Raspberries that boot from it. The TFTP will provide the /boot partition files that make up the bootstrap files that get the Raspberry running enough to load the files in the /root partition and start running what looks like LINUX!
The magic is setting up DHCP to tell the Raspberry, “Here’s your IP address, and oh, by the way, here’s where to find your boot files on the network (since you can’t find your SD card to boot from!”
I’ll start by setting up the file server. Let’s call it “boots”. I’m going to store my files on a 60GB USB drive. Using lsblk, I can confirm that the Raspberry sees it:
root@boots:~# lsblk NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT sda 8:0 1 28.7G 0 disk ├─sda1 8:1 1 256M 0 part /boot └─sda2 8:2 1 28.4G 0 part / sdb 8:16 1 60M 0 disk
Let’s create a partition on it:
root@boots:~# fdisk /dev/sdb Welcome to fdisk (util-linux 2.36.1). Changes will remain in memory only, until you decide to write them. Be careful before using the write command. Command (m for help): p Disk /dev/sdb: 60 MiB, 62914560 bytes, 122880 sectors Disk model: Flash-Disk Units: sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes Disklabel type: gpt Disk identifier: 29EC7820-7E2F-4FD1-BE65-A55AE0A971EE Command (m for help): n Partition number (1-128, default 1): 1 First sector (34-122846, default 2048): <<enter>> Last sector, +/-sectors or +/-size{K,M,G,T,P} (2048-122846, default 122846): <<enter>> Created a new partition 1 of type 'Linux filesystem' and of size 59 MiB. Command (m for help): p Disk /dev/sdb: 60 MiB, 62914560 bytes, 122880 sectors Disk model: Flash-Disk Units: sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes Disklabel type: gpt Disk identifier: 29EC7820-7E2F-4FD1-BE65-A55AE0A971EE Device Start End Sectors Size Type /dev/sdb1 2048 122846 120799 59M Linux filesystem Command (m for help): w The partition table has been altered. Calling ioctl() to re-read partition table. Syncing disks. root@boots:~#
Once the partition is in place, we can format it:
root@boots:~# mkfs /dev/sdb1 mke2fs 1.46.2 (28-Feb-2021) Creating filesystem with 60396 1k blocks and 15104 inodes Filesystem UUID: ae5309bc-7958-4cda-8d3e-7b701f0080d8 Superblock backups stored on blocks: 8193, 24577, 40961, 57345 Allocating group tables: done Writing inode tables: done Writing superblocks and filesystem accounting information: done root@boots:~#
Next step, create a mount point and mount the new drive.
root@boots:~# mkdir /data1 root@boots:~# mount /dev/sdb1 /data1 root@boots:~# df -h Filesystem Size Used Avail Use% Mounted on /dev/root 28G 4.0G 23G 15% / devtmpfs 1.7G 0 1.7G 0% /dev tmpfs 1.9G 16K 1.9G 1% /dev/shm tmpfs 759M 868K 758M 1% /run tmpfs 5.0M 4.0K 5.0M 1% /run/lock /dev/sda1 253M 30M 223M 12% /boot rock:/data/clusterfs 19T 13T 5.3T 72% /work tmpfs 380M 16K 380M 1% /run/user/0 /dev/sdb1 56M 14K 54M 1% /data1 root@boots:~#
OK! Look good. We’ve got a 54M /data1 partition to share our PXE files. (Don’t forget to add that to /etc/fstab so it’s still there after a reboot!)
Next, we’ll need to install some software:
apt install -y nfs-kernel-server
Let’s keep the configuration simple for the time being. If we decide to keep this, we can tighten up security later. I just like to make sure everything works first. Add a line to /etc/exports:
/data1 *(rw,sync,no_subtree_check,no_root_squash)
This line is very powerful! NO SPACE between the * and the (. Of all the troubleshooting to get this to work, NFS gave me the most issues!
Enable and start the NFS server
With the packages installed and the directory added to your /etc/fstab file, you can now start the NFS server.
sudo systemctl enable nfs-server.service sudo systemctl start nfs-server.service
Let’s jump on another Raspberry to make sure this is working:
root@node01:~# mount boots:/data1 /mnt root@node01:~# df -h Filesystem Size Used Avail Use% Mounted on /dev/root 28G 4.9G 22G 19% / devtmpfs 326M 0 326M 0% /dev tmpfs 455M 140K 455M 1% /dev/shm tmpfs 182M 820K 182M 1% /run tmpfs 5.0M 4.0K 5.0M 1% /run/lock /dev/sda1 253M 30M 223M 12% /boot rock:/data/clusterfs 19T 13T 5.3T 72% /work tmpfs 91M 24K 91M 1% /run/user/1000 tmpfs 91M 16K 91M 1% /run/user/0 boots:/data1 28G 4.0G 23G 15% /mnt
Yep, it mounts! The Size is a little suspicious. Let’s move along for now, but I’m keeping my eye on that volume size!
Next, a tftp server for the boot files!
Thx John! In order to mount the share on the client, it needs ‘nfs-common’ package installed (at least in Debian 11).