How to Set Up a PXE Boot Server on RHEL 7
Provisioning bare-metal servers or virtual machines one by one from USB media does not scale. A PXE (Preboot Execution Environment) boot server lets a machine boot directly from the network, pull a kernel and RAM disk from a TFTP server, and optionally complete an entirely automated installation using a Kickstart file. The result is a repeatable, hands-free deployment pipeline that can provision dozens of systems simultaneously. This tutorial builds a complete PXE environment on a single RHEL 7 host using TFTP, DHCP, Syslinux, and either VSFTPD or Apache HTTP to serve the installation tree.
Prerequisites
- RHEL 7 server with two network interfaces or a single interface with a static IP (e.g.,
192.168.10.1) on the provisioning network. - Root or
sudoaccess. - A CentOS 7 or RHEL 7 ISO image available locally (e.g.,
/root/CentOS-7-x86_64-DVD-2009.iso). - Enough disk space to mount and serve the ISO (~4 GB).
- DHCP authority over the provisioning network — no other DHCP server running on that subnet.
Step 1: Install Required Packages
Install the TFTP server, DHCP server, Syslinux bootloader files, and a web or FTP server to serve the installation tree:
sudo yum install -y tftp-server dhcp syslinux vsftpd
Optionally install Apache HTTP if you prefer HTTP over FTP for serving the ISO tree:
sudo yum install -y httpd
The TFTP server in RHEL 7 is managed via xinetd or systemd socket activation. Enable and start the TFTP socket:
sudo systemctl enable tftp.socket
sudo systemctl start tftp.socket
sudo systemctl status tftp.socket
Step 2: Populate the TFTP Boot Directory
Syslinux provides pxelinux.0, the first-stage PXE bootloader. Copy it into the TFTP root:
sudo cp /usr/share/syslinux/pxelinux.0 /var/lib/tftpboot/
sudo cp /usr/share/syslinux/menu.c32 /var/lib/tftpboot/
sudo cp /usr/share/syslinux/mboot.c32 /var/lib/tftpboot/
sudo cp /usr/share/syslinux/chain.c32 /var/lib/tftpboot/
Mount the ISO and copy the kernel (vmlinuz) and initial RAM disk (initrd.img) into a subdirectory:
sudo mkdir -p /mnt/centos7
sudo mount -o loop /root/CentOS-7-x86_64-DVD-2009.iso /mnt/centos7
sudo mkdir -p /var/lib/tftpboot/centos7
sudo cp /mnt/centos7/images/pxeboot/vmlinuz /var/lib/tftpboot/centos7/
sudo cp /mnt/centos7/images/pxeboot/initrd.img /var/lib/tftpboot/centos7/
Verify the directory structure:
ls -lh /var/lib/tftpboot/
ls -lh /var/lib/tftpboot/centos7/
Step 3: Create the PXE Boot Menu
PXE clients fetch their boot configuration from /var/lib/tftpboot/pxelinux.cfg/. The filename is matched by the client MAC address (e.g., 01-aa-bb-cc-dd-ee-ff) and falls back to default.
sudo mkdir -p /var/lib/tftpboot/pxelinux.cfg
sudo vi /var/lib/tftpboot/pxelinux.cfg/default
Paste the following menu configuration:
DEFAULT menu.c32
PROMPT 0
TIMEOUT 300
ONTIMEOUT local
MENU TITLE PXE Boot Menu - ProgressiveRobot Lab
LABEL local
MENU LABEL Boot from local disk
LOCALBOOT 0
LABEL centos7-install
MENU LABEL Install CentOS 7 (Interactive)
KERNEL centos7/vmlinuz
APPEND initrd=centos7/initrd.img inst.repo=ftp://192.168.10.1/pub/centos7 quiet
LABEL centos7-ks
MENU LABEL Install CentOS 7 (Kickstart - Automated)
KERNEL centos7/vmlinuz
APPEND initrd=centos7/initrd.img inst.repo=ftp://192.168.10.1/pub/centos7 inst.ks=ftp://192.168.10.1/pub/ks.cfg quiet
The TIMEOUT 300 value is in tenths of a second, so 30 seconds. ONTIMEOUT local boots from the local disk if no choice is made.
Step 4: Serve the Installation Tree via VSFTPD
VSFTPD can serve the ISO tree as an anonymous FTP source with minimal configuration. Copy the mounted ISO contents to the FTP public directory:
sudo mkdir -p /var/ftp/pub/centos7
sudo cp -r /mnt/centos7/* /var/ftp/pub/centos7/
This copy takes several minutes depending on disk speed. Verify content:
ls /var/ftp/pub/centos7/
Enable and start VSFTPD:
sudo systemctl enable vsftpd
sudo systemctl start vsftpd
Step 5: Configure the DHCP Server
Edit the DHCP configuration to hand out IP addresses and point clients to the TFTP server and PXE bootloader:
sudo vi /etc/dhcp/dhcpd.conf
option domain-name "lab.local";
option domain-name-servers 192.168.10.1;
default-lease-time 600;
max-lease-time 7200;
# Tell clients this is authoritative
authoritative;
# The subnet being managed
subnet 192.168.10.0 netmask 255.255.255.0 {
range 192.168.10.100 192.168.10.200;
option routers 192.168.10.1;
option subnet-mask 255.255.255.0;
option broadcast-address 192.168.10.255;
# PXE boot options
next-server 192.168.10.1; # TFTP server IP
filename "pxelinux.0"; # First-stage bootloader
}
# Optional: fixed address for a specific host by MAC
host webserver01 {
hardware ethernet aa:bb:cc:dd:ee:ff;
fixed-address 192.168.10.50;
next-server 192.168.10.1;
filename "pxelinux.0";
}
Enable and start the DHCP daemon:
sudo systemctl enable dhcpd
sudo systemctl start dhcpd
sudo systemctl status dhcpd
Step 6: Create a Kickstart File for Automated Installation
A Kickstart file answers all installer prompts automatically. Create a minimal example:
sudo vi /var/ftp/pub/ks.cfg
#version=DEVEL
# System authorisation information
auth --enableshadow --passalgo=sha512
# Installation method
install
url --url="ftp://192.168.10.1/pub/centos7"
# Keyboard layout and language
keyboard --vckeymap=us --xlayouts='us'
lang en_US.UTF-8
# Network configuration (first interface, DHCP)
network --bootproto=dhcp --device=eth0 --onboot=yes --ipv6=auto
# Root password (generated with: python -c "import crypt; print(crypt.crypt('yourpassword'))")
rootpw --iscrypted $6$rounds=656000$randomsalt$encryptedhashhere
# Firewall
firewall --enabled --service=ssh
# SELinux
selinux --enforcing
# Timezone
timezone America/New_York --isUtc
# Bootloader
bootloader --append=" crashkernel=auto" --location=mbr
# Partition layout - wipes all disks
zerombr
clearpart --all --initlabel
autopart
# Package selection
%packages
@^minimal
@core
chrony
vim
%end
# Post-installation script
%post
systemctl enable chronyd
%end
# Reboot after installation
reboot
Step 7: Configure the Firewall
Open firewall ports for DHCP, TFTP, and FTP:
sudo firewall-cmd --permanent --add-service=dhcp
sudo firewall-cmd --permanent --add-service=tftp
sudo firewall-cmd --permanent --add-service=ftp
sudo firewall-cmd --reload
sudo firewall-cmd --list-all
Step 8: Test with a Virtual Machine
In KVM/QEMU or VirtualBox, create a new VM on the same network as the PXE server and set the boot order to Network (PXE) first. On boot, the VM will:
- Send a DHCP DISCOVER broadcast.
- Receive an offer from
dhcpdincludingnext-serverandfilename. - Download
pxelinux.0via TFTP from192.168.10.1. - Display the boot menu defined in
pxelinux.cfg/default. - Download the kernel and initrd, then launch the installer.
Monitor DHCP lease assignments:
sudo tail -f /var/log/messages | grep -i dhcp
Monitor TFTP transfers:
sudo journalctl -u tftp.socket -f
Conclusion
You have built a fully functional PXE boot server on RHEL 7 that handles the complete network provisioning workflow: DHCP hands out addresses and points clients to the TFTP server, Syslinux provides the boot menu, VSFTPD serves the installation tree, and an optional Kickstart file drives fully automated installs. This infrastructure can provision physical servers, virtual machines, and cloud instances that support PXE, eliminating manual installation steps and ensuring every host starts from a known, consistent baseline. Add per-machine Kickstart files named by MAC address to the FTP server for host-specific configurations without any manual intervention.