PXE - ether42/bootable-usb GitHub Wiki

Setup

On the rootfs:

apt-get install tftpd-hpa
systemctl disable tftpd-hpa

TFTP

tftpd-hpa's root is by default set to /srv/tftp in /etc/default/tftpd-hpa.

To log the clients' requests, increase the verbosity:

sed -i 's/TFTP_OPTIONS="--secure"/TFTP_OPTIONS="--secure --verbose"/' /etc/default/tftpd-hpa

Syslinux

Retrieve a recent version of Syslinux (the project's structure changed a bit to allow EFI support and is now more modular):

cd /tmp
wget -O - https://www.kernel.org/pub/linux/utils/boot/syslinux/syslinux-6.03.tar.gz | tar zxvf -

Copy the necessary files to boot on BIOS and 64-bit EFI machines (32-bit compatibility has similar steps):

# base files, ldlinux should be in the same directory as pxelinux
cp syslinux-6.03/bios/core/pxelinux.0 /srv/tftp/pxelinux.bios
cp syslinux-6.03/bios/com32/elflink/ldlinux/ldlinux.c32 /srv/tftp
cp syslinux-6.03/efi64/efi/syslinux.efi /srv/tftp/pxelinux.e64
cp syslinux-6.03/efi64/com32/elflink/ldlinux/ldlinux.e64 /srv/tftp

# all the modules
mkdir /srv/tftp/{bios,e64}
find syslinux-6.03/bios/ -name '*.c32' -and -not -name ldlinux.c32 | xargs -I{} cp {} /srv/tftp/bios
find syslinux-6.03/efi64/ -name '*.c32' | xargs -I{} cp {} /srv/tftp/e64

Create a configuration file for each supported architecture, specifying the modules' path and a common configuration:

for architecture in bios e64; do
  cat << EOF > /srv/tftp/"$architecture".cfg
PATH $architecture
INCLUDE common.cfg
EOF
done

Here is a basic common configuration that will perform a local boot by default (if unsupported by your hardware, change the ui parameter):

cat << EOF > /srv/tftp/common.cfg
timeout 100
totaltimeout 300

# ui menu.c32
ui vesamenu.c32
menu title PXE boot
menu color scrollbar 7;37;40

default local
ontimeout local

label local
  menu label Local boot
  text help
  Perform a local boot (default).
  endtext
  localboot 0
EOF

DHCP

Refer to the initial DHCP setup.

The DHCP server configuration is a bit more complex but more versatile. The goal is to not hardcode anything and redirect clients to the proper pxelinux file based on their architecture.

Create /etc/dhcp/pxe and include it:

# retrieve architecture
option architecture-type code 93 = unsigned integer 16;

# http://marc.info/?l=dhcp-hackers&m=118676179028480&w=2
option pxelinux-configfile code 209 = text;

class "pxe" {
  match if substring (option vendor-class-identifier, 0, 9) = "PXEClient";

  log(info, concat("PXE client '", option vendor-class-identifier, "' ",
                   "architecture type '0x", binary-to-ascii(16, 16, "", option architecture-type), "', ",
                   "boot file will be set to '0x", binary-to-ascii(16, 16, "", option architecture-type), ".boot', ",
                   "config file will be set to '0x", binary-to-ascii(16, 16, "", option architecture-type), ".cfg', ",
                   "symlink them on the TFTP server"));

  next-server 10.0.100.253;

  if exists dhcp-parameter-request-list {
    # 0xd1 is pxelinux-configfile option 209
    option dhcp-parameter-request-list = concat(option dhcp-parameter-request-list, d1);
  }

  option bootfile-name = concat("0x", binary-to-ascii(16, 16, "", option architecture-type), ".boot");
  option pxelinux-configfile = concat("0x", binary-to-ascii(16, 16, "", option architecture-type), ".cfg");
}

I know of the following architecture codes:

  • 0x0: BIOS
  • 0x6: seems to be for EFI 32
  • 0x7 & 0x9: seems to be for EFI 64

When a client boots, the DHCP will send the filenames of a boot and a configuration based on its architecture to fetch on the TFTP server. These files must be symlinked to the corresponding pxelinux.{bios,e64} and {bios,e64}.cfg.

For example:

ln -s pxelinux.bios 0x0.boot
ln -s bios.cfg 0x0.cfg

Images

It may be interesting to create a volume to store PXE images:

lvcreate -L 4GiB -n pxe lxc
mkfs.ext3 -L pxe /dev/lxc/pxe

And add the corresponding LXC configuration:

lxc.mount.entry = /dev/lxc/pxe srv/tftp ext3 defaults,create=dir 0 2

To be fancy, the ISO's filesystem.squashfs could be shared from the host (avoiding an unnecessary copy and allowing automatic updates):

lxc.mount.entry = /lib/live/mount/medium/live srv/tftp/images/live none bind,create=dir 0 0
lxc.hook.autodev = sh -c 'mkdir -p "$LXC_ROOTFS_MOUNT"/srv/tftp/images/live/filesystem.squashfs.d && mount "$LXC_ROOTFS_MOUNT"/srv/tftp/images/live/filesystem.squashfs "$LXC_ROOTFS_MOUNT"/srv/tftp/images/live/filesystem.squashfs.d'

And as such, PXE booting the Debian Live created by the scripts from this repository may be done with the following configuration:

label Debian Live
  menu label Debian Live
  kernel images/live/filesystem.squashfs.d/vmlinuz
  append initrd=images/filesystem.squashfs.d/initrd.img boot=live console=ttyS0,115200n8 console=tty0 persistence persistence-encryption=none,luks nofstab fetch=tftp://10.0.101.253/images/filesystem.squashfs

Compared with the options of the generated images, fetch has been added to specify the location of the base filesystem, toram and findiso have been removed. The options ip=frommedia and nopersistence may also be added as necessary.

⚠️ **GitHub.com Fallback** ⚠️