I’m currently doing many tests with the Openshift bare-metal installation, and as I’m creating and destroying the VMs again and again, having a PXE server to provide the installation images and configuration to the VMs is very handy and saves a lot of time.
This is an example of my PXE configuration mounted on a Fedora box that acts as router.
Boot server
I’m currently using dnsmasq as my DNS and DHCP server and I will use it as TFTP server to provide the information required by the PXE clients.
First, let’s install the required packages:
# dnf install dnsmasq syslinux-tftpboot
The files served by TFTP are located in /tftpboot, I have copied there too the files needed to boot EFI machines:
# cp /boot/efi/EFI/fedora/*efi /tftpboot
Now configure dnsmasq in /etc/dnsmasq.conf to enable the TFTP service and assign tags to send different DHCP options if the client is BIOS or EFI. Don’t forget to restart the service:
# PXE
enable-tftp
tftp-root=/tftpboot
dhcp-match=set:bios,option:client-arch,0
dhcp-match=set:uefi,option:client-arch,7
dhcp-boot=tag:bios,pxelinux.0
dhcp-boot=tag:uefi,shim.efi
Enable the TFTP service in the firewall:
# firewall-cmd --add-service=tftp --permanent
# firewall-cmd --reload
BIOS clients
For the BIOS clients, create the folder /tftpboot/pxelinux.cfg and create there the configuration files. Please, note that I’m using a HTTP server called bootserver.lan.
Example config /tftpboot/pxelinux.cfg/fedora for Fedora Server and Workstation:
DEFAULT menu.c32
TIMEOUT 600
PROMPT 0
LABEL Fedora32_Server
KERNEL http://bootserver.lan/fedora32-server/images/pxeboot/vmlinuz
APPEND initrd=http://bootserver.lan/fedora32-server/images/pxeboot/initrd.img inst.stage2=http://bootserver.lan/fedora32-server ip=dhcp
LABEL Fedora32_Server_rescue
KERNEL http://bootserver.lan/fedora32-server/images/pxeboot/vmlinuz
APPEND initrd=http://bootserver.lan/fedora32-server/images/pxeboot/initrd.img inst.stage2=http://bootserver.lan/fedora32-server ip=dhcp rescue
LABEL Fedora32_Workstation
KERNEL http://bootserver.lan/fedora32-workstation/images/pxeboot/vmlinuz
APPEND initrd=http://bootserver.lan/fedora32-workstation/images/pxeboot/initrd.img root=live:http://bootserver.lan/fedora32-workstation/LiveOS/squashfs.img ip=dhcp rd.live.image
LABEL CentOS8
KERNEL http://bootserver.lan/centos8/images/pxeboot/vmlinuz
APPEND initrd=http://bootserver.lan/centos8/images/pxeboot/initrd.img inst.stage2=http://bootserver.lan/centos8 ip=dhcp
Example config /tftpboot/pxelinux.cfg/master for Red Hat CoreOS:
DEFAULT pxeboot
TIMEOUT 20
PROMPT 0
LABEL pxeboot
KERNEL http://bootserver.lan/rhcos/rhcos-4.5.6-x86_64-installer-kernel-x86_64
APPEND ip=dhcp rd.neednet=1 initrd=http://bootserver.lan/rhcos/rhcos-4.5.6-x86_64-installer-initramfs.x86_64.img console=tty0 console=ttyS0 coreos.inst=yes coreos.inst.install_dev=vda coreos.inst.image_url=http://bootserver.lan/rhcos/rhcos-4.5.6-x86_64-metal.x86_64.raw.gz coreos.inst.ignition_url=http://bootserver.lan/rhcos/master.ign
Now we create symbolyc links for the clients to choose the desired configuration. To designate a specific configuration to a MAC, create a link prefixed with ‘01-’. If the client MAC is not listed, it will use the default entry:
# cd /tftpboot/pxelinux.cfg
# ln -s master 01-aa-bb-cc-dd-ee-ff
# ln -s fedora default
EFI clients
The EFI clients will look for the configuration in /tftpboot/grub.cfg. I’m just configuring Fedora and CentOS boot here:
set timeout=60
set default=0
menuentry 'Install Fedora 32 Server' --class fedora --class gnu-linux --class gnu --class os {
set root=(http,bootserver.lan)
linuxefi /fedora32-server/images/pxeboot/vmlinuz ip=dhcp inst.stage2=http://bootserver.lan/fedora32-server
initrdefi /fedora32-server/images/pxeboot/initrd.img
}
menuentry 'Rescue a Fedora system' --class fedora --class gnu-linux --class gnu --class os {
set root=(http,bootserver.lan)
linuxefi /fedora32-server/images/pxeboot/vmlinuz ip=dhcp inst.stage2=http://bootserver.lan/fedora32-server rescue
initrdefi /fedora32-server/images/pxeboot/initrd.img
}
menuentry 'Start Fedora-Workstation-Live 32' --class fedora --class gnu-linux --class gnu --class os {
set root=(http,bootserver.lan)
linuxefi /fedora32-workstation/images/pxeboot/vmlinuz ip=dhcp root=live:http://bootserver.lan/fedora32-workstation/LiveOS/squashfs.img rd.live.image
initrdefi /fedora32-workstation/images/pxeboot/initrd.img
}
menuentry 'Install CentOS 8' --class centos --class gnu-linux --class gnu --class os {
set root=(http,bootserver.lan)
linuxefi /centos8/images/pxeboot/vmlinuz ip=dhcp inst.stage2=http://bootserver.lan/centos8
initrdefi /centos8/images/pxeboot/initrd.img
}
HTTP server
The OS images are hosted in a HTTP server, which can be in the same machine or somewhere else. I’m using nginx with this configuration in /etc/nginx/conf.d/bootserver.lan.conf:
server {
listen [::]:80;
listen 0.0.0.0:80;
server_name bootserver.lan;
access_log /var/log/nginx/bootserver.lan_access.log main;
root /var/www/bootserver.lan;
location / {
allow 192.168.0.0/16;
# Allow your local net
deny all;
}
}
Now, you have to create the different OS folders in /var/www/bootserver.lan and copy the full contents of the ISOs there:
# mkdir -p /var/www/bootserver.lan/{rhcos,fedora-workstation,fedora-server,centos8}
Copy the ISO contents:
# rsync -av /mnt/ISO /var/www/bootserver.lan/fedora-workstation
Test it!
Everything is now in place, it’s time to launch a new VM with PXE boot. To debug any problem, check the journal messages of dnsmasq and the access log of the HTTP server:
# journalctl -f -u dnsmasq
# tail -20f /var/log/nginx/bootserver.lan_access.log