Automated Bare Metal Provisioning with PXE and Kickstart
Installing an operating system on each server manually consumes too much time and can cause errors. PXE (Preboot Execution Environment) with Kickstart automation allows your servers automatically download the OS from a central server over the network, configure themselves, and reboot. In this guide, you will learn Automated OS Setup with PXE and Kickstart.
When you combine PXE boot with Kickstart scripts, there is no need for USB drives, no clicking through installers, and no manual steps.
This guide will show you how to set up a complete PXE deployment server on RHEL 9, configure DHCP, TFTP, and HTTP servers, create a Kickstart automation file, and deploy multiple machines in minutes.
Whether you’re managing a small cluster or a large cluster at PerLod Hosting, this technique is essential for scaling your infrastructure efficiently.
Table of Contents
Prerequisites for Automated OS Setup with PXE and Kickstart
In this article, you will learn to set up a central deployment server that allows other servers in the same network to boot from the network and automatically install the OS.
Here is what you need for this guide:
- Server: A flexible dedicated server or VM with a static IP address like 192.168.100.10 running AlmaLinux 9 or any RHEL 9, like Rocky Linux 9.
- Client: A bare-metal server or VM connected to the same network, configured to boot from Network (PXE) in BIOS/UEFI.
- ISO File: The AlmaLinux 9 minimal ISO.
Install Required Services for PXE Kickstart Baremetal Provisioning
A PXE boot server requires three core services working together, including:
- DHCP assigns IP addresses to clients requesting a network boot.
- TFTP transfers the bootloader (firmware files) to the booting machine.
- HTTP hosts the OS installation files and Kickstart automation script.
As a root user, run the following commands to update the system packages and install these required services:
dnf update -y
dnf install dhcp-server tftp-server httpd syslinux -y
Enable services to start on boot:
systemctl enable --now dhcpd tftp.socket httpd
Open Firewall Ports and Adjust SELinux in PXE Server
Before PXE clients can access the services, the PXE server must allow the required network traffic. You must open the firewall for DHCP, TFTP, and HTTP so clients can get an IP address, download the boot files, and access the installation source.
Also, SELinux can block TFTP/HTTP access if the correct labels aren’t set. You can temporarily set SELinux to Permissive mode for this guide.
In production, it’s better to keep Enforcing and applying proper SELinux rules.
Allow traffic for DHCP (67/UDP), TFTP (69/UDP), and HTTP (80/TCP) by using the commands below:
firewall-cmd --permanent --add-service=dhcp
firewall-cmd --permanent --add-service=tftp
firewall-cmd --permanent --add-service=http
Reload the firewall to apply the changes:
firewall-cmd --reload
Set SELinux to Permissive mode to prevent permission issues during setup with the commands below:
setenforce 0
sed -i 's/^SELINUX=.*/SELINUX=permissive/g' /etc/selinux/config
HTTP Install Source for PXE and Kickstart
Now that DHCP and TFTP can boot the client, the installer still needs a place to download the OS packages and read the Kickstart file from. You can turn your PXE server into a simple HTTP repo by mounting the AlmaLinux ISO and copying its contents into Apache’s web directory.
If you don’t download the ISO image, you can use the commands below to download it:
cd /tmp
wget https://repo.almalinux.org/almalinux/9/isos/x86_64/AlmaLinux-9-latest-x86_64-minimal.iso
Create a directory for the OS files by using the command below:
mkdir -p /var/www/html/almalinux9
Mount the ISO with the following command:
mount -o loop,ro /tmp/AlmaLinux-9-latest-x86_64-minimal.iso /mnt
Copy all files with:
cp -r /mnt/* /var/www/html/almalinux9/
Then, restore permissions so Apache can read them:
chmod -R 755 /var/www/html/almalinux9
umount /mnt
Now every PXE client can pull the full installer content directly from:
http://PXE-SERVER-IP/almalinux9/
This makes deployments fast, consistent, and easy to scale.
Configure UEFI PXE Boot Files
Most modern dedicated servers boot in UEFI mode, so your PXE setup must provide the correct UEFI boot chain over TFTP.
You can copy the signed UEFI bootloader files, including Shim and GRUB, with the installer kernel (vmlinuz) and initramfs (initrd.img) into your TFTP root so the client can boot the installer and then continue the automated Kickstart install.
Create the UEFI-specific directory with the command below:
mkdir -p /var/lib/tftpboot/uefi
Copy the bootloaders from the ISO content we just extracted with the commands below:
cp /var/www/html/almalinux9/EFI/BOOT/BOOTX64.EFI /var/lib/tftpboot/uefi/
cp /var/www/html/almalinux9/EFI/BOOT/grubx64.efi /var/lib/tftpboot/uefi/
Copy the Kernel (vmlinuz) and Initial Ram Disk (initrd) with the following commands:
cp /var/www/html/almalinux9/images/pxeboot/vmlinuz /var/lib/tftpboot/uefi/
cp /var/www/html/almalinux9/images/pxeboot/initrd.img /var/lib/tftpboot/uefi/
Then, set the correct permissions:
chmod -R 755 /var/lib/tftpboot/
Note: The UEFI firmware typically downloads BOOTX64.EFI, which then loads grubx64.efi, and GRUB reads a grub.cfg file (commonly placed alongside them under a uefi/ directory).
Configure DHCP for PXE Boot
DHCP is what makes PXE discoverable. When a client boots from the network, it first asks for an IP address, and the DHCP server replies with both an IP lease and the information needed to start the boot process (the PXE server address and the boot file name).
At this point, you can configure DHCP to point clients to your PXE server and to deliver the correct UEFI bootloader by detecting the client’s architecture type.
This ensures modern UEFI servers boot correctly, while still allowing an optional legacy BIOS fallback if you need it.
Edit /etc/dhcp/dhcpd.conf file as shown below:
# /etc/dhcp/dhcpd.conf
# Global options
option space pxelinux;
option pxelinux.magic code 208 = string;
option pxelinux.configfile code 209 = text;
option pxelinux.pathprefix code 210 = text;
option pxelinux.reboottime code 211 = unsigned integer 32;
option architecture-type code 93 = unsigned integer 16;
subnet 192.168.100.0 netmask 255.255.255.0 {
range 192.168.100.100 192.168.100.200;
option routers 192.168.100.1;
option subnet-mask 255.255.255.0;
option domain-name-servers 8.8.8.8;
# PXE Server IP (This server)
next-server 192.168.100.10;
# Logic to detect UEFI clients
if option architecture-type = 00:07 {
filename "uefi/BOOTX64.EFI";
} else if option architecture-type = 00:09 {
filename "uefi/BOOTX64.EFI";
} else {
# Legacy BIOS fallback (optional, requires pxelinux.0)
filename "pxelinux.0";
}
}
Once you’re done, restart DHCP with the command below:
systemctl restart dhcpd
Create a Kickstart File for Unattended Installation
Kickstart is the automation part of your PXE deployment, which pre-answers the installer questions such as language, disk layout, network, packages, users, and post-install actions, so the installation runs fully unattended.
In this step, you can generate a secure hashed root password, write your ks.cfg, and host it over HTTP so every PXE-booted server can fetch it during installation.
Generate an encrypted root password with the command below:
openssl passwd -6 MySecurePassword123
Create /var/www/html/ks.cfg file and add the following script to the file:
# /var/www/html/ks.cfg
# Use text mode install
text
# Don't run the Setup Agent on first boot
firstboot --disable
# Keyboard layouts
keyboard --vckeymap=us --xlayouts='us'
# System language
lang en_US.UTF-8
# Network information
# "link" automatically picks the first active link
network --bootproto=dhcp --device=link --ipv6=auto --activate
network --hostname=localhost.localdomain
# Root password (paste the output of openssl passwd -6 here)
rootpw --iscrypted $6$randomsalt$hashedpasswordstring...
# System timezone
timezone Asia/Dubai --isUtc
# Installation source (Point to your HTTP server)
url --url="http://192.168.100.10/almalinux9/"
# Bootloader configuration
bootloader --location=mbr --append="rhgb quiet crashkernel=auto"
# Clear the Master Boot Record
zerombr
# Remove all existing partitions
clearpart --all --initlabel
# Disk Partitioning (Automatic LVM)
autopart --type=lvm
# Reboot after installation
reboot
# Packages to install
%packages
@^minimal-environment
kexec-tools
vim
curl
%end
# Post-installation script (optional)
%post
echo "Welcome to your new server" > /etc/motd
%end
Once you are done, you can check for any syntax errors by installing the pykickstart tool and running the command below:
ksvalidator /var/www/html/ks.cfg
Create the GRUB PXE Menu
After the client downloads the UEFI boot files over TFTP, GRUB takes control and needs a boot menu that tells the installer kernel where to find your installation source and your Kickstart file.
At this point, you can create a Grub file with two choices, including an unattended install and a manual install for interactive setups.
Create /var/lib/tftpboot/uefi/grub.cfg file and add the following content to the file:
set default="0"
set timeout=10
menuentry 'Install AlmaLinux 9 (Automated)' {
linuxefi uefi/vmlinuz ip=dhcp inst.ks=http://192.168.100.10/ks.cfg inst.repo=http://192.168.100.10/almalinux9/
initrdefi uefi/initrd.img
}
menuentry 'Install AlmaLinux 9 (Manual)' {
linuxefi uefi/vmlinuz ip=dhcp inst.repo=http://192.168.100.10/almalinux9/
initrdefi uefi/initrd.img
}
Key points:
- linuxefi: Loads the kernel.
- ip=dhcp: Tells the kernel to request an IP during boot.
- inst.ks=…: Points to the automation script.
- inst.repo=…: Points to the installation files.
Test PXE with Kickstart Deployment
Now that everything is configured, you can restart services, do a quick permissions sanity check, and then PXE-boot a client to confirm the deployment works.
Restart the services with the commands below:
systemctl restart dhcpd httpd
Ensure /var/lib/tftpboot and /var/www/html are readable.
Boot the Client:
- Turn on the dedicated server or VM.
- Enter BIOS or Boot Menu.
- Select PXE and Network Boot.
During boot:
- You should see the client get an IP (DHCP).
- It will download BOOTX64.EFI (TFTP).
- The GRUB menu will appear.
- Once the timer expires or you press Enter, it will load the kernel, fetch the ks.cfg file from HTTP, and automatically start formatting the drive.
Troubleshooting Common PXE Issues
Here are the most common PXE errors and their solutions:
Issue1. Client times out / skips PXE:
If the client doesn’t get an IP fast enough, it usually falls back to the next boot device. Start by confirming the DHCP service is running and actually listening on the correct interface, especially if the PXE server has multiple NICs or VLANs.
- Check DHCP status and logs with the commands below:
systemctl status dhcpd
journalctl -u dhcpd
- Verify the client’s MAC is not blocked upstream.
- Confirm the DHCP scope matches the client subnet and that the server’s firewall allows DHCP.
Issue 2. TFTP “File not found”:
This almost always means DHCP is pointing to a file that doesn’t exist under the TFTP root, or GRUB is referencing paths incorrectly.
Check TFTP logs with the command below:
journalctl -u tftp
Ensure the boot filename matches your folder layout. For example, uefi/BOOTX64.EFI must exist under /var/lib/tftpboot/uefi/.
In grub.cfg, use paths relative to the TFTP root, for example:
Correct: uefi/vmlinuz
Wrong: /var/lib/tftpboot/uefi/vmlinuz
Confirm permissions allow reads with the command below:
chmod -R 755 /var/lib/tftpboot
Issue 3. Dracut initqueue timeout (installer can’t reach repo/ks):
When Dracut hangs with an initqueue timeout, the kernel booted successfully, but the installer can’t fetch “inst.repo” or “inst.ks” over the network.
Verify the URLs are correct and reachable from the client network:
#inst.repo
http://192.168.100.10/almalinux9/
#inst.ks
http://192.168.100.10/ks.cfg
Check Apache access logs while booting a client:
tail -f /var/log/httpd/access_log
If you can open a shell in the installer environment, test connectivity to the PXE server IP and HTTP URLs.
Confirm firewall allows HTTP and DHCP, and that routing is correct for that subnet.
FAQs
Can I PXE boot Windows servers?
No. PXE with Kickstart is exclusive to Linux systems, including RHEL, AlmaLinux, Debian, Ubuntu, etc.
What if a Kickstart file has an error and installation fails halfway?
The installer usually drops to a shell. You can fix the Kickstart, reboot the client, and try again.
Does PXE work in different subnets?
Yes, but you’ll need a DHCP relay agent that forwards PXE requests to your central DHCP server.
Conclusion
At this point, you have a fully automated bare-metal server deployment pipeline, which is one of the most powerful tools in any IT infrastructure. PXE with Kickstart setup handles DHCP, network boot, OS installation, partitioning, package selection, and post-install configuration without a single manual click.
- DHCP discovers and directs network clients to your PXE server.
- TFTP transfers the UEFI bootloader chain.
- HTTP delivers the OS installer packages and automation scripts.
- Kickstart removes human interaction entirely.
We hope you enjoy this guide on Automated OS Setup with PXE and Kickstart. Subscribe to our X and Facebook channels to get the latest articles.