In a previous post, I wrote about the steps I followed to create a Gateway to separate my Home network from my Home Lab network.

In this post, we'll configure a Raspberry Pi (RPi) 4 Model B to PXE Boot from a Synology Diskstation DS720+.

What is PXE Boot?

The Preboot eXecution Environment (PXE) specification describes a standardised client–server environment that boots a software assembly, retrieved from a network, on PXE-enabled clients. - Wikipedia

Clients require a network interface controller (NIC) and utilise DHCP and TFTP.

In data centres, PXE is the most popular choice for operating system booting, installation and deployment.

Synology NAS

The Synology Diskstation DS720+ is running DSM 7.0.1 (DSM 7.0.1-42218 Update 3).

ds-720-

We need to:

  • Configure a Static IP
  • Enable NFS
  • Create some Shared Folders
  • Edit the Shared Folders NFS permissions
  • Enable TFTP
  • Install and configure a DHCP Server
  • Enable PXE Boot
Static IP

In the DSM's Control Panel, click on Network and then select the Network Interface tab:

network-interface

Manual configuration:

network-interface-manual-config

Enable NFS

In the Control Panel, click on File Services and then select the NFS tab:

enable-nfs

Create Shared Folders

We need to create some shared folders for the RPi's Boot and OS files:

  • rpi-pxe (used for the RPi's OS files)
  • rpi-tftpboot (used for the RPi's Boot files)

In the Control Panel, click on Shared Folder:

shared-folder

General configuration, rpi-pxe:

shared-folder-general-config

General configuration, rpi-tftpboot:

shared-folder-general-config-2

And then for each folder (rpi-pxe and rpi-tftpboot) edit the NFS permissions:

nfs-permissions

Enable TFTP

In the Control Panel, click on File Services and then select the Advanced tab:

enable-tftp

DHCP Server

Use the DSM's Package Center to install a DHCP Server. In the DSM's Main Menu click on DHCP Server.

dhcp-network-interface

And then for each Network Interface (LAN 1 and LAN 2) enable the DHCP server:

enable-dhcp-server

We also need to configure the Subnet list:

create-subnet-1

And the Vendor Settings:

dhcp-vendor-settings

There is one more configuration step we need to complete on the DHCP Server, however, we can't do that until we have setup our RPi.

Raspberry Pi

I used the Raspberry Pi Imagr (v1.7.1) to create a fresh install of Raspberry Pi OS Lite 64 bit (a port of Debian Bullseye with no Desktop environment) for my Raspberry Pi 4 Model B 8GB.

I used the Imagr's Advanced options to: set a hostname (relay-node-1); enable SSH (public key only), set a username (ada) and password; set the locale settings and to skip the first-run wizard.

Note: You can use a fully qualified domain name (FQDN), for example: relay-node-1.stake-pool.orcada.io

Then I used SSH to connect to the device and updated the operating system:

sudo apt update
sudo apt full-upgrade

Note: You can use the DHCP Server's DCHP Clients tab to find your RPi's (dynamic) IP address.

Static IP

The Raspberry Pi uses dhcpcd to configure TCP/IP across all of its network interfaces. We want to assign a static IP to our RPi.

Edit the /etc/dhcpcd.conffile:

sudo nano /etc/dhcpcd.conf

And add the following lines to the bottom of the file:

...

# relay-node-1
interface eth0
static ip_address=192.168.101.3/24
static routers=192.168.101.1
static domain_name_servers=192.168.20.1 8.8.8.8

To restart dhcpcd:

sudo systemctl daemon-reload && sudo systemctl restart dhcpcd
Copy the OS files to the rpi-pxe Shared Folder
Create the remote mount point

Connect (SSH) to the Synology NAS, you should see something like:

admin@nas-1:~$

Create a directory in the rpi-pxe shared folder, that matches the RPi's hostname:

cd /volume1/rpi-pxe
sudo mkdir relay-node-1

And update the permissions:

sudo chmod 777 relay-node-1

Note: You can check your RPi's hostname using the following command:

hostname
Create the local mount point

Create a local mount point (directory) that matches the RPi's hostname:

sudo mkdir -p /nfs/relay-node-1

Mount the rpi-pxe shared folder (the remote mount point) with NFS:

sudo mount -t nfs -O proto=tcp,port=2049,rw,all_squash,anonuid=1001,anongid=1001 192.168.101.2:/volume1/rpi-pxe/relay-node-1 /nfs/relay-node-1 -vvv

Copy the OS files

sudo rsync -xa --progress --exclude /nfs / /nfs/relay-node-1/
Copy the Boot files to the rpi-tftpboot Shared Folder
Create the local mount point

Create a local mount point (directory):

sudo mkdir -p /nfs/rpi-tftpboot

Mount the rpi-tftpboot shared folder (the remote mount point) with NFS:

sudo mount -t nfs -O proto=tcp,port=2049,rw,all_squash,anonuid=1001,anongid=1001 192.168.101.2:/volume1/rpi-tftpboot /nfs/rpi-tftpboot -vvv

After mounting the rpi-tftpboot shared folder, the next step is to copy the universal RPi bootcode.bin to the root of the rpi-tftpboot shared folder. bootcode.bin is used by all RPi models and must be in the root of this shared folder for PXE Boot to succeed:

sudo cp /boot/bootcode.bin /nfs/rpi-tftpboot/

Get the RPi's serial number:

vcgencmd otp_dump | grep 28: | sed s/.*://g

You should see something like:

d7cde1e3

Create a directory for the boot files, that matches the RPi's serial number:

sudo mkdir -p /nfs/rpi-tftpboot/d7cde1e3

Copy the boot files:

sudo cp -r /boot/* /nfs/rpi-tftpboot/d7cde1e3/
Boot options

Edit /etc/fstab (the filesystem table) so that it mounts the RPi's tftpboot directory when it starts up:

sudo nano /nfs/relay-node-1/etc/fstab

Update it as follows:

proc            /proc           proc    defaults          0       0
192.168.101.2:/volume1/rpi-tftpboot/d7cde1e3 /boot nfs defaults,vers=3,proto=tcp 0 0

Edit the kernel options in cmdline.txt:

sudo nano /nfs/rpi-tftpboot/d7cde1e3/cmdline.txt

Update it as follows:

console=serial0,115200 console=tty1 root=/dev/nfs nfsroot=192.168.101.2:/volume1/rpi-pxe/relay-node-1,vers=3 rw ip=dhcp elevator=deadline rootwait
eeprom

We need to configure the eeprom to include the PXE boot options. Use the following command to identify the lastest version of the firmware:

ls -al /lib/firmware/raspberrypi/bootloader/stable/

Copy the lastest version of the firmware to a temporary directory in your home directory:

sudo cp /lib/firmware/raspberrypi/bootloader/stable/pieeprom-2022-03-10.bin pieeprom.bin

Create a boot configuration file:

sudo nano bootconf.txt

Update it as follows:

[all]
BOOT_UART=0
WAKE_ON_GPIO=1
POWER_OFF_ON_HALT=0
DHCP_TIMEOUT=45000
DHCP_REQ_TIMEOUT=4000
TFTP_FILE_TIMEOUT=30000
TFTP_IP=192.168.101.2
TFTP_PREFIX=0
ENABLE_SELF_UPDATE=1
DISABLE_HDMI=0
BOOT_ORDER=0x241
SD_CARD_MAX_RETRIES=3
NET_BOOT_MAX_RETRIES=5

The RPi will try to boot from a microSD card, then the network, then from any attached USB storage.

Now we can create a new eeprom binary:

sudo rpi-eeprom-config --out pieeprom-new.bin --config bootconf.txt pieeprom.bin

And write it to the eeprom:

sudo rpi-eeprom-update -d -f ./pieeprom-new.bin

Reboot (leave the microSD card inserted):

sudo reboot

Check the new boot configuration values using the following command:

vcgencmd bootloader_config

Synology NAS

Enable PXE Boot

There is one more configuration step we need to complete on the DHCP Server, and that is to enable PXE Boot:

enable-pxe

PXE Boot

Shutdown the RPi:

sudo shutdown -h now

Turn off the power, remove the microSD card, turn the power back on. The RPi should now PXE boot.

Connect (SSH) to the RPi and check the mounted filesytems:

findmnt

You should see something like:

Troubleshooting

If you run into any issues try plugging in a monitor:

output-1

A coloured splash screen (actually it's just four pixels "blown up" by the GPU to full screen) is displayed after the GPU firmware (start.elf) is loaded:

output-2

This should be replaced by the linux console a few seconds later:

output-3

Resources:
References: