Netboot PXE Live CD Multiple Releases

This article details how to configure a stream-lined net-boot server for PXE clients using DHCP, TFTP and NFS to run live-CD images, custom-debugging, and diskless clients. Network clients can use PXE to boot using files on a server. The aim is to loop-mount the ISO images so that both TFTP and NFS have access to them.

It also shows how to configure net-boot PowerPC ISO images for Apple iMac/iBook NewWorld PowerPC using a modified yaboot (Yet Another Boot loader) that supports kernel and initrd images larger than 6MB. (This section will be added soon).

Because TFTP uses a chroot jail the mounts are done inside the jail and then bound (mount --bind) to locations in the NFS server tree. TFTP needs access to the (compressed) kernel image vmlinuz and initial RAM-disk image initrd.gz. It also needs a minimum of three PXE boot files: the boot-strap code (pxelinux.0), the menu code (menu.c32), and the menu text configuration (pxelinux.cfg/default).

NFS needs access to all other files from the CD/installed images.

In this article the sub-net DHCP server is on (WRT54GL running dd-wrt). The TFTP/NFS server is The net-boot client will get a dynamic IP in the range through

DHCP options

DHCP and the Bootp protocols provide an IP address for a client to network boot (performed by client's PC BIOS).

DHCP Daemon

DHCP and TFTP on Same Server

The TFTP server is running on the same host and interface as the DHCP/Bootp server:

subnet netmask {
    filename "pxelinux.0";

TFTP on Separate Server

The TFTP server is installed on which is a separate server:

subnet netmask {
    filename "pxelinux.0";


Provide the file-name and IP address of the TFTP server where the client will get the boot images.


Note: If using dd-wrt on a router and adding this setting via the web interface, it should be added in the Additional DNSMasq Options text-area not the Additional DHCPd Options text-area.

TFTP Server

sudo apt-get install tftpd-hpa

The network-accessible files will be installed in /var/lib/tftpboot/.

PXE Configuration


Copy the PXE boot-loader and menu binary executables from the syslinux package (the package may need installing first):

sudo apt-get install syslinux
sudo cp /usr/lib/syslinux/pxelinux.0 /var/lib/tftpboot/
sudo cp /usr/lib/syslinux/menu.c32 /var/lib/tftpboot/

Create a sub-directory

sudo mkdir -p /var/lib/tftpboot/pxelinux.cfg

and create the file /var/lib/tftpboot/pxelinux.cfg/default with an entry for each bootable image the PXE server will offer:

Note: The contents of indented lines following each append should be all on one line in the file. They are wrapped here to prevent ultra-long lines and scrolling to read.

DEFAULT menu.c32
ONTIMEOUT localboot

LABEL localboot
        MENU LABEL ^Local Boot (from CD or Hard Disk)
        LOCALBOOT 0
        TIMEOUT 600

LABEL 10.04 Lucid x86 32-bit Ubuntu Alternate
    kernel iso-image/ubuntu-10.04-alternate-i386/install/netboot/ubuntu-installer/i386/linux
    append netboot=nfs nfsroot= initrd=iso-image/ubuntu-10.04-alternate-i386/install/netboot/ubuntu-installer/i386/initrd.gz 
LABEL 10.04 Lucid x86 64-bit Ubuntu Live
    kernel iso-image/ubuntu-10.04-desktop-amd64/casper/vmlinuz
    append boot=casper netboot=nfs nfsroot= initrd=iso-image/ubuntu-10.04-desktop-amd64/casper/initrd.lz 
LABEL 10.04 Lucid x86 32-bit Ubuntu Live DEBUG netconsole
    kernel iso-image/ubuntu-10.04-desktop-i386-DEBUG/casper/vmlinuz
    append boot=casper netboot=nfs nfsroot= initrd=iso-image/ubuntu-10.04-desktop-i386-DEBUG/casper/initrd.lz essential=e100 netconsole=@,@
LABEL 10.04 Lucid x86 32-bit Ubuntu Live
    kernel iso-image/ubuntu-10.04-desktop-i386/casper/vmlinuz
    append boot=casper netboot=nfs nfsroot= initrd=iso-image/ubuntu-10.04-desktop-i386/casper/initrd.lz 
LABEL 10.04 Lucid x86 32-bit Xubuntu Alternate
    kernel iso-image/xubuntu-10.04-alternate-i386/install/netboot/ubuntu-installer/i386/linux
    append netboot=nfs nfsroot= initrd=iso-image/xubuntu-10.04-alternate-i386/install/netboot/ubuntu-installer/i386/initrd.gz 
LABEL 10.04 Lucid x86 32-bit Xubuntu Live
    kernel iso-image/xubuntu-10.04-desktop-i386/casper/vmlinuz
    append boot=casper netboot=nfs nfsroot= initrd=iso-image/xubuntu-10.04-desktop-i386/casper/initrd.lz 

If a PC (or group of PCs) requires a customised set of options a menu can be created where the menu file-name matches all or part of (in order) the BIOS GUID, MAC address, or IP address. See /usr/share/doc/syslinux/pxelinux.txt.gz for details. Here's an example:

If the boot file name is /var/lib/tftpboot/pxelinux.0, the UUID is b8945908-d6a6-41a9-611d-74a6ab80b83d, the Ethernet MAC address is 88:99:AA:BB:CC:DD and the IP address ( == hexadecimal C000025B), it will try:


CD Images

To avoid needing to extract ISO CD/DVD images they can be mounted directly into the file system. The paths must match what is specified in the PXE menu entries.

In my system all the downloaded ISOs are kept together. I use separate sub-directories for the different Ubuntu sub-projects such as Xubuntu (this is especially helpful for the current development images since the ISO names for sub-project ISOs can be the same as the Ubuntu ISOs) and use symbolic-links in the top-most directory, along with extracted images in sub-directories that can be altered for debugging:

/home/all/iso-image/ubuntu-10.04-alternate-i386.iso -> ubuntu/ubuntu-10.04-alternate-i386.iso
/home/all/iso-image/ubuntu-10.04-alternate-powerpc.iso -> ubuntu/ubuntu-10.04-alternate-powerpc.iso
/home/all/iso-image/ubuntu-10.04-desktop-amd64.iso -> ubuntu/ubuntu-10.04-desktop-amd64.iso
/home/all/iso-image/ubuntu-10.04-desktop-i386.iso -> ubuntu/ubuntu-10.04-desktop-i386.iso
/home/all/iso-image/ubuntu-10.04-desktop-powerpc.iso -> ubuntu/ubuntu-10.04-desktop-powerpc.iso
/home/all/iso-image/xubuntu-10.04-alternate-i386.iso -> xubuntu/xubuntu-10.04-alternate-i386.iso
/home/all/iso-image/xubuntu-10.04-desktop-i386.iso -> xubuntu/xubuntu-10.04-desktop-i386.iso

Because the TFTP daemon runs in a chroot jail the ISO images must be mounted as descendants of /var/lib/tftpboot/.

Manual Mount/Export? Creation

Create a holding directory:

sudo mkdir -p /var/lib/tftproot/iso-image

Mount each bootable CD image:

sudo mkdir -p /var/lib/tftproot/iso-image/ubuntu-10.04-desktop-i386
sudo mount -t iso9660 -o loop /home/all/iso-image/ubuntu-10.04-desktop-i386.iso /var/lib/tftpboot/iso-image/ubuntu-10.04-desktop-i386

NFS Server Configuration

It is recommended to use the NFS server built into the Linux kernel so install the user-space administration package:

sudo apt-get install nfs-kernel-server

Create directories that will be used as mount-points for other paths (this avoids putting files in an unusual location or using unusual long paths in NFS mount references):

sudo mkdir -p /srv/boot/iso-image

Link this directory to the TFTP daemon's chroot jail:

sudo mount --rbind /var/lib/tftpboot/iso-image /srv/boot/iso-image

Note: Use --rbind here since the sub-mount(s) of /var/lib/tftpboot/iso-image/ need to be exposed (--bind won't expose sub-mounts).

Export the file-systems for each mount --rbind:

sudo exportfs -i -o async,no_root_squash,no_subtree_check,ro  

Network Boot

Automated Start/Stop? Script

The TFTP and NFS exports can be done automatically using my attached pxe-prepare script Download. The script is called with either the start or stop command and will create or remove the mount and export for each ISO image or sub-directory in the CD image root directory but only when there is an associated .pxelabel file.

 sudo pxe-prepare start
stop: Unknown instance: 
mounting ISO ubuntu-10.04-alternate-i386
 TFTP: iso-image/ubuntu-10.04-alternate-i386
mounting ISO ubuntu-10.04-alternate-powerpc
 TFTP: iso-image/ubuntu-10.04-alternate-powerpc
mounting ISO ubuntu-10.04-desktop-amd64
 TFTP: iso-image/ubuntu-10.04-desktop-amd64
mounting directory ubuntu-10.04-desktop-i386-DEBUG
 TFTP: iso-image/ubuntu-10.04-desktop-i386-DEBUG
mounting ISO ubuntu-10.04-desktop-i386
 TFTP: iso-image/ubuntu-10.04-desktop-i386
mounting ISO ubuntu-10.04-desktop-powerpc
 TFTP: iso-image/ubuntu-10.04-desktop-powerpc
mounting ISO xubuntu-10.04-alternate-i386
 TFTP: iso-image/xubuntu-10.04-alternate-i386
mounting ISO xubuntu-10.04-desktop-i386
 TFTP: iso-image/xubuntu-10.04-desktop-i386
tftpd-hpa start/running, process 7248

sudo pxe-prepare stop
unmounting ubuntu-10.04-alternate-i386
unmounting ubuntu-10.04-alternate-powerpc
unmounting ubuntu-10.04-desktop-amd64
unmounting ubuntu-10.04-desktop-i386
unmounting ubuntu-10.04-desktop-i386-DEBUG
unmounting ubuntu-10.04-desktop-powerpc
unmounting xubuntu-10.04-alternate-i386
unmounting xubuntu-10.04-desktop-i386
tftpd-hpa stop/waiting

Client Boot

On the client PC enable PXE net-boot in BIOS. Restart. The BIOS will either ask for a particular key to be pressed to attempt a net-boot or will try it as part of the boot order.

The PC will report the progress of the PXE boot attempt. If successful the PXE menu will be shown. Selecting an option will cause the kernel image (vmlinuz) and the initial ram-disk image (initrd.gz) to be fetched. The casper scripts will handle the mounting of the NFS server CD image at /cdrom and will then proceed to boot. It can take some time if the network is slow (e.g. a WiFi? network).

Netconsole Debugging

Sometimes it is useful to capture the kernel log messages during boot-time. If the client and manager PC have serial ports (many PCs do not) a null-modem cable can be used.

However, seeing as the PC is booting over the network it makes sense to make use of the kernel's netconsole facility to echo the messages to another PC. That could be a syslog server or simply the netcat process.

Log Server

Use netcat to listen for UDP packets on the default netconsole target port (6666). Optionally specify the server's interface to listen on (useful when multi-homed):

nc -vv -u -l -p 6666 -s

Modified live-CD Initial RAM-disk Image

Now the live-CD's casper/initrd.gz needs netconsole adding to the list of modules it should load. The 'regular' way would be to add module entries to the initrd /conf/modules file and ensure the corresponding modules are in its /lib/modules/$(uname -r)/ directory.

However, I've been experimenting with an alternative that alters the initrd /init script so that both prerequisite modules (network device drivers) and netconsole itself can be demand-loaded via the kernel command-line. I'd like to get the mechanism accepted into the initramfs-tools package so that future live-CD's (and installed systems) have this additional flexibility.

For now, which-ever mechanism is used, the initrd image has to be expanded, altered, and rebuilt.

Mount ISO Image

Mount the ISO CD image into the file-system:

sudo mkdir /mnt/live-cd
sudo mount -t iso9660 -o loop /home/all/iso-image/ubuntu-10.04-desktop-i386.iso /mnt/live-cd

Create a Working Copy

The image needs to be altered so a working copy will be used.

mkdir /home/all/iso-image/ubuntu-10.04-desktop-i386-DEBUG
cp -a /mnt/live-cd/* /home/all/iso-image/ubuntu-10.04-desktop-i386-DEBUG/

Extract Initrd

Create a temporary location and extract the image contents:

mkdir /tmp/initrd
cd /tmp/initrd

For initrd images compressed using gzip + tar (pre-Karmic 9.10):

zcat /home/all/iso-image/ubuntu-9.04-desktop-i386-DEBUG/casper/initrd.gz | cpio -i -d

For initrd images compressed using lzma (Karmic 9.10 and later):

lzma -dc -S .lz /home/all/iso-image/ubuntu-10.04-desktop-i386-DEBUG/casper/initrd.lz | cpio -id

Patch to /init Script

Download the init.patch file attached to this article Download. It adds an additional kernel command-line option (essential=) and detects the netconsole= option and when found, loads the module with the given parameters.

cd /tmp
wget -N

Apply it using:

cd /tmp/initrd
patch -p3 < /tmp/init.patch

Ensure Network Module is Included

This step is dependent on the network device in the PC. First identify the network chip-set and from that the kernel module that drives it. Check the module is included in the initrd image. For example, the Intel e100 is used by the PC so:

cd /tmp/initrd
find ./lib/modules/ -name 'e100*'


If the kernel module isn't in the initrd image copy it from an installed system that uses the same kernel version or mount the live-CD's squashfs file-system and copy it from there:

mkdir /mnt/squash
sudo mount -t squashfs -o loop /home/all/iso-image/ubuntu-10.04-desktop-i386-DEBUG/casper/filesystem.squashfs /mnt/squash

Now it is possible to locate the module. Let's use e100 again as an example - in practice this step is only needed if the module isn't in the initrd image:

find /mnt/squash/lib/modules -name 'e100.ko'


cp /mnt/squash/lib/modules/2.6.32-22-generic/kernel/drivers/net/e100.ko /tmp/initrd/lib/modules/2.6.32-22-generic/kernel/drivers/net/e100.ko

sudo umount /mnt/squash

Rebuild Initrd

Collect the list of file names, re-create the cpio archive and compress it.

cd /tmp/initrd

For initrd compressed with gzip (pre-Karmic 9.10):

find . | cpio -o -H newc | gzip > /tmp/initrd.gz

For initrd compressed with lzma (Karmic 9.10 and later):

find . | cpio --dereference -o -H newc | lzma -7 > /tmp/initrd.lz

Copy Back to live-CD Working Copy

Replace the original (pre-Karmic 9.10):

cp /tmp/initrd.gz /home/all/iso-image/ubuntu-9.04-desktop-i386-DEBUG/casper/

or (for Karmic 9.10 and later):

cp /tmp/initrd.lz /home/all/iso-image/ubuntu-10.04-desktop-i386-DEBUG/casper/

Modified PXE Boot Menu Entry

The netconsole parameters need adding to the kernel command line. This could be done manually by editing the menu at boot-time but it makes more sense to add a custom debug entry to the PXE menu.

With the additional essential= parameter it is possible to ensure the network device driver is loaded before netconsole starts - a requirement for netconsole to work. In this example the Intel e100 driver is being loaded. When using netconsole it is useful to increate the verbosity of kernel messages using debug (Note: when using debug the upstart /init script writes a boot-log to /dev/.initramfs/initramfs.debug and /casper.log - copied to /var/log/ when the root file-system is ready).

Add an entry to /var/lib/tftpboot/pxelinux.cfg/default:

LABEL 10.04 Lucid 32-bit Live DEBUG netconsole
        kernel iso-image/ubuntu-10.04-desktop-i386-DEBUG/casper/vmlinuz
        append debug boot=casper netboot=nfs
          essential=e100 netconsole=@,@ --

The format is netconsole=[local-port]@[local-ip-address]/[interface],[target-port]@<target-ip-address>/[target-mac-address] (<required>, [optional]).

Note: Although netconsole will use the default local-ip-address if one isn't given, it doesn't appear to work directly or with broadcast unless an IP address is specified. This can be a problem if multiple PCs might use the PXE netconsole facility and may require manual intervention at the PXE boot menu by the user to set a free IP address.