PXE (Preboot Execution Environment) booting allows machines to boot from the network and install an operating system without a physical installation medium. This is invaluable for data centres and labs where provisioning dozens or hundreds of machines manually is impractical. On RHEL 9, you can build a complete PXE infrastructure using TFTP for boot file delivery, DHCP to hand out network boot instructions, and HTTP to serve the installation tree and optional Kickstart automation files.

Prerequisites

  • RHEL 9 server with a static IP address on the provisioning network (e.g., 192.168.1.1)
  • Root or sudo access
  • RHEL 9 installation ISO or mounted installation media
  • Client machines with PXE-capable network cards and PXE enabled in BIOS/UEFI
  • No existing DHCP server on the provisioning subnet (or a coordinated scope)

Step 1 — Install Required Packages

Install the TFTP server, DHCP server, syslinux (provides PXE boot files), and a web server for the installation tree:

dnf install -y tftp-server dhcp-server syslinux httpd
systemctl enable --now tftp.socket httpd

Open the required firewall services:

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

Step 2 — Populate the TFTP Boot Directory

The TFTP server root is /var/lib/tftpboot/. Copy the syslinux PXE loader files and create the required directory structure:

mkdir -p /var/lib/tftpboot/pxelinux.cfg
mkdir -p /var/lib/tftpboot/rhel9

# Copy the PXE bootloader and menu module from syslinux
cp /usr/share/syslinux/pxelinux.0 /var/lib/tftpboot/
cp /usr/share/syslinux/menu.c32   /var/lib/tftpboot/
cp /usr/share/syslinux/mboot.c32  /var/lib/tftpboot/
cp /usr/share/syslinux/chain.c32  /var/lib/tftpboot/

Now mount the RHEL 9 installation ISO and copy the kernel and initial ramdisk:

mount -o loop /path/to/rhel-9-x86_64.iso /mnt

cp /mnt/images/pxeboot/vmlinuz  /var/lib/tftpboot/rhel9/
cp /mnt/images/pxeboot/initrd.img /var/lib/tftpboot/rhel9/

Step 3 — Create the PXE Boot Menu

Create the default boot menu at /var/lib/tftpboot/pxelinux.cfg/default. Clients that do not match a MAC-specific file fall back to this file:

cat > /var/lib/tftpboot/pxelinux.cfg/default << 'EOF'
DEFAULT menu.c32
PROMPT 0
TIMEOUT 300
ONTIMEOUT local

MENU TITLE PXE Boot Menu — RHEL 9 Provisioning

LABEL rhel9-install
  MENU LABEL Install RHEL 9 (Interactive)
  KERNEL rhel9/vmlinuz
  APPEND initrd=rhel9/initrd.img inst.repo=http://192.168.1.1/rhel9 quiet

LABEL rhel9-ks
  MENU LABEL Install RHEL 9 (Automated Kickstart)
  KERNEL rhel9/vmlinuz
  APPEND initrd=rhel9/initrd.img inst.repo=http://192.168.1.1/rhel9 inst.ks=http://192.168.1.1/ks/rhel9.ks quiet

LABEL local
  MENU LABEL Boot from local disk
  LOCALBOOT 0
EOF

Step 4 — Serve the Installation Tree via HTTP

Copy the full installation tree from the ISO to a directory served by Apache:

mkdir -p /var/www/html/rhel9
cp -r /mnt/* /var/www/html/rhel9/
umount /mnt

# Set correct SELinux context on the web root
restorecon -Rv /var/www/html/rhel9/

Create a minimal Kickstart file for automated installs:

mkdir -p /var/www/html/ks

cat > /var/www/html/ks/rhel9.ks << 'EOF'
#version=RHEL9
lang en_US.UTF-8
keyboard us
timezone America/New_York --utc
rootpw --plaintext changeme123
reboot
text
url --url=http://192.168.1.1/rhel9
bootloader --location=mbr
clearpart --all --initlabel
autopart
%packages
@^minimal-environment
%end
EOF

restorecon -Rv /var/www/html/ks/

Step 5 — Configure the DHCP Server

Edit /etc/dhcp/dhcpd.conf to configure the DHCP scope and PXE boot options. The next-server directive points clients to the TFTP server, and filename tells them which bootloader to fetch:

cat > /etc/dhcp/dhcpd.conf << 'EOF'
option domain-name "lab.local";
option domain-name-servers 192.168.1.1;
default-lease-time 600;
max-lease-time 7200;
authoritative;

subnet 192.168.1.0 netmask 255.255.255.0 {
  range 192.168.1.100 192.168.1.200;
  option routers 192.168.1.1;

  # PXE boot settings
  next-server 192.168.1.1;
  filename "pxelinux.0";
}
EOF

systemctl enable --now dhcpd

Verify the DHCP service started cleanly:

systemctl status dhcpd
journalctl -u dhcpd -n 20

Step 6 — Test the PXE Boot

Power on a client machine with PXE boot enabled as the first boot device. It should obtain a DHCP lease, download pxelinux.0 from TFTP, and display the boot menu you defined. Select the installation option to confirm the kernel loads and the installer reaches the repository.

On the server, you can monitor TFTP file requests in real time:

journalctl -u tftp.socket -f

# Check DHCP lease assignments
cat /var/lib/dhcpd/dhcpd.leases

# Verify TFTP is listening on UDP 69
ss -ulnp | grep 69

Conclusion

You have built a complete PXE boot server on RHEL 9 using TFTP, DHCP, syslinux, and Apache. Client machines on the provisioning network can now boot from the network and install RHEL 9 either interactively or fully automated using a Kickstart file. This infrastructure forms the backbone of scalable bare-metal provisioning pipelines.

Next steps: How to Write Advanced Kickstart Files for RHEL 9, How to Configure Chrony as a Time Server on RHEL 9, and How to Set Up a RHEL 9 Satellite Server for Patch Management.