Technologies like PXE (Preboot Execution Environment) and its open-source implementation iPXE are essential for managing multiple machines or deploying operating systems at scale (e.g., in a data centre).

PXE Boot Chain

  • NIC with PXE Firmware
  • BIOS capable of booting from NIC
  • DHCP with options 66 and 67
  • TFTP server with NBP
  • and so on.

DHCP option 66 (“next server”) specifies the address of the TFTP server, and option 67 (“bootfile name”) specifies the NBP (Network Bootstrap Program). For example, 66 set to 10.1.1.1 and 67 set to pxelinux.0.

The chain is necessary because the NBP must be very small, as it is a pre-boot program designed to fetch and load the target system.

The OS installer can be served from the same TFTP server or shared via HTTP, NFS, or SMB.

Note: The DHCP, TFTP, and HTTP servers can run on the same host or on different ones. For example, DHCP could be handled by a network appliance such as a Cisco router, TFTP by a NAS, and HTTP by any machine on the LAN or the Internet.


INDEX

  • Installing
    • DHCP Server
    • TFTP Server
    • HTTP Server
  • Configuring
    • NAT / Routing
    • PXE Boot
    • iPXE Boot
  • PXE the Easy Way
  • Auto Install
    • Ubuntu Server

INSTALLING PACKAGES

apt update && apt upgrade -y
apt install isc-dhcp-server tftpd-hpa pxelinux syslinux-common -y

If you see an error message immediately after installation, that is expected. The DHCP service failed to start because another DHCP server is already active on the same network segment.


DHCP SERVER

Specify the network interface the DHCP service should bind to.

nano /etc/default/isc-dhcp-server

Define the parameters to be assigned to the client’s network adapter.

nano /etc/dhcp/dhcpd.conf
subnet 10.1.1.0 netmask 255.255.255.0 {
  range 10.1.1.100 10.1.1.200;
  option routers 10.1.1.1;
  option broadcast-address 10.1.1.255;
  option domain-name-servers 1.1.1.1;
  next-server 10.1.1.1; 
  filename "pxelinux.0";
}

Note: In this example, the DHCP and TFTP servers are the same host. If running TFTP on a different server, update the next-server IP accordingly.

Apply the changes.

systemctl restart isc-dhcp-server
systemctl enable isc-dhcp-server

The equivalent commands to set options 66 and 67 on a Ubiquiti EdgeRouter are:

$ configure
# show service dhcp-server
# set service dhcp-server shared-network-name LAN subnet 10.1.1.0/24 bootfile-name pxelinux.0
# set service dhcp-server shared-network-name LAN subnet 10.1.1.0/24 tftp-server-name 10.1.1.1
# commit
# save

This is what the DHCP offer looks like in a packet capture.

It can also be observed using the Nmap script broadcast-dhcp-discover.

nmap --script broadcast-dhcp-discover


TFTP SERVER

By default, the TFTP server root directory is /srv/tftp/. Netboot images need to be placed there.

Debian 12 Netboot

mkdir -p /srv/tftp/debian
cd /srv/tftp/debian
wget http://deb.debian.org/debian/dists/bookworm/main/installer-amd64/current/images/netboot/debian-installer/amd64/linux
wget http://deb.debian.org/debian/dists/bookworm/main/installer-amd64/current/images/netboot/debian-installer/amd64/initrd.gz

PXE Boot with TFTP-HPA

cd /srv/tftp/
cp /usr/lib/PXELINUX/pxelinux.0
cp /usr/lib/syslinux/modules/bios/menu.c32
cp /usr/lib/syslinux/modules/bios/ldlinux.c32
cp /usr/lib/syslinux/modules/bios/libutil.c32
mkdir -p /srv/tftp/pxelinux.cfg
nano /srv/tftp/pxelinux.cfg/default
DEFAULT menu.c32
PROMPT 0
MENU TITLE PXE Boot Menu
TIMEOUT 50

LABEL debian
    MENU LABEL Install Debian 12
    KERNEL debian/linux
    APPEND initrd=debian/initrd.gz

Apply the configuration.

systemctl restart tftpd-hpa
systemctl enable tftpd-hpa

Use the Nmap script tftp-enum.nse to test the TFTP service.

nmap -sU -p 69 --script tftp-enum.nse 10.1.1.1

PXE Boot with Dnsmasq (alternative to TFTP-HPA)

Dnsmasq provides DNS, DHCP, and TFTP in a single daemon.

Installation and configuration.

apt remove --purge tftpd-hpa -y
apt install dnsmasq -y
nano /etc/dnsmasq.d/pxe.conf
#port=0                                              # Disable DNS
enable-tftp                                          # Enable TFTP
tftp-root=/srv/tftp
dhcp-boot=pxelinux.0
pxe-service=x86PC, "Boot from network", pxelinux
log-queries                                          # Logging
log-facility=/var/log/dnsmasq.log
interface=eth1                                       # Bind only to vmbr1 interface
except-interface=lo
bind-interfaces
dhcp-range=10.1.1.100,10.1.1.200,12h                 # DHCP pool
dhcp-option=3,10.1.1.1                               # Default gateway
dhcp-option=6,10.1.1.1                               # DNS server
systemctl restart dnsmasq

INTERNET ACCESS

Since a netinstall requires Internet access to fetch packages, the PXE boot server needs to perform NAT.

echo "net.ipv4.ip_forward=1" >> /etc/sysctl.d/99-ipforward.conf
sysctl -p /etc/sysctl.d/99-ipforward.conf
nano /etc/nftables.conf
#!/usr/sbin/nft -f
table ip nat {
    chain prerouting {
        type nat hook prerouting priority 0;
    }
    chain postrouting {
        type nat hook postrouting priority 100;
        oifname "eth0" masquerade
    }
}
systemctl restart nftables
nft list ruleset

SERVING ISO FILES ON LAN

It is also possible to boot from an ISO over the network via HTTP or NFS.

HTTP

Install Nginx and get iPXE.

apt install nginx -y
mkdir -p /srv/tftp/ipxe
cd /srv/tftp/ipxe
wget https://boot.ipxe.org/ipxe.lkrn
mkdir -p /var/www/html/ipxe
cd /var/www/html/ipxe
cp /usr/lib/syslinux/memdisk .
cp /usr/lib/syslinux/modules/bios/sanboot.c32 .
nano boot.ipxe
#!ipxe

menu iPXE Boot Menu
item ubuntu Ubuntu ISO 
item shell iPXE Shell
choose distro && goto ${distro}

:ubuntu
sanboot http://releases.ubuntu.com/noble/ubuntu-24.04.2-live-server-amd64.iso
#kernel http://10.1.1.1/isos/linux ip=dhcp url=http://releases.ubuntu.com/noble/ubuntu-24.04.2-live-server-amd64.iso
#initrd http://10.1.1.1/isos/initrd.gz
#boot

:shell
shell

Note: The memdisk lines are commented out due to its memory limit of around 700 MB. Use sanboot instead, which handles larger ISO files up to 2 GB.

Get the ISOs.

mkdir -p /var/www/html/isos
cd /var/www/html/isos
wget https://releases.ubuntu.com/24.04/netboot/amd64/initrd -O initrd.gz
wget https://releases.ubuntu.com/24.04/netboot/amd64/linux

Create the chain: PXELINUX + iPXE.

nano /srv/tftp/pxelinux.cfg/default

Append the following block.

LABEL iPXE Boot
    MENU LABEL Boot using iPXE
    KERNEL ipxe/ipxe.lkrn
    APPEND dhcp && chain http://10.1.1.1/ipxe/boot.ipxe

PXE BOOT THE EASY WAY

NetBoot.xyz [Link]

Set DHCP option 67 to netboot.xyz.kpxe.

A single-line Docker deployment makes this even simpler.

docker run -d --name=netbootxyz -p 3000:3000 -p 8080:80 -p 69:69/udp -v /srv/config:/config -v /srv/assets:/assets --restart unless-stopped ghcr.io/netbootxyz/netbootxyz

Ports exposed:

  • 3000 Dashboard
  • 8080 Assets (ISOs)
  • 69/udp TFTP (NBP and configs)

Navigate to the dashboard at http://10.1.1.1:3000/.

LinuxServer.io [Link]

(pending)

iVentoy [Link]

(pending)


UBUNTU AUTO INSTALL

In the iPXE configuration, set the following.

kernel http://10.1.1.1/vmlinuz root=/dev/ram0 ramdisk_size=3500000 cloud-config-url=/dev/null autoinstall ds=nocloud;s=http://10.1.1.1 ip=dhcp url=http://10.1.1.1/ubuntu.iso initrd=initrd.magic
initrd http://10.1.1.1/initrd

Then create the necessary files.

touch meta-data
touch vendor-data
nano user-data

Add the following content, adjusting the parameters as needed.

#cloud-config
autoinstall:
  version: 1
  refresh-installer:
    update: true
    channel: latest/stable
  apt:
    disable_components: []
    fallback: abort
  mirror-selection:
    geoip: true
  packages:
    - htop
    - curl
    - nano
    - iputils-ping
    - qemu-guest-agent
  drivers:
    install: true
  refresh-installer:
    channel: stable
    update: yes
  storage:
    layout:
      name: direct
  user-data:
    disable_root: false
  identity:
    hostname: ubuntu-server
    realname: ubuntu
    username: ubuntu
    password: "$y$...password...hash"
  kernel:
    package: linux-generic
  keyboard:
    layout: us
    toggle: null
    variant: ''
  locale: en_US.UTF-8
  network:
    version: 2
    renderer: networkd
    ethernets:
        alleths:
            match:
                name: e*
            dhcp4: true
  oem:
    install: auto
  source:
    id: ubuntu-server-minimal
    search_drivers: true
  ssh:
    install-server: true
    allow-pw: true
    authorized-keys:
      - "id_rsa AAAAA"
  updates: security
  timezone: America/Toronto
  late-commands:
    - curtin in-target -- apt update
    - curtin in-target -- apt upgrade -y

BONUS

As an alternative to the well-known Ventoy [Link], check out Aegis-Boot [Link], a signed UEFI Secure Boot rescue environment.