Ubuntu – Ultimate PXE Server Setup – BIOS & UEFI Support

By | December 12, 2022


This guide will explain how to configure your dhcp/pxe/tftp server infrastructure to support BIOS and UEFI-based systems network installation.  This guide will mix PXELinux and grub technology.  This combination seems the one that provides the best results when there is a need to deploy operating systems on UEFI or BIOS based systems.   Because grub files are signed, this setup will also support UEFI and secure boot option enabled as well

The pxelinux bootloader will be used when BIOS Based systems need to be installed.  Grub bootloader approach will be used when UEFI Systems needs to be deployed.  The selection of the bootloader will be done automatically when the client boots.  The boot process with include a packet information that will tell the PXE server which bootloader to use…. 

To deploy Ubuntu operating system through the network, necessary infrastructure and server services needs to be present on the network.  DHCP, DNS, TFTP, Web and File services are needed in order to build up the needed PXE infrastructure.


The following assumptions have been made in order to have this scenario working 

  • Hyper-v platform is used to emulated UEFI based virtual machines
  • VM Generation 2 will be used in order to have UEFI and SecureBoot option is Enabled 
  • You have internet connection in order to download additional necessary packages
  • You have Ubuntu 18.04 Server ISO or installation files 
  • You have Ubuntu 18.04 Desktop ISO or installation files 

Step by Step Guide 

Step 0 – Install Ubuntu 18.04.2 Server Edition 

In this post, we will be using Ubuntu 18.04.2 Server as the PXE server.  Ubuntu 18.04.2 has been selected because this is a Long Term Service (LTS) release. This post will not explain how to install an Ubuntu server.  When your installation is completed, move to the next step

Step 1 – Set a Static IP address on your Ubuntu Server

Ubuntu Server has no Desktop interface available by default.  We will need to perform most of the actions through command lines.  No fear, you will see it’s quite easy actually.  To set a static ip address on your Ubuntu Server, you will need to edit the following file  /etc/netplan/50-cloud-init.yaml.  

To edit this file, issue the following command 

sudo nano /etc/netplan/50-cloud-init.yaml

Replace the content of the file with the following one (you might need to update the information based on your infrastructure

         dhcp4: no 
         addresses: [] 
               addresses: [,]
version: 2

In order to apply the changes, we need to execute this command as well 

sudo netplan apply

Finally, check that the ip address has been set correctly by issuing the following command 

ip addr

Step 2 – Build up your PXE Server

In this post, we assume that the Ubuntu Server will be hosting all the necessary services needed to implement a proper PXE Infrastructure. To setup a pxe infra, we need to install the following packages 

  • dnsmasq (providing DHCP,DNS and TFTP services),
  • apache web for storage purposes and
  • NFS packages if you are planning to deploy Ubuntu Desktop through your PXE infrastructure. 

Step 2.1 – Install apache web server

To install the apache package, you will issue the following command  

sudo apt-get install apache2

Step 2.2 – Install NFS packages

NFS packages will provide file services capabilities. To install the nfs packages, execute the following commands 

sudo apt-get install nfs-kernel-server 

Step 2.3 – Install dnsmasq packages

To install the dnsmasq package, you will issue the following command  

sudo apt-get dnsmasq

Step 3 – Create the TFTP Folder Structure

We will create a folder called tftp at root of the filesystem (/tftp).   Within this folder, the following structure will be create


To create this structure, you will need to execute the following commands

sudo mkdir /tftp
sudo mkdir /tftp/bios
sudo mkdir /tftp/boot
sudo mkdir /tftp/grub

Step 4 – Upload source files on your PXE Server  

Because you are using the Apache Web server, we will be copying all sources files under /var/www/html directory.  We will copy the iso files contents of Ubuntu 18.04 Desktop and Ubuntu Server under this location. We will create the following structure first 

sudo mkdir /var/www/html/bionic/server
sudo mkdir /var/www/html/bionic/desktop

You can obviously add other version of Ubuntu files and your structure could look like the following  


So, mount your iso file into your Ubuntu server.  To mount it, issue the following command 

sudo mount /dev/sr0 /media

Copy the files from the iso image into the correct directory.  You can use the following syntax to perform the operation 

sudo cp -rf  <%Your Path To Install Files%>/*  /var/www/html/server/bionic

When the copy is finished, unmount the iso/DVD image from your machine by issuing the following command 

sudo umount /media

Repeat the operation for each operating system sources files you want to copy on your PXE Server 

Step 5 – Configuring your NFS Server Settings 

Since our folder structure is ready, we can start configuring the different services that are used by the PXE server.   To ensure that our directory structure is accessible through the network and through the nfs protocol, we will need to edit the following file by issuing the following command

sudo nano /etc/exports

Insert at the bottom of the file, the path where you have stored your installation files, which subnet can access it and which kind of right you want to grant.  In our  scenario, we want to grant access to the following directory /var/www/html/bionic/desktop through the network subnet and we are granting read only access (ro).  So, at the end of the file, we would add the following line 


When this has been done, it’s time to restart the nfs service. To do that, you simply execute the following command 

sudo systemctl restart nfs-kernel-server

Step 6 – Configuring the dnsmasq services 

Almost there !  Now, we need to configure the dnsmasq service which will provide the glue between the different services.  dnsmasq configuration file will be used to provide the necessary information to the pxe client when it boots.  This file will dictate where to look for pxe bootloader based on the client architecture (uefi or bios).  So, let’s edit the /etc/dnsmasq.conf file and at the bottom add the following information

To edit the configuration file, issue the following command  

sudo nano /etc/dnsmasq.conf 

Copy and update the following information at the bottom of the file 

Note : You will need to modify it accordingly to reflect your own infrastructure

#Interface information 
#--use ip addr to see the name of the interface on your system

#DHCP Settings
#-- Set dhcp scope

#-- Set gateway option

#-- Set DNS server option

#-- dns Forwarder info

# Specify TFTP Options #

#--location of the pxeboot file

#--enable tftp service

#-- Root folder for tftp

#--Detect architecture and send the correct bootloader file

To have the change applied to your system, you will need to restart the dnsmasq service.  To perform such task, you will execute the following command 

sudo systemctl restart dnsmasq

Then, you should check that the dnsmasq is started correctly and that no errors are reported by issuing the command 

sudo systemctl status dnsmasq

Step 7 – Uploading all the necessary files in your TFTP folder Structure 

We are almost ready !  Now, we need to get the necessary file placed in your tftp folder in order to have pxe capability. 

Step 7.1 – populate bios folder 

In the /tftp/bios folder, we will place the pxelinux files needed.  To obtain the pxelinux files, you can download the files from the following url (https://mirrors.edge.kernel.org/pub/linux/utils/boot/syslinux/Testing/6.04/).  Then, you can copy the following files from pxelinux sources files to /tftp/bios folder

sudo cp <%your download location%>/bios/com32/elflink/ldlinux/ldlinux.c32  /tftp/bios/ldlinux.c32
sudo cp <%your download location%>/bios/com32/libutil/libutil.c32  /tftp/bios/libutil.c32  
sudo cp <%your download location%>/bios/com32/menu/menu.c32  /tftp/bios/menu.c32
sudo cp <%your download location%>/bios/com32/menu/vesamenu.c32  /tftp/bios/vesamenu.c32 
sudo cp <%your download location%>/bios/core/pxelinux.0  /tftp/bios/pxelinux.0
sudo cp <%your download location%>/bios/core/lpxelinux.0  /tftp/bios/lpxelinux.0

You will also need to create a symbolic link to the /tftp/boot folder.  You will need to issue the following command 

sudo ln -s /tftp/boot  /tftp/bios/boot

We will also need to create the folder called pxelinux.cfg under the /tftp/bios folder. Inside this folder, we will create an empty file called default.  This file control the pxelinux behavior. We will populate it with the following code 

DEFAULT menu.c32

MENU COLOR TABMSG  37;40  #ffffffff #00000000
MENU COLOR TITLE   37;40  #ffffffff #00000000 
MENU COLOR SEL      7     #ffffffff #00000000
MENU COLOR UNSEL    37;40 #ffffffff #00000000
MENU COLOR BORDER   37;40 #ffffffff #00000000

LABEL Ubuntu Server 18.04
    kernel /boot/server/linux
    append vga=788 initrd=/boot/server/initrd.gz

LABEL Ubuntu Desktop 18.04
    kernel /boot/casper/vmlinuz
    append nfsroot= netboot=nfs ro file=/cdrom/preseed/ubuntu.seed boot=casper initrd=boot/casper/initrd.lz systemd.mask=tmp.mount --

Save it 

You are ready to move to the next section

Step 7.2 – Populate boot folder 

In this step, we need to place the correct bootloader in order for the installation process to start accordingly.  Under the /tftp/boot folder, we will create 2 sub folders to make a distinction between the server and the desktop bootloader files. So the folder structure will look like the following 

    | - server
    | - casper

We will copy the necessary files from the /var/www/html location.   Issue the following commands to copy the necessary files to the correct location 

sudo cp /var/www/html/bionic/desktop/casper/vmlinuz      /tftp/boot/casper
sudo cp /var/www/html/bionic/desktop/casper/initrd.lz    /tftp/boot/casper
sudo cp /var/www/html/bionic/server/install/netboot/ubuntu-installer/amd64/linux       /tftp/boot/server
sudo cp /var/www/html/bionic/server/install/netboot/ubuntu-installer/amd64/initrd.gz   /tftp/boot/server

Step 7.3 – Populate grub folder 

Finally, we need to populate the grub folder. This folder contains the files that are needed to boot uefi systems.  So, in your system, you will execute the following commands. The commands below basically will download the necessary signed bootloader files and grub files needed by PXE server and extract the contents on their dedicated folders (shim and grub)

apt-get download shim.signed
dpkg -x <%name of the deb package%> shim

apt-get download grub-efi-amd64-signed
dpkg -x <%name of the deb package%> grub

When this is done, we can simply copy the needed file into the tftp boot folder.  So, execute the following commands. Change the path accordingly based on your settings… 

sudo cp ~/grub/<%name of package%>/usr/lib/grub/x86_64-efi-signed/grubnetx64.eif.signed  /tftp/grubx64.efi
sudo cp ~/shim/<%name of package%>/usr/lib/shim/shimx64.efi.signed  /tftp/grub/bootx64.efi

Finally, we will copy two additional files from the source iso image.  They will server as base for the next step. So, execute the following commands 

sudo cp /var/www/html/bionic/server/boot/grub/grub.cfg  /tftp/grub/
sudo cp /var/www/html/bionic/server/boot/grub/font.pf2 /tftp/grub/

Step 7.4 – Create/update the grub.cfg

We are almost done !  Now, we need to create also a boot menu and get the proper option available and working.  The grub boot loader reads information from the grub.cfg file.  If you have followed this step by step guide, the content of the grub.cfg file should look like this 

if loadfont /grub/font.pf2 ; then
set gfxmode=auto
insmod efi_gop
insmod efi_uga
insmod gfxterm
terminal_output gfxterm

set menu_color_normal=white/black
set menu_color_highlight=black/light-gray
set timeout=5

menuentry "Ubuntu Server 18.04" {
   set gfxpayload=keep
   linux  boot/server/linux ip=dhcp rw
   initrd boot/server/initrd.gz
menuentry "Ubuntu Desktop 18.04" {
   set gfxpayload=keep
   linux /boot/casper/vmlinuz ip=dhcp nfsroot= netboot=nfs ro file=/cdrom/preseed/ubuntu.seed boot=casper systemd.mask=tmp.mount --
   initrd /boot/casper/initrd.lz

Step 8 – Test your configuration 

This is the fun part ! If everything is working as expected, when you boot your Bios client, you should see the pxelinux boot loader showing up.  As you can see on the screenshot below, we have customized a little bit the look’n feel of the boot menu in order to match to the grub boot menu. 


Click on picture for better resolution 

Doing the same for UEFI computers, you should see a boot menu similar to the following.. 


Click on picture for better resolution 

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.