Skip to content

Solution: PXE Boot Fails - UEFI Mismatch

Triage

  1. Capture PXE traffic from one of the new servers:

    tcpdump -i eth0 -vvv -s0 port 67 or port 68 or port 69 -w /tmp/pxe_capture.pcap
    

  2. Examine the DHCP Discover from the UEFI client. Look for option 93 (Client System Architecture):

  3. Value 0x0000 = BIOS/Legacy (Intel x86PC)
  4. Value 0x0007 = UEFI x64 (EFI BC)
  5. Value 0x0009 = UEFI x64 (EFI x86-64)

  6. Check what boot filename the DHCP server is offering:

    grep -i "filename\|boot-file" /etc/dhcp/dhcpd.conf
    
    If it only serves pxelinux.0, that confirms the mismatch.

  7. Check if a UEFI boot file exists:

    ls -la /tftpboot/grubx64.efi /tftpboot/shimx64.efi 2>/dev/null
    

Root Cause

The DHCP server is configured to serve pxelinux.0 (a Legacy BIOS PXE bootloader) to all clients. UEFI PXE clients cannot execute this file -- they need an EFI binary such as grubx64.efi or shimx64.efi. The TFTP transfer "fails" because the UEFI firmware downloads pxelinux.0 but cannot parse it as a valid EFI application, or the client requests an EFI-specific path that does not exist.

Fix

  1. Install the UEFI PXE boot files on the TFTP server:

    # For RHEL/CentOS based provisioning:
    cp /boot/efi/EFI/centos/shimx64.efi /tftpboot/
    cp /boot/efi/EFI/centos/grubx64.efi /tftpboot/
    
    # Or from the shim-x64 and grub2-efi-x64 packages:
    yum install -y shim-x64 grub2-efi-x64
    cp /boot/efi/EFI/centos/shimx64.efi /tftpboot/
    cp /boot/efi/EFI/centos/grubx64.efi /tftpboot/
    

  2. Update the DHCP configuration to serve the correct file based on architecture:

    # /etc/dhcp/dhcpd.conf
    class "pxeclients-bios" {
        match if substring (option vendor-class-identifier, 0, 20) = "PXEClient:Arch:00000";
        filename "pxelinux.0";
    }
    
    class "pxeclients-uefi" {
        match if substring (option vendor-class-identifier, 0, 20) = "PXEClient:Arch:00007";
        filename "shimx64.efi";
    }
    
    class "pxeclients-uefi-64" {
        match if substring (option vendor-class-identifier, 0, 20) = "PXEClient:Arch:00009";
        filename "shimx64.efi";
    }
    

  3. Create a GRUB config for UEFI network boot:

    mkdir -p /tftpboot/grub
    cat > /tftpboot/grub/grub.cfg << 'GRUBEOF'
    set timeout=10
    menuentry 'Install OS via network' {
        linuxefi (tftp)/images/vmlinuz inst.repo=http://10.20.0.5/repo inst.ks=http://10.20.0.5/ks/default.cfg
        initrdefi (tftp)/images/initrd.img
    }
    GRUBEOF
    

  4. Restart DHCP and test:

    systemctl restart isc-dhcp-server
    # or
    systemctl restart dhcpd
    

  5. Test with one new server. Watch the console to confirm TFTP download succeeds and GRUB menu appears.

Rollback / Safety

  • The DHCP class matching ensures Legacy BIOS clients still receive pxelinux.0. Existing servers are unaffected.
  • If the change breaks existing provisioning, revert dhcpd.conf and restart DHCP.
  • Keep a backup of the working config: cp /etc/dhcp/dhcpd.conf /etc/dhcp/dhcpd.conf.bak.$(date +%F)
  • Test both UEFI and Legacy PXE boot after the change to confirm coexistence.

Common Traps

  • Trap: Using grubx64.efi directly instead of shimx64.efi when Secure Boot is enabled. The shim is needed as the first-stage loader for Secure Boot chain of trust.
  • Trap: Matching on option 93 numerically instead of checking the vendor-class-identifier string. Different DHCP server versions handle this differently.
  • Trap: Forgetting to create the GRUB configuration file. Without grub.cfg, GRUB boots but drops to a shell with no menu entries.
  • Trap: Not testing backward compatibility. The DHCP class matching must be tested for both UEFI and BIOS clients.
  • Trap: TFTP block size issues. Some UEFI clients request large block sizes (1468+). Ensure the TFTP server supports tsize and blksize options.