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 sudo access
  • 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, and vi

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.