PXE server in Fedora with dnsmasq

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

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s