PXE (Preboot eXecution Environment) boot lets you install an operating system over the network without a physical USB drive or DVD. On RHEL 8 this capability is built from three cooperating services: a DHCP server that hands out IP addresses and points new clients to the boot server, a TFTP server that delivers the initial bootloader, and an HTTP or NFS server that hosts the installation tree. This tutorial builds all three layers on a single RHEL 8 host so that any bare-metal machine or virtual machine on your LAN can boot and install automatically.
Prerequisites
- RHEL 8 server with a static IP (example:
192.168.1.5) and internet access - Root or
sudoaccess - A RHEL 8 or CentOS Stream 8 ISO image available locally
- A test VM or spare machine configured to boot from the network first
- Basic familiarity with
firewall-cmd,systemctl, andvi
Step 1 — Install Required Packages
Install the TFTP server, DHCP server, Syslinux bootloader files, and the Apache HTTP server to serve the OS image tree.
dnf install -y tftp-server syslinux dhcp-server httpd
systemctl enable --now tftp.socket httpd
The TFTP service on RHEL 8 is socket-activated via tftp.socket; enabling the socket unit is sufficient — tftp.service launches on demand when a client connects. Apache will serve the OS installation tree over HTTP on port 80.
Step 2 — Populate the TFTP Boot Directory
Copy the Syslinux PXE bootloader and its dependencies into the TFTP root, then create the configuration directory.
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/
mkdir -p /var/lib/tftpboot/pxelinux.cfg
Next, mount the RHEL 8 ISO and copy the kernel and initrd into the TFTP tree, then expose the full installation tree over HTTP.
mount -o loop /path/to/rhel-8-x86_64.iso /mnt
# Kernel and initrd for the PXE menu
mkdir -p /var/lib/tftpboot/rhel8
cp /mnt/images/pxeboot/vmlinuz /var/lib/tftpboot/rhel8/
cp /mnt/images/pxeboot/initrd.img /var/lib/tftpboot/rhel8/
# Full OS tree for the installer
mkdir -p /var/www/html/rhel8
cp -r /mnt/* /var/www/html/rhel8/
umount /mnt
restorecon -Rv /var/lib/tftpboot/
restorecon -Rv /var/www/html/rhel8/
Step 3 — Create the PXE Boot Menu
Create /var/lib/tftpboot/pxelinux.cfg/default with a menu entry that points the installer at your HTTP server.
cat > /var/lib/tftpboot/pxelinux.cfg/default << 'EOF'
DEFAULT menu.c32
PROMPT 0
TIMEOUT 300
ONTIMEOUT RHEL8
MENU TITLE PXE Boot Menu
LABEL RHEL8
MENU LABEL Install RHEL 8
KERNEL rhel8/vmlinuz
APPEND initrd=rhel8/initrd.img ip=dhcp inst.repo=http://192.168.1.5/rhel8 quiet
EOF
Replace 192.168.1.5 with your server’s actual static IP. For an unattended install, append inst.ks=http://192.168.1.5/ks.cfg to the APPEND line and place a Kickstart file at /var/www/html/ks.cfg.
Step 4 — Configure the DHCP Server
Edit /etc/dhcp/dhcpd.conf so that DHCP responses include the PXE boot server address and the bootloader filename.
cat > /etc/dhcp/dhcpd.conf << 'EOF'
option domain-name-servers 8.8.8.8;
default-lease-time 600;
max-lease-time 7200;
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;
option subnet-mask 255.255.255.0;
# PXE boot directives
next-server 192.168.1.5;
filename "pxelinux.0";
}
EOF
systemctl enable --now dhcpd
Verify the service started without errors with systemctl status dhcpd. If another DHCP server is already running on the network, consult your network administrator before enabling this one to avoid IP conflicts.
Step 5 — Open Firewall Ports
Allow DHCP (UDP 67/68), TFTP (UDP 69), and HTTP (TCP 80) through the firewall.
firewall-cmd --add-service=dhcp --permanent
firewall-cmd --add-service=tftp --permanent
firewall-cmd --add-service=http --permanent
firewall-cmd --reload
firewall-cmd --list-services
Step 6 — Test PXE Boot with a Client VM
Create a new virtual machine in KVM/QEMU or VirtualBox, set the NIC to bridge mode on the same subnet (192.168.1.0/24), and configure the boot order to prefer the network interface. Power on the VM and watch for the PXE menu to appear after the DHCP lease is granted.
# On the PXE server: watch DHCP lease activity in real time
journalctl -u dhcpd -f
# Confirm TFTP requests are being served
journalctl -u tftp.service -f
# Check Apache access log for installer tree requests
tail -f /var/log/httpd/access_log
If the VM gets a DHCP address but stalls before displaying the menu, confirm that pxelinux.0 exists in /var/lib/tftpboot/ and that SELinux contexts were restored with restorecon. A common issue on RHEL 8 is the TFTP socket not being activated — verify with systemctl status tftp.socket.
Conclusion
You now have a fully functional PXE boot server on RHEL 8 that can provision any network-booted machine in your environment. Combining DHCP, TFTP, and HTTP on a single host keeps the architecture simple while still supporting dozens of simultaneous PXE clients. Adding a Kickstart file to the mix removes all interactive prompts and allows completely hands-off OS installation at scale.
Next steps: How to Automate RHEL 8 Installations with Kickstart, How to Configure Chrony as a Time Server on RHEL 8, and How to Manage RHEL 8 Servers with Ansible.