Skip to main content

PXE (Preboot eXecution Environment)

Environment

Field Spec or Version
CPU QEMU Virtual CPU version 2.5+ (2 Cores)
RAM 2G
OS Rocky Linux 10.0 (Red Quartz)
Network interface ens18 with static IP 192.168.3.11/24
DNS 192.168.3.1 (Private DNS Server)

Package Installation

dnf install -y syslinux syslinux-tftpboot dnsmasq nfs-utils exportfs rsync

Package Configuration

  • Mount Ubuntu Live Iso

    export ISO_MP='/media/iso'
    mkdir -p "$ISO_MP"
    mount /dev/sr0 "$ISO_MP"
    
  • /etc/dnsmasq.conf

    # Listen on this specific port instead of the standard DNS port
    # (53). Setting this to zero completely disables DNS function,
    # leaving only DHCP and/or TFTP.
    port=0
    
    # If you want dnsmasq to listen for DHCP and DNS requests only on
    # specified interfaces (and the loopback) give the name of the
    # interface (eg eth0) here.
    # Repeat the line for more than one interface.
    interface=ens18
    
    # Uncomment this to enable the integrated DHCP server, you need
    # to supply the range of addresses available for lease and optionally
    # a lease time. If you have more than one network, you will need to
    # repeat this for each network on which you want to supply DHCP
    # service.
    dhcp-range=192.168.3.200,192.168.3.250,12h
    
    # Override the default route supplied by dnsmasq, which assumes the
    # router is the same machine as the one running dnsmasq.
    # Do the same thing, but using the option name
    dhcp-option=option:router,192.168.3.1
    dhcp-option=option:dns-server,192.168.3.1
    
    # Set the boot filename for netboot/PXE. You will only need
    # this if you want to boot machines over the network and you will need
    # a TFTP server; either dnsmasq's built-in TFTP server or an
    # external one. (See below for how to enable the TFTP server.)
    dhcp-boot=syslinux.efi
    
    # Enable dnsmasq's built-in TFTP server
    enable-tftp
    
    # Set the root directory for files available via FTP.
    tftp-root=/var/tftp
    
    # Log lots of extra information about DHCP transactions.
    log-dhcp
    
  • Init TFTP server provided by dnsmasq

    TFTP only provides basic files for PXE, like bootloader, boot menu, and initrd entry.

    export TFTP_PATH='/var/tftp'
    mkdir -p "$TFTP_PATH"
    
    # PXE bootloader
    # Alter: copy these files from Ubuntu distro if files from rocky failed.
    cp /tftpboot/efi64/syslinux.efi "$TFTP_PATH"
    cp /tftpboot/efi64/ldlinux.e64 "$TFTP_PATH"
    
    # PXE boot menu
    mkdir "$TFTP_PATH/pxelinux.cfg"
    cat > "$TFTP_PATH/pxelinux.cfg/default" <<'EOF'
    DEFAULT ubuntu
    
    LABEL ubuntu
      KERNEL ubuntu/vmlinuz
      INITRD ubuntu/initrd
      APPEND boot=casper netboot=nfs nfsroot=192.168.3.11:/srv/ubuntu-live ip=dhcp ---
    
    EOF
    
    # PXE boot option1 - Ubuntu
    export TFTP_UBUNTU_PATH="$TFTP_PATH/ubuntu"
    mkdir -p "$TFTP_UBUNTU_PATH"
    cp "$ISO_MP/casper/initrd" "$TFTP_UBUNTU_PATH"
    cp "$ISO_MP/casper/vmlinuz" "$TFTP_UBUNTU_PATH"
    
    chown -R dnsmasq: "$TFTP_PATH"
    chcon -R -t tftpdir_t "$TFTP_PATH"
    
  • Init NFS server

    NFS provides actual live OS because OS files is too large to TFTP for transfer. TFTP only transfer files with max size about 100M stably.

    export NFS_UBUNTU_PATH='/srv/ubuntu-live'
    mkdir -p "$NFS_UBUNTU_PATH"
    rsync -a "$ISO_MP/" "$NFS_UBUNTU_PATH/"
    chcon -R -t nfs_t "$NFS_UBUNTU_PATH"
    
    cat >> /etc/exports <<EOF
    $NFS_UBUNTU_PATH *(ro,sync,no_subtree_check)
    EOF
    
  • Unmount Ubuntu Live Iso

    umount "$ISO_MP"
    rmdir "$ISO_MP"
    

Final Checks

  • tree "$TFTP_PATH"

    /var/tftp
    โ”œโ”€โ”€ ldlinux.e64
    โ”œโ”€โ”€ pxelinux.cfg
    โ”‚ย ย  โ””โ”€โ”€ default
    โ”œโ”€โ”€ syslinux.efi
    โ””โ”€โ”€ ubuntu
        โ”œโ”€โ”€ initrd
        โ””โ”€โ”€ vmlinuz
    
    3 directories, 5 files
    
  • tree -L 2 "$NFS_UBUNTU_PATH"

    /srv/ubuntu-live
    โ”œโ”€โ”€ boot
    โ”‚ย ย  โ”œโ”€โ”€ grub
    โ”‚ย ย  โ””โ”€โ”€ memtest86+x64.bin
    โ”œโ”€โ”€ boot.catalog
    โ”œโ”€โ”€ casper
    โ”‚ย ย  โ”œโ”€โ”€ filesystem.manifest
    โ”‚ย ย  โ”œโ”€โ”€ filesystem.size
    โ”‚ย ย  โ”œโ”€โ”€ initrd
    โ”‚ย ย  โ”œโ”€โ”€ install-sources.yaml
    โ”‚ย ย  โ”œโ”€โ”€ ubuntu-server-minimal.manifest
    โ”‚ย ย  โ”œโ”€โ”€ ubuntu-server-minimal.size
    โ”‚ย ย  โ”œโ”€โ”€ ubuntu-server-minimal.squashfs
    โ”‚ย ย  โ”œโ”€โ”€ ubuntu-server-minimal.squashfs.gpg
    โ”‚ย ย  โ”œโ”€โ”€ ubuntu-server-minimal.ubuntu-server.installer.generic.manifest
    โ”‚ย ย  โ”œโ”€โ”€ ubuntu-server-minimal.ubuntu-server.installer.generic.size
    โ”‚ย ย  โ”œโ”€โ”€ ubuntu-server-minimal.ubuntu-server.installer.generic.squashfs
    โ”‚ย ย  โ”œโ”€โ”€ ubuntu-server-minimal.ubuntu-server.installer.generic.squashfs.gpg
    โ”‚ย ย  โ”œโ”€โ”€ ubuntu-server-minimal.ubuntu-server.installer.manifest
    โ”‚ย ย  โ”œโ”€โ”€ ubuntu-server-minimal.ubuntu-server.installer.size
    โ”‚ย ย  โ”œโ”€โ”€ ubuntu-server-minimal.ubuntu-server.installer.squashfs
    โ”‚ย ย  โ”œโ”€โ”€ ubuntu-server-minimal.ubuntu-server.installer.squashfs.gpg
    โ”‚ย ย  โ”œโ”€โ”€ ubuntu-server-minimal.ubuntu-server.manifest
    โ”‚ย ย  โ”œโ”€โ”€ ubuntu-server-minimal.ubuntu-server.size
    โ”‚ย ย  โ”œโ”€โ”€ ubuntu-server-minimal.ubuntu-server.squashfs
    โ”‚ย ย  โ”œโ”€โ”€ ubuntu-server-minimal.ubuntu-server.squashfs.gpg
    โ”‚ย ย  โ””โ”€โ”€ vmlinuz
    โ”œโ”€โ”€ dists
    โ”‚ย ย  โ”œโ”€โ”€ noble
    โ”‚ย ย  โ”œโ”€โ”€ stable -> noble
    โ”‚ย ย  โ””โ”€โ”€ unstable -> noble
    โ”œโ”€โ”€ EFI
    โ”‚ย ย  โ””โ”€โ”€ boot
    โ”œโ”€โ”€ install
    โ”œโ”€โ”€ md5sum.txt
    โ”œโ”€โ”€ pool
    โ”‚ย ย  โ”œโ”€โ”€ main
    โ”‚ย ย  โ””โ”€โ”€ restricted
    โ””โ”€โ”€ ubuntu -> .
    
    15 directories, 24 files
    

Service Restart

firewall-cmd --permanent --add-service=dhcp
firewall-cmd --permanent --add-service=tftp

# NFS
firewall-cmd --permanent --add-service=nfs
firewall-cmd --permanent --add-service=rpc-bind
firewall-cmd --permanent --add-service=mountd

firewall-cmd --reload

systemctl enable --now dnsmasq
systemctl restart dnsmasq

exportfs -ra
systemctl enable --now nfs-server
systemctl restart nfs-server

Create another PXE client

  • No disk or disc required for PXE boot
  • Enable PXE boot

Screenshot_20250901_063029.png

Screenshot_20250901_065424-1.png

Screenshot_20250901_063926.png

Troubleshoot

If your PXE client stucks at UEFI boot, your files in /var/tftp/ are possibly bad.

The Syslinux EFI implementation is incomplete/buggy in many RHEL/Fedora/Rocky builds, so you can copy them from Ubuntu repo directly.

Screenshot_20250901_061949.png