Linux PXE Server in Heterogeneous Network with Existing DHCP Server (Part 1 – memtest)

So I have a heterogeneous network, and I want to netboot various computers within that network without having to write individual lines in the DHCP server config files. Moreover, the DHCP server for my network lives on a separate router machine with virtually zero disk space, so the PXE server must be separate to that without compromising the rest of the DHCP network. I want to be able to netboot random machines as I quite frequently have computers in the house that need to be wiped and/or reinstalled - ideally this should be as easy and painless as possible. Being able to netboot any machine I plug in to the network will allow for that to be easily done at any time.

Ideally, the PXE server should be able to serve at least the following images to various machines on request:

  • Ubuntu Live CD (16.04 & 17.04; i386 & x86_64)
  • Memtest86+
  • DBAN
  • Windows 7 & 10, Home & Pro; i386 & x86_64

Also, I want to be able to netboot other architectures, specifically Raspberry Pi boards so I don't have to use those pesky SD Cards and can keep them all updated in a single place. In the future I want to also be able to netboot my SGI machine, as the disk in it is old and whines (a bit like me), and also my NextSTEP machine (A HP 712 workstation). If I am successful I may also drag the DEC Alpha out of the garage and sit that on the network too. So any solution I come up with has to be able to accommodate those architectures in the future (without necessarily being used for those more exotic architectures - more on that later). I won't go into the background detail of PXE and netbooting too much as there are plenty of references on the web that explain it a lot better than I'd be able to.

In my preliminary research, I found the following pages which I have found useful in determining the strategy I will take:

I have also taken a lot of inspiration for the menu structure etc from the YUMI Linux usb multiboot installer, from which I have unashamedly copied the menu logo and menu layout (with some modifications).

The server I will use is a machine I have running Ubuntu 17.04. It's a reasonably decent machine, a bit short on RAM with only 4GB but it has enough disk (a pretty-much blank 3TB disk) and a gigabit connection to the main network backplane. In an ideal world I'd rather it be running one of the LTS releases of Ubuntu, but since we will be requiring at least DNSMasq version 2.76 to boot UEFI properly, I've just gone the whole hog and updated to the newest Ubuntu version rather than installing a custom version of DNSMasq (16.04LTS only has v2.75).

For this blog, I'll be following Manski's blog fairly closely, as that's a good starting point that will get us most of the way to where we want to be.

Let's get into it.

First we will ensure we are up to date with all the latest patches etc:

$ sudo apt update ; sudo apt upgrade

Aside: I wanted to put the "and" operator in the command above but the WordPress Markdown plugin I'm using expanded it to "&&" rather than "&&" so I just went with ';'

Install Required Packages

We will need to first of all ensure we have the required packages installed on our Linux server. For this we will initially need dnsmasq, pxelinux and syslinux:

$ sudo apt install dnsmasq pxelinux syslinux-common

We will also require the memtest86 binary as our first netboot target. Luckily I have that kicking about somewhere so don't need to download it, but if you don't have it already you will need to get it from Memtest. On our network (and most networks these days) we already have a working DHCP server, so we will skip any configuration of that and assume that it's all good. For our PXE and TFTPboot server to not tread all over our existing DHCP, we'll have to use the proxy-dhcp mode of DNSMasq; we'll get to that in a minute.

Create Directories for Netboot files

It's here that we will diverge slightly from our primary source (Manski's blog), and create a directory structure for our netboot files based on architecture. This allows us to keep it all a bit more organised, as in the future we may have a whole stack of directories and we don't want to have too many in our tftpboot root. First we will look at our machine to see where we want to put the files we'll serve:

$ df
Filesystem            1K-blocks       Used  Available Use% Mounted on
udev                    1965796          0    1965796   0% /dev
tmpfs                    404316      42056     362260  11% /run
/dev/sda1             145975872    8001564  130536076   6% /
tmpfs                   2021576         48    2021528   1% /dev/shm
tmpfs                      5120          4       5116   1% /run/lock
tmpfs                   2021576          0    2021576   0% /sys/fs/cgroup
/dev/sdb1            2884152988  168921104 2568702224   7% /data
tmpfs                    404312        148     404164   1% /run/user/1000

We'll chuck our netboot server files into the /data partition - it's a 3TB disk I have preseeded with a whole bunch of IRIX and NextSTEP cd images & boot files for future use, but apart from that is empty. Let's make some of our directories that we'll start with, so we can get an idea of how our system will look when it's fully loaded:

$ mkdir -p /data/tftpboot/i386/memtest \
           /data/tftpboot/i386/ubuntu \
           /data/tftpboot/x86_64/ubuntu

You can see that gives us plenty of scope for adding new architectures and also new distributions etc without getting too confused about where anything in particular will live. Now we need to create the folder for the menus:

$ mkdir -p /data/tftpboot/pxelinux.cfg

The pxelinux.cfg directory we have created must correspond in name to the pxelinux.0 image we will serve up to our clients. So if a client is served foo.0, it will need to have a corresponding directory called foo.cfg. The appropriate bootloader file and corresponding menu file will be served to the requesting device based on the architecture it reports in the PXE request. For this stage we will concentrate on the ubiquitous i386 architecture, and get the memtest86 binary running. In subsequent blogs we will complete the multi-boot menu and multi-arch binary delivery.

Copy Boot Files & Create Our Default Menu

First we need to copy over the memtest86 binary into the appropriate directory. Manski tells us that it's important that the ".bin" suffix is dropped for PXE booting; this is because the .bin extension is a special meaning extension for a "CD Boot Sector" image, so we drop it on copy:

$ cp /path/to/memtest86+-5.01.bin /data/tftpboot/i386/memtest/memtest86+-5.01

Now we need to put the bootloader and menu file into the root directory of the tftp server, in our case the /data/tftpboot directory. We'll use a symlink so when our syslinux is updated on the host system it keeps track. Manski tells us to use the ldlinux.c32 file, but we would like a nice menu so we'll use the vesamenu version instead. Note that to use the vesamenu you will also require the libcom32.c32 and libutil.c32 files; also we will still need ldlinux.c32 for all boot modes. At this stage we will copy over a nice menu logo as well; any 640x480 PNG file could be used, we will use a nice image I prepared earlier:

$ ln -s /usr/lib/PXELINUX/pxelinux.0 /data/tftpboot/
$ ln -s /usr/lib/syslinux/modules/bios/vesamenu.c32 /data/tftpboot/
$ ln -s /usr/lib/syslinux/modules/bios/ldlinux.c32 /data/tftpboot/
$ ln -s /usr/lib/syslinux/modules/bios/libcom32.c32 /data/tftpboot/
$ ln -s /usr/lib/syslinux/modules/bios/libutil.c32 /data/tftpboot/
$ cp /path/to/menu.png /data/tftboot/

Now we need to create our menu. Under the pxelinux.cfg directory we will need to make a file called default, which at this stage will look like this:

# Menu Entry for PXELINUX. Created 20170618 mvdw.

UI vesamenu.c32
PROMPT 0
TIMEOUT 600
DEFAULT memtest86
# Later we will move this to a separate file to be INCLUDEd here:
MENU TITLE Universal PXE Linux Bootloader
MENU BACKGROUND menu.png
MENU TABMSG  http://www.vandewerken.com.au/blog/
MENU WIDTH 72
MENU MARGIN 10
MENU VSHIFT 3
MENU HSHIFT 6
MENU ROWS 15
MENU TABMSGROW 20
MENU TIMEOUTROW 22
menu color title 1;36;44 #66A0FF #00000000 none
menu color hotsel 30;47 #C00000 #DDDDDDDD
menu color sel 30;47 #000000 #FFFFFFFF
menu color border 30;44    #D00000 #00000000 std
menu color scrollbar 30;44 #DDDDDDDD #00000000 none
# end include

LABEL memtest86
    menu label memtest86+-5.01
#    menu indent 1
    kernel /i386/memtest/memtest86+-5.01

#label Ubuntu Distributions
#    menu label Ubuntu Distributions ->
#    MENU INDENT 1
#    CONFIG /menu/ubuntu.cfg

#label System Tools
#    menu label System Tools ->
#    MENU INDENT 1
#    CONFIG /menu/system.cfg

A couple of points about this file before we go on. Firstly, there is a whole stack of stuff in there that we will later take out into a separate file to make it cleaner and allow the sub-menus to also include it. Also, you can see that I've added the future menu items, but they're commented out for now - first we'll get memtest86 going then worry about more fancy configuration (sub-menus and the like).

Configure DNSMasq

Now we want to edit /etc/dnsmasq.conf to enable the tftpserver portion without affecting either the local network DNS nor the local network DHCP. The default dnsmasq.conf file under Ubuntu 17.04 is completely commented out; we first back it up:

$ sudo cp /etc/dnsmasq.conf /etc/dnsmasq.conf.bak

then replace it with the following:

# Configuration file for dnsmasq.
#
# Format is one option per line, legal options are the same
# as the long options legal on the command line. See
# "/usr/sbin/dnsmasq --help" or "man 8 dnsmasq" for details.

# Disable DNS Server
port=0

# Enable DHCP logging
log-dhcp

# Respond to PXE requests for the specified network;
# run as DHCP proxy

dhcp-range=192.168.29.0,proxy
dhcp-boot=pxelinux.0

# Disable re-use of the DHCP servername and filename fields as extra
# option space. That's to avoid confusing some old or broken DHCP clients.
dhcp-no-override

# PXE menu.  The first part is the text displayed to the user.  The second is the timeout, in seconds.
pxe-prompt="Booting Network Client", 5

# Provide network boot option called "Network Boot".

# The known types are x86PC, PC98, IA64_EFI, Alpha, Arc_x86,
# Intel_Lean_Client, IA32_EFI, BC_EFI, Xscale_EFI and X86-64_EFI
# This option is first and will be the default if there is no input from the user.
pxe-service=x86PC,"Network Boot",pxelinux
# pxe-service=X86-64_EFI, "Network Boot x86-64 UEFI", <image-name>
# pxe-service=Xscale_EFI, "Network Boot ARM", <image-name>

enable-tftp
tftp-root=/data/tftpboot

Note that I have put my network in on the line with dhcp-range=; you will need to edit this to suit the network you have at your installation. Also note that for the moment we have only enabled x86 architecture - we will get to the other arches at a later stage but for now we will make sure we can boot it like this.

Now we need to make a quick hack to make sure our local dns on the server doesn't try to use its own dnsmasq, since we've disabled that functionality. To do this we edit /etc/default/dnsmasq and add the following line at the end:

DNSMASQ_EXCEPT=lo

Run and Test!

Now we restart the dnsmasq service:

$ service dnsmasq start

and we should be able to boot any i386 architecture machine on the network and run memtest86. Note that you may have to setup the BIOS of the target machine to be able to boot from the network.

Final Notes

If you've been following along with this blog and comparing it to the excellent Manski.net version, you will see that it's very similar. That's true, but in the next instalment I will extend this to be able to boot other OSes than just memtest, and then we'll look into other architectures and images.

Here's a link to the menu image file I used; feel free to copy and use for your own server. Credit to the excellent YUMI project from which the original of this came.

Thanks for reading, till next time.

Leave a Reply

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