Introduction

In this guide, I will show you how to set up a fully functional network boot system that will allow you to run the Live CD’s and installers of multiple different operating systems, as well as several useful maintenance and repair utilities. No USB drives required!

This guide will assume that you have a working grasp of *NIX system administration, familiarity with common Unix utilities, and the ability to configure a working system via a command line.

Rationale

Booting any given operating system is a fairly simple affair: download an ISO or an image file, flash it to a USB drive, and boot from it. If you have an abundance of ISOs, utilities such as Ventoy and YUMI will let you consolidate them all into a single multiboot USB drive. And if you’re especially exotic, you may have one of iodd's excellent drive enclosures that directly mounts ISOs to a virtual SATA optical drive—​and can even mount fully rewritable VHD images to discrete virtual SATA LUNs—​using the controls on the enclosure itself.

These are all good options, but they all have one common denominator: the requirement of a USB drive. An especially limiting factor if you have lots of systems to work on, but not enough drives for them all!

Last year, I was exposed to network booting for the first time via the excellent FOG Project. And while FOG is geared towards capturing and deploying system images, the experience started me down something of a rabbit hole: wondering if I could take my USB drives full of ISO’s and instead boot them directly off of the network, without needing to constantly dig around for the drives and shuttle them between systems.

The answer, as it turns out, is a resounding "yes"! After lots of experimentation and learning about the network boot abilities of Linux, Windows, and others, I was successful in getting multiple different operating systems to boot over a network connection, exactly as they would via a USB drive.

While this project shares a lot in common with the netboot.xyz project—​and indeed, is able to boot to it—​this project differs in that it operates entirely over a local area network and does not require an Internet connection. As a result, it loads operating systems significantly faster than netboot.xyz does, often at full line speed!

Requirements

Server

To host our netboot infrastructure, we will need a server with a minimum of:

  • A gigabit Ethernet connection or faster

  • Enough storage space for each OS you plan to run

A NAS is ideal for this setup, but common single-board computers such as the Raspberry Pi or similar is sufficient to host the netboot server.

For the server’s operating system, this guide will cover using FreeBSD. While any Linux or BSD distribution should work as well, you will need to adapt the instructions as necessary for your chosen system. If you have managed to get things working on an alternative operating system, feel free to let me know.

Whichever server OS you choose, it will need to host the following services:

  • TFTP

  • NFS

  • DHCP (in ProxyDHCP mode)

  • Samba (optional, for netbooting Windows-based systems)

iPXE will be used as our network boot software of choice, as it can boot a variety of different operating systems and is very easy to write interactive scripts for.

Network

This guide is designed under the assumption that you will not have control over your local area network, such as in an enterprise network or with common residential and SOHO router boxes. Our netboot server will use a ProxyDHCP server—​a separate DHCP server that only responds to PXE clients—​to overcome this restriction.

However, if you do have complete control over your network, such as with OpenWrt, Tomato, IPFire, pfSense, OPNsense, or similar, they will allow you to set your network boot parameters directly. This should be preferred wherever possible.

The vast majority of PXE clients will work perfectly fine with our default ProxyDHCP setup, but there are some very old or buggy PXE clients that will not work correctly with ProxyDHCP. This is especially true if your network’s primary DHCP server sends conflicting or malformed netboot information of it’s own, which certain residential routers are known to do. Sadly, there is no fix in these situations, outside of switching your network infrastructure over to one of the above options.

Client

Each client system you plan to boot from the network must have:

  • An Ethernet connection

  • The ability to network boot on said connection

You can enable network booting in the BIOS settings of your client system if it isn’t already. Consult your system or motherboard manual for directions.

The Ethernet connection can be either USB or PCI; as long as your system’s firmware can boot to it, it does not matter.

You do not need to worry about UEFI or BIOS boot modes, either: this netboot setup can serve both types of boot firmware simultaneously.

Wi-Fi PXE is not supported. Even if your system has support for it in it’s firmware and can successfully boot to iPXE, there is currently no way to maintain that connection once iPXE hands control over to the operating system.

If your system does not have network boot support available, it may be possible to add it into your system by flashing your network card’s boot ROM or installing the UEFI drivers for your network card. Doing so is out of scope for this guide, however.

Server Installation

Other operating systems will be coming soon. Check back later!

FreeBSD

FreeBSD is a stable, resource-friendly, and performant Unix-like system that, by far, has the easiest time serving as our network boot host. Most of the network services required to run our network boot server—​TFTP and NFS in particular—​are already included in the base system and are very easy to configure, and the few additional tools we will need to install are similarly very simple to install and configure as well.

Installing FreeBSD

Download the latest release of FreeBSD and boot to the installer on your chosen server system. The installer is very straightforward, so follow all the on-screen steps to install FreeBSD, and reboot to your new installation.

A default installation onto either ZFS or UFS is sufficient for our purposes. Further tweaking and configuration of your FreeBSD system is out of scope for this document; refer to the FreeBSD Handbook if you have any special requirements.

Once rebooted, log in as root.

Configuring FreeBSD

Install the software we will need for our netboot server.

Run as root:
pkg install dnsmasq ipxe

We will configure the software later.

FreeBSD includes the vi and ee text editors; it’s own download utility fetch as a replacement for wget and curl; and the included tar implementation can extract ZIP and ISO files as-is. If you prefer using a different editor or set of utilities, you may search for and install them now from the package repository as needed.

Configuring Network Services

Before You Begin

This guide will use the directory /netboot to store our network boot data. It is where our TFTP, NFS, and Samba services will all be rooted to.

You may of course use whichever directory you wish, but /netboot is assumed throughout this guide: make sure to alter the instructions as necessary to compensate for your alternative netboot directory!

Create our netboot directory:

Run as root:
mkdir /netboot

If you have a disk you would like to mount to this directory, do so now and update your fstab accordingly, ensuring it is world readable.

We will be editing scripts as well as downloading and extracting the contents of ISO files into this directory, so you may wish to make /netboot writable by a regular user to avoid the need to obtain root access whenever you wish to add more operating systems.

ProxyDHCP

dnsmasq will be used to provide ProxyDHCP service to the network.

Open the dnsmasq configuration file, located in either:

  • /usr/local/etc/dnsmasq.conf (FreeBSD)

  • /etc/dnsmasq.conf (All others)

And populate it with the following lines:

dnsmasq.conf
port=0
log-dhcp
dhcp-no-override
dhcp-range=<ip>,proxy (1)
1 Substitute <ip> with the subnet of your local network, e.g. 192.168.0.0

The last digit of the IP address does not matter: all that matters is that it is part of the same subnet.

If you move your netboot server to a different network, you will need to update this subnet IP appropriately.

TFTP

In almost all circumstances, dnsmasq’s integrated TFTP server is sufficient. Instructions are provided for different TFTP servers in case you wish to use them, but be warned that they will require additional dnsmasq configuration.

dnsmasq TFTP server

Add the following lines to your dnsmasq.conf file:

dnsmasq.conf
enable-tftp
tftp-root=/netboot

FreeBSD TFTP server

FreeBSD’s TFTP server is invoked via inetd, so we will need to configure it appropriately.

Open /etc/inetd.conf in your preferred editor, and search for the TFTP service lines:

/etc/inetd.conf
#tftp	dgram	udp	    wait	root	/usr/libexec/tftpd	tftpd -l -s /tftpboot
#tftp	dgram	udp6	wait	root	/usr/libexec/tftpd	tftpd -l -s /tftpboot

Uncomment the IPv4 line and change the TFTP root to /netboot, such that the service line reads as:

/etc/inetd.conf
tftp	dgram	udp 	wait	root	/usr/libexec/tftpd	tftpd -l -s /netboot

PXE

Add the following lines to your dnsmasq.conf file:

dnsmasq.conf
dhcp-userclass=set:ipxe,iPXE
pxe-prompt=tag:!ipxe,"Press F8 to change iPXE network drivers",3
pxe-service=tag:!ipxe,X86PC,"UNDI driver only",undionly.kpxe
pxe-service=tag:!ipxe,X86PC,"Native iPXE drivers",ipxe.pxe
pxe-service=tag:!ipxe,X86-64_EFI,"SNP driver only",snponly.efi-x86_64
pxe-service=tag:!ipxe,X86-64_EFI,"Native iPXE drivers",ipxe.efi-x86_64
pxe-service=tag:!ipxe,BC_EFI,"SNP driver only",snponly.efi-x86_64
pxe-service=tag:!ipxe,BC_EFI,"Native iPXE drivers",ipxe.efi-x86_64
pxe-service=tag:!ipxe,IA32_EFI,"SNP driver only",snponly.efi-i386
pxe-service=tag:!ipxe,IA32_EFI,"Native iPXE drivers",ipxe.efi-i386
pxe-service=tag:ipxe,X86PC,"iPXE script",autoexec.ipxe
pxe-service=tag:ipxe,X86-64_EFI,"iPXE script",autoexec.ipxe
pxe-service=tag:ipxe,BC_EFI,"iPXE script",autoexec.ipxe
pxe-service=tag:ipxe,IA32_EFI,"iPXE script",autoexec.ipxe

If you’ve chosen to use a different or separate TFTP server, you must add ,<ip> to the end of each pxe-service= directive, where <ip> is the IP address of your TFTP server, such that they look like this example:

pxe-service=tag:!ipxe,X86PC,"UNDI driver only",undionly.kpxe,192.168.0.X

NFS

Next, we will configure NFS.

FreeBSD

Populate /etc/exports with the following:

/etc/exports
/netboot	-alldirs -webnfs
V4: /netboot

Enable Services

Now that our network services are sufficiently configured, it is time to enable them.

FreeBSD

First, enable all of our services:

Run as root:
sysrc dnsmasq_enable="YES"
sysrc rpcbind_enable="YES"
sysrc rpcbind_flags="-s"
sysrc nfs_server_enable="YES"
sysrc nfs_server_flags="-t -u"
sysrc nfsv4_server_enable="YES"
sysrc mountd_enable="YES"
sysrc mountd_flags="-r -S"
sysrc rpc_lockd_enable="YES"
sysrc rpc_statd_enable="YES"
sysrc inetd_enable="YES"       (1)
1 Only if using FreeBSD’s TFTP daemon

And then start the services:

Run as root:
service dnsmasq start
service rpcbind start
service statd start
service lockd start
service mountd start
service nfsd start
service inetd start  (1)
1 Only if using FreeBSD’s TFTP daemon

If any services have failed, recheck their configuration and restart them as appropriate.

iPXE

The stock builds of iPXE from the official project website, unfortunately, lack a few crucial features we need: NFS support being chief among them. We will thus go through the steps of getting a correctly configured version of iPXE installed and made available to our netboot clients.

FreeBSD

The customized FreeBSD version of iPXE available in the repos is preconfigured with all of the extra features we will need.

We installed the iPXE package during our configuration of FreeBSD, which added all the required iPXE executables to /usr/local/share/ipxe. Simply copy the needed files from that directory into /netboot:

Run as root:
cp /usr/local/share/ipxe/ipxe.pxe /netboot
cp /usr/local/share/ipxe/ipxe.efi-i386 /netboot
cp /usr/local/share/ipxe/ipxe.efi-x86_64 /netboot
cp /usr/local/share/ipxe/undionly.kpxe /netboot
cp /usr/local/share/ipxe/snponly.efi-i386 /netboot
cp /usr/local/share/ipxe/snponly.efi-x86_64 /netboot

Writing Initial iPXE Scripts

By itself, iPXE does nothing: it requires a script in order to do anything, and by default, iPXE will attempt to load an autoexec.ipxe script from the root of your TFTP server. We will write this script now.

iPXE scripting is very similar to batch scripting and shell scripting. If you know how to write those, you will have a very easy time writing iPXE scripts.

If you would like to read more about iPXE scripting beyond the scope of this guide, refer to the iPXE documentation.

Create autoexec.ipxe in your /netboot directory with the following content:

/netboot/autoexec.ipxe
#!ipxe
iseq ${platform} efi && dhcp ||
chain --autofree --replace ${cwduri}main.ipxe
exit

All this snippet does is ensure the network is configured correctly before loading our main iPXE script, main.ipxe, over TFTP. We will write this next.

Create main.ipxe in your /netboot directory with the following content to start with:

/netboot/main.ipxe
#!ipxe

# Detect CPU arch
cpuid --ext 29 && set arch x86_64 || set arch i386
# ${platform} either "pcbios" or "efi"

# ${next-server} is TFTP IP
set nfs_path /netboot
set nfs_ip ${next-server}
set nfs_url nfs://${nfs_ip}${nfs_path}

:main_menu
menu Choose an OS:
# To be populated later...
item netbootxyz Boot to netboot.xyz (Internet)
item shell iPXE Shell
choose selection && goto ${selection}

## Menus
# To be populated later...

## Others

:netbootxyz
chain --autofree https://boot.netboot.xyz
goto main_menu

:shell
shell
echo Returning to main menu...
sleep 3
goto main_menu

This basic example does a few things:

  • Detects our CPU architecture

  • Sets NFS variables used throughout the scripts

  • Creates the main menu we will be interacting with

  • Adds a few initial entries to the menu for testing

Testing

At this stage, you have done enough setup to test the network boot system. Grab a computer with an Ethernet connection, plug it in, enable it’s network boot capability (if necessary), and boot it to the network.

If you were successful, you should successfully drop into the iPXE menu! If your testing system has Internet connectivity, you can load directly into netboot.xyz using the given menu option, if desired.

Testing with VirtualBox

You can test the netboot setup using a VirtualBox VM, configured as follows:

  • EFI firmware enabled

  • No disks or ISOs attached

  • Using VirtIO networking

  • Virtual network card bridged to your network connection; not using NAT

Configuring a VM like this will allow it to netboot, allowing you to test the setup quickly and easily.

Netbooting on a non-EFI VM is possible, but the built-in iPXE firmware that Oracle ships with the VirtualBox BIOS implementation does not work correctly, and will freeze if we try to netboot.

If you would like to try anyway, enter the VM settings, uncheck "Enable EFI", check "Network" in the boot order, and switch the network card to a non-VirtIO adapter. Once the VM is started, quickly press Ctrl-B to escape to the iPXE shell when prompted, and execute the following commands:

iPXE shell:
dhcp
chain -ar tftp://${proxydhcp/dhcp-server}/ipxe.pxe (1)
1 Substitute ${proxydhcp/dhcp-server} with ${next-server} or the IP address of your TFTP server if this doesn’t work.

This will boot our netboot server’s iPXE executable, which will allow the VM to netboot correctly.

Adding Operating Systems

Now that your network boot system is finally ready, it’s time to add some operating systems!

Ubuntu (and derivatives)

Installation steps will vary, depending on if you will run the desktop or server live image.

These instructions will assume the latest Ubuntu LTS (24.04.1 as of writing), but any version of Ubuntu will work, provided it has the network drivers for your client system. Make sure to update the directory and file names appropriately!

These instructions will also work the same for Ubuntu spins such as Kubuntu, and derivatives such as Linux Mint and Pop!_OS. Again, make sure to modify the directory and file names as appropriate!

However, for those aforementioned derivatives, the kernel and initrd files may be in different locations and the kernel arguments may be slightly different, so make sure you check the contents of the ISO image and account for any differences!

Desktop

These instructions will use the standard Ubuntu Desktop image, but any of the respins like Kubuntu or Xubuntu will work as well.

Download the latest Ubuntu Desktop and extract the contents to a subdirectory:

Run as root:
mkdir -p /netboot/linux/ubuntu2404desktop
cd /netboot/linux/ubuntu2404desktop
fetch https://releases.ubuntu.com/24.04.1/ubuntu-24.04.1-desktop-amd64.iso
tar xvf ubuntu-24.04.1-desktop-amd64.iso
rm ubuntu-24.04.1-desktop-amd64.iso

And then write a script for it in /netboot/linux/ubuntu2404desktop.ipxe:

/netboot/linux/ubuntu2404desktop.ipxe
#!ipxe

set os_root /linux/ubuntu2404desktop
set os_path ${nfs_path}${os_root}
set os_url ${nfs_url}${os_root}
set os_args boot=casper netboot=nfs BOOTIF=${mac} ip=dhcp root=/dev/nfs nfsroot=${nfs_ip}:${os_path} initrd=initrd.magic
set os_kernel ${os_url}/casper/vmlinuz
set os_initrd ${os_url}/casper/initrd

imgfree
clear menu
menu Ubuntu 24.04.1 Desktop:
item stock Boot with default settings
item vga Boot with safe graphics
item --gap ================================================================================
item goback <= Back
choose --default stock --timeout 3000 which_os && goto ${which_os}

:stock
initrd ${os_initrd}
chain ${os_kernel} ${os_args}
exit 0

:vga
initrd ${os_initrd}
chain ${os_kernel} ${os_args} nomodeset
exit 0

:goback
clear menu
exit 0

Add a menu entry for it in your menu.ipxe file (or a subscript of your choosing):

/netboot/menu.ipxe
:main_menu
menu Choose an OS:
# To be populated later...
iseq ${arch} x86_64 && item ubuntu2404desktop Ubuntu 24.04.1 Desktop || (1)
item netbootxyz Boot to netboot.xyz (Internet)
item shell iPXE Shell
choose selection && goto ${selection}

## Menus
:ubuntu2404desktop                             (1)
chain ${nfs_url}/linux/ubuntu2404desktop.ipxe  (1)
goto main_menu                                 (1)
1 Add these lines to your config.

You should now be able to network boot Ubuntu 24.04 Desktop!

Server

Download the latest Ubuntu Server and extract the contents to a subdirectory:

Run as root:
mkdir -p /netboot/linux/ubuntu2404server
cd /netboot/linux/ubuntu2404server
fetch https://releases.ubuntu.com/24.04.1/ubuntu-24.04.1-live-server-amd64.iso
tar xvf ubuntu-24.04.1-live-server-amd64.iso
rm ubuntu-24.04.1-live-server-amd64.iso

And then write a script for it in /netboot/linux/ubuntu2404server.ipxe:

/netboot/linux/ubuntu2404server.ipxe
#!ipxe

set os_root /os/linux/ubuntu-24.04.1-live-server-amd64
set os_path ${nfs_path}${os_root}
set os_url ${nfs_url}${os_root}
set os_args netboot=nfs BOOTIF=${mac} ip=dhcp root=/dev/nfs nfsroot=${nfs_ip}:${os_path} initrd=initrd.magic
set os_kernel ${os_url}/casper/vmlinuz
set os_initrd ${os_url}/casper/initrd

imgfree
clear menu
menu Ubuntu 24.04.1 Server:
item stock Boot with default settings
item vga Boot with safe graphics
item --gap ================================================================================
item goback <= Back
choose --default stock --timeout 3000 which_os && goto ${which_os}

:stock
initrd ${os_initrd}
chain ${os_kernel} ${os_args}
exit 0

:vga
initrd ${os_initrd}
chain ${os_kernel} ${os_args} nomodeset
exit 0

:goback
clear menu
exit 0

Add a menu entry for it in your menu.ipxe file (or a subscript of your choosing):

/netboot/menu.ipxe
:main_menu
menu Choose an OS:
# To be populated later...
iseq ${arch} x86_64 && item ubuntu2404server Ubuntu 24.04.1 Server || (1)
item netbootxyz Boot to netboot.xyz (Internet)
item shell iPXE Shell
choose selection && goto ${selection}

## Menus
:ubuntu2404server                              (1)
chain ${nfs_url}/linux/ubuntu2404server.ipxe   (1)
goto main_menu                                 (1)
1 Add these lines to your config.

You should now be able to network boot Ubuntu 24.04 Server!

Debian (and derivatives)

Currently, only the live Debian images can be network booted.

The standard Debian installer images will boot, but they will not mount the NFS share, thus falling back to acting as netinstall images and defeating the entire purpose of netbooting them. I am currently investigating how to fix this, and welcome any suggestions!

These instructions will assume the latest version of Debian (12.7 as of writing), but any version of Debian will work, provided it has the network drivers for your client system. Make sure to update the directory and file names appropriately!

These instructions will also work the same for Debian distros such as LMDE and MX Linux. However, kernel and initrd files and boot arguments may be different on these distributions, so make sure you check the ISO contents and adjust as needed!

Live

These instructions will use the live GNOME image of Debian, but any of the live versions will work, including the command-line only 'standard' image.

Download the latest Debian Live image and extract the contents to a subdirectory:

Run as root:
mkdir -p /netboot/linux/debian12gnome
cd /netboot/linux/debian12gnome
fetch https://cdimage.debian.org/debian-cd/current-live/amd64/iso-hybrid/debian-live-12.7.0-amd64-gnome.iso
tar xvf debian-live-12.7.0-amd64-gnome.iso
rm debian-live-12.7.0-amd64-gnome.iso

And then write a script for it in /netboot/linux/debian12gnome.ipxe:

/netboot/linux/debian12gnome.ipxe
#!ipxe

set os_root /linux/debian12gnome
set os_path ${nfs_path}${os_root}
set os_url ${nfs_url}${os_root}
set os_args boot=live components BOOTIF=${mac} ip=dhcp root=/dev/nfs nfsroot=${nfs_ip}:${os_path} initrd=initrd.magic
set os_kernel ${os_url}/live/vmlinuz
set os_initrd ${os_url}/live/initrd.img

imgfree
clear menu
menu Debian Live 12.7.0 amd64 (GNOME):
item stock    Boot with default settings
item failsafe Boot in failsafe mode
item --gap ================================================================================
item goback <= Back
choose --default stock --timeout 3000 which_os && goto ${which_os}

:stock
initrd ${os_initrd}
chain ${os_kernel} ${os_args}
exit 0

:failsafe
initrd ${os_initrd}
chain ${os_kernel} ${os_args} memtest noapic noapm nodma nomce nosmp nosplash vga=788
exit 0

:goback
clear menu
exit 0

Add a menu entry for it in your menu.ipxe file (or a subscript of your choosing):

/netboot/menu.ipxe
:main_menu
menu Choose an OS:
# To be populated later...
iseq ${arch} x86_64 && item debian12gnome Debian 12 Live (GNOME) || (1)
item netbootxyz Boot to netboot.xyz (Internet)
item shell iPXE Shell
choose selection && goto ${selection}

## Menus
:debian12gnome                             (1)
chain ${nfs_url}/linux/debian12gnome.ipxe  (1)
goto main_menu                             (1)
1 Add these lines to your config.

You should now be able to network boot the Debian 12 live system!

Alma/Rocky Linux

Both the installers and live images of Alma/Rocky Linux 8 and 9 are fully bootable over the network.

The setup required for Alma/Rocky Linux 8 and 9 is largely identical, but the kernel arguments differ between the installer and live images.

Installer

This example will use the AlmaLinux 9 DVD image, but the minimal image may be used instead, if desired. Only the names and URLs need to be modified to adapt these instructions to AlmaLinux 8, or the equivalent Rocky Linux releases.

Download the latest AlmaLinux and extract the contents to a subdirectory:

Run as root:
mkdir -p /netboot/linux/alma9install
cd /netboot/linux/alma9install
fetch https://repo.almalinux.org/almalinux/9.4/isos/x86_64/AlmaLinux-9.4-x86_64-dvd.iso
tar xvf AlmaLinux-9.4-x86_64-dvd.iso
rm AlmaLinux-9.4-x86_64-dvd.iso

And then write a script for it in /netboot/linux/alma9install.ipxe:

/netboot/linux/alma9install.ipxe
#!ipxe

set os_root /linux/alma9install
set os_path ${nfs_path}${os_root}
set os_url ${nfs_url}${os_root}
set os_args inst.stage2=nfs:${nfs_ip}:${os_path} inst.repo=nfs:${nfs_ip}:${os_path} initrd=initrd.magic
set os_kernel ${os_url}/images/pxeboot/vmlinuz
set os_initrd ${os_url}/images/pxeboot/initrd.img

imgfree
clear menu
menu AlmaLinux 9 Installer:
item stock    Boot with default settings
item textonly Boot into text mode
item rescue   Boot into rescue mode
item --gap ================================================================================
item goback <= Back
choose --default stock --timeout 3000 which_os && goto ${which_os}

:stock
initrd ${os_initrd}
chain ${os_kernel} ${os_args}
exit 0

:textonly
initrd ${os_initrd}
chain ${os_kernel} ${os_args} inst.text
exit 0

:rescue
initrd ${os_initrd}
chain ${os_kernel} ${os_args} inst.rescue
exit 0

:goback
clear menu
exit 0

Add a menu entry for it in your menu.ipxe file (or a subscript of your choosing):

/netboot/menu.ipxe
:main_menu
menu Choose an OS:
# To be populated later...
iseq ${arch} x86_64 && item alma9install AlmaLinux 9 Installer || (1)
item netbootxyz Boot to netboot.xyz (Internet)
item shell iPXE Shell
choose selection && goto ${selection}

## Menus
:alma9install                             (1)
chain ${nfs_url}/linux/alma9install.ipxe  (1)
goto main_menu                            (1)
1 Add these lines to your config.

You should now be able to network boot the AlmaLinux 9 installer!

Live

This example will use the full AlmaLinux 9 live GNOME image, but any of the available live environments will work. As before, only the names and URLs need to be modified to adapt these instructions to AlmaLinux 8, or the equivalent Rocky Linux releases.

Download the latest AlmaLinux and extract the contents to a subdirectory:

Run as root:
mkdir -p /netboot/linux/alma9live
cd /netboot/linux/alma9live
fetch https://repo.almalinux.org/almalinux/9/live/x86_64/AlmaLinux-9.4-x86_64-Live-GNOME.iso
tar xvf AlmaLinux-9.4-x86_64-Live-GNOME.iso
rm AlmaLinux-9.4-x86_64-Live-GNOME.iso

And then write a script for it in /netboot/linux/alma9live.ipxe:

/netboot/linux/alma9live.ipxe
#!ipxe

set os_root /linux/alma9live
set os_path ${nfs_path}${os_root}
set os_url ${nfs_url}${os_root}
set os_args inst.stage2=nfs:${nfs_ip}:${os_path} inst.repo=nfs:${nfs_ip}:${os_path} initrd=initrd.magic
set os_kernel ${os_url}/images/pxeboot/vmlinuz
set os_initrd ${os_url}/images/pxeboot/initrd.img

imgfree
clear menu
menu AlmaLinux 9 Live (GNOME):
item stock    Boot with default settings
item --gap ================================================================================
item goback <= Back
choose --default stock --timeout 3000 which_os && goto ${which_os}

:stock
initrd ${os_initrd}
chain ${os_kernel} ${os_args}
exit 0

:goback
clear menu
exit 0

Add a menu entry for it in your menu.ipxe file (or a subscript of your choosing):

/netboot/menu.ipxe
:main_menu
menu Choose an OS:
# To be populated later...
iseq ${arch} x86_64 && item alma9live AlmaLinux 9 Live (GNOME) || (1)
item netbootxyz Boot to netboot.xyz (Internet)
item shell iPXE Shell
choose selection && goto ${selection}

## Menus
:alma9live                             (1)
chain ${nfs_url}/linux/alma9live.ipxe  (1)
goto main_menu                         (1)
1 Add these lines to your config.

You should now be able to network boot the AlmaLinux 9 live system!

Arch Linux

Arch Linux is fairly straightforward to network boot.

Download the latest Arch ISO and extract the contents to a subdirectory:

Run as root:
mkdir -p /netboot/linux/archlinux
cd /netboot/linux/archlinux
fetch https://geo.mirror.pkgbuild.com/iso/2024.10.01/archlinux-x86_64.iso
tar xvf archlinux-x86_64.iso
rm archlinux-x86_64.iso

And then write a script for it in /netboot/linux/archlinux.ipxe:

/netboot/linux/archlinux.ipxe
#!ipxe

set os_root /linux/archlinux
set os_path ${nfs_path}${os_root}
set os_url ${nfs_url}${os_root}
set os_args BOOTIF=${mac} ip=dhcp archisobasedir=arch archiso_nfs_srv=${nfs_ip}:${os_path} initrd=initrd.magic
set os_kernel ${os_url}/arch/boot/x86_64/vmlinuz-linux
set os_initrd ${os_url}/arch/boot/x86_64/initramfs-linux.img

imgfree
clear menu
menu Arch Linux:
item stock    Boot with default settings
item noverify Boot without signature verification
item nocopy   Boot in low RAM mode
item nocpver  Boot in low RAM mode & without signature verification
item --gap ================================================================================
item goback <= Back
choose --default stock --timeout 3000 which_os && goto ${which_os}

:stock
initrd ${os_initrd}
chain ${os_kernel} ${os_args} cms_verify=y
exit 0

:noverify
initrd ${os_initrd}
chain ${os_kernel} ${os_args}
exit 0

:nocopy
initrd ${os_initrd}
chain ${os_kernel} ${os_args} copytoram=n cms_verify=y
exit 0

:nocpver
initrd ${os_initrd}
chain ${os_kernel} ${os_args} copytoram=n
exit 0

:goback
clear menu
exit 0

Add a menu entry for it in your menu.ipxe file (or a subscript of your choosing):

/netboot/menu.ipxe
:main_menu
menu Choose an OS:
# To be populated later...
iseq ${arch} x86_64 && item archlinux Arch Linux || (1)
item netbootxyz Boot to netboot.xyz (Internet)
item shell iPXE Shell
choose selection && goto ${selection}

## Menus
:archlinux                             (1)
chain ${nfs_url}/linux/archlinux.ipxe  (1)
goto main_menu                         (1)
1 Add these lines to your config.

You should now be able to network boot into the Arch Linux installer!

Adding Utilities

Beyond just operating systems, you can also network boot a variety of useful system utilities.

UEFI Shells

If your system doesn’t have it’s own UEFI shell, having one available via the network can come in very handy.

This section will cover obtaining both an upstream EDK2 build of the shell, and the patched, widely compatible shell from OpenCore.

Run as root:
mkdir -p /netboot/util/uefishell
cd /netboot/util/uefishell
fetch https://github.com/pbatard/UEFI-Shell/releases/download/24H1/shellia32.efi
fetch https://github.com/pbatard/UEFI-Shell/releases/download/24H1/shellx64.efi
fetch https://github.com/acidanthera/OpenCorePkg/releases/download/1.0.2/OpenCore-1.0.2-RELEASE.zip
tar xvf OpenCore-1.0.2-RELEASE.zip X64/EFI/OC/Tools/OpenShell.efi IA32/EFI/OC/Tools/OpenShell.efi
mv X64/EFI/OC/Tools/OpenShell.efi openshellx64.efi
mv IA32/EFI/OC/Tools/OpenShell.efi openshellia32.efi
rm -r X64 IA32 OpenCore-1.0.2-RELEASE.zip

With the shells downloaded, write an iPXE script /netboot/util/uefishell.ipxe to boot them:

/netboot/util/uefishell.ipxe
#!ipxe

set os_root /util/misc/uefishell
set os_url ${nfs_url}${os_root}

imgfree
clear menu
iseq ${arch} x86_64 && goto menu64 ||
iseq ${arch} i386 && goto menu32 ||
echo Arch not supported, returning...
sleep 2
goto goback

:menu64
menu UEFI Shells (64-bit):
item edk64  EDK2 Shell ||
item open64 OpenCore Shell ||
item --gap ================================================================================
item goback <= Back
choose --default edk64 --timeout 3000 uefishell && goto ${uefishell}

:menu32
menu UEFI Shells (32-bit):
item edk32  EDK2 Shell ||
item open32 OpenCore Shell ||
item --gap ================================================================================
item goback <= Back
choose --default edk32 --timeout 3000 uefishell && goto ${uefishell}

:edk64
chain ${os_url}/shellx64.efi
exit 0

:open64
chain ${os_url}/openshellx64.efi
exit 0

:edk32
chain ${os_url}/shellia32.efi
exit 0

:open32
chain ${os_url}/openshellia32.efi
exit 0

:goback
clear menu
exit 0

Add a menu entry for it in your menu.ipxe file (or a subscript of your choosing):

/netboot/menu.ipxe
:main_menu
menu Choose an OS:
# To be populated later...
iseq ${platform} efi && item uefishell UEFI Shell || (1)
item netbootxyz Boot to netboot.xyz (Internet)
item shell iPXE Shell
choose selection && goto ${selection}

## Menus
:uefishell                             (1)
chain ${nfs_url}/util/uefishell.ipxe   (1)
goto main_menu                         (1)
1 Add these lines to your config.

You should now be able to network boot to a UEFI shell!

rEFInd

rEFInd is a very useful UEFI boot manager that can help you reboot into your OS if your bootloader becomes damaged somehow.

We can load it over PXE as well, but with the small caveat that it will be in text mode, as we cannot load rEFInd’s graphical assets over the network as well. This should not matter, as rEFInd remains perfectly usable in text mode.

Run as root:
mkdir -p /netboot/util/refind
cd /netboot/util/refind
fetch http://sourceforge.net/projects/refind/files/0.14.2/refind-bin-0.14.2.zip
tar xvf refind-bin-0.14.2.zip
rm refind-bin-0.14.2.zip
sed s/#textonly/textonly/ refind-bin-0.14.2/refind/refind.conf-sample > refind-bin-0.14.2/refind/refind.conf-pxe

Now write the iPXE script for rEFInd under /netboot/util/refind.ipxe:

/netboot/util/refind.ipxe
#!ipxe

set os_root /util/refind/refind-bin-0.14.2/refind
set os_url ${nfs_url}${os_root}

imgfree
clear menu
iseq ${arch} x86_64 && goto menu64 ||
iseq ${arch} i386 && goto menu32 ||
echo Arch not supported, returning...
sleep 2
goto goback

:menu64
menu rEFInd (64-bit):
item stock64 Boot with default settings
item drv64 Boot with extra filesystem drivers
item --gap ================================================================================
item goback <= Back
choose --default stock64 --timeout 3000 refind && goto ${refind}

:menu32
menu rEFInd (32-bit):
item stock32 Boot with default settings
item drv32 Boot with extra filesystem drivers
item --gap ================================================================================
item goback <= Back
choose --default stock32 --timeout 3000 refind && goto ${refind}

:stock64
initrd ${os_url}/refind.conf-pxe
chain ${os_url}/refind_x64.efi
exit 0

:drv64
initrd ${os_url}/refind.conf-pxe
initrd ${os_url}/drivers_x64/btrfs_x64.efi
initrd ${os_url}/drivers_x64/ext4_x64.efi
initrd ${os_url}/drivers_x64/hfs_x64.efi
initrd ${os_url}/drivers_x64/iso9660_x64.efi
chain ${os_url}/refind_x64.efi
exit 0

:stock32
initrd ${os_url}/refind.conf-pxe
chain ${os_url}/refind_ia32.efi
exit 0

:drv32
initrd ${os_url}/refind.conf-pxe
initrd ${os_url}/drivers_ia32/btrfs_ia32.efi
initrd ${os_url}/drivers_ia32/ext4_ia32.efi
initrd ${os_url}/drivers_ia32/hfs_ia32.efi
initrd ${os_url}/drivers_ia32/iso9660_ia32.efi
chain ${os_url}/refind_ia32.efi
exit 0

:goback
clear menu
exit 0

Add a menu entry for it in your menu.ipxe file (or a subscript of your choosing):

/netboot/menu.ipxe
:main_menu
menu Choose an OS:
# To be populated later...
iseq ${platform} efi && item refind rEFInd || (1)
item netbootxyz Boot to netboot.xyz (Internet)
item shell iPXE Shell
choose selection && goto ${selection}

## Menus
:refind                             (1)
chain ${nfs_url}/util/refind.ipxe   (1)
goto main_menu                      (1)
1 Add these lines to your config.

You should now be able to network boot rEFInd!

Memtest86+

Memtest86+ is a powerful open-source memory tester for PC’s. It has explicit support for PXE booting, and loading it via iPXE allows us to specify extra command-line options for it, just like in the GRUB distribution of Memtest86+.

Memtest86+ is not to be confused with Memtest86, a commercial product with a very similar name. While the two share a common ancestry and perform a similar function, the commercial Memtest86 requires a $5000 site license in order for it to PXE boot, and will thus not be covered in this guide.

Run as root:
mkdir -p /netboot/util/memtest86
cd /netboot/util/memtest86
fetch https://memtest.org/download/v7.00/mt86plus_7.00.binaries.zip
tar xvf mt86plus_7.00.binaries.zip
rm mt86plus_7.00.binaries.zip

Now write the iPXE script for Memtest86+ under /netboot/util/memtest86.ipxe:

/netboot/util/memtest86.ipxe
#!ipxe

set os_path /util/memtest86
set os_url ${nfs_url}${os_path}

imgfree
clear menu
menu Memtest86+:
item stock Boot with default settings
item newkb Boot with built-in USB keyboard support
item oldkb Boot with legacy BIOS emulation for USB keyboards
item nosmp Boot without SMP & memory detection
item --gap ================================================================================
item back2test <= Back to System Tests
choose --default stock --timeout 3000 mtargs

iseq ${mtargs} back2test && goto back2test ||
iseq ${mtargs} stock     && clear os_args ||
iseq ${mtargs} newkb     && set os_args keyboard=both ||
iseq ${mtargs} oldkb     && set os_args keyboard=legacy ||
iseq ${mtargs} nosmp     && set os_args nosmp nosm nobench ||

iseq ${platform} efi && iseq ${arch} x86_64 && kernel ${os_url}/memtest64.efi ${os_args} ||
iseq ${platform} efi && iseq ${arch} i386 && kernel ${os_url}/memtest32.efi ${os_args} ||
iseq ${platform} pcbios && iseq ${arch} x86_64 && kernel ${os_url}/memtest64.bin ${os_args} ||
iseq ${platform} pcbios && iseq ${arch} i386 && kernel ${os_url}/memtest32.bin ${os_args} ||
chain || goto noarch

:back2test
clear menu
exit 0

:noarch
echo No Memtest86+ version for your architecture. Returning to previous menu...
sleep 2
clear menu
exit 0

Add a menu entry for it in your menu.ipxe file (or a subscript of your choosing):

/netboot/menu.ipxe
:main_menu
menu Choose an OS:
# To be populated later...
item memtest86 Memtest86+              (1)
item netbootxyz Boot to netboot.xyz (Internet)
item shell iPXE Shell
choose selection && goto ${selection}

## Menus
:memtest86                             (1)
chain ${nfs_url}/util/memtest86.ipxe   (1)
goto main_menu                         (1)
1 Add these lines to your config.

You should now be able to network boot Memtest86+!

Future Expansion

Further revisions and additions to this guide will include:

  • Setting up the netboot server on Alma/Rocky Linux

  • Network booting even more systems, including:

    • OpenSUSE

    • Linux Mint

    • Pop!_OS

    • Microsoft Windows installer

    • Hiren’s Boot CD

    • PlopKexec

    • ZFSBootMenu

    • Other miscellaneous utilities

Errata

  • 1.2

    • Metadata edits for Jekyll processing.

  • 1.1 - 2024-12-14

    • Updated copyright to CC-BY.

    • Minor edits and cleanup.

    • Future entries were expanded upon, but remain commented out for the time being.

  • 1.0 - 2024-10-25

    • Initial release