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.