Changes RSS

====== Debian-based PXE boot setup ====== In this document, and the related documents in the guides:pxe namespace, I will document my PXE boot-server setup. It is my intention to have quite a few "features" in my setup, including: * Menu-based selection of boot options * Booting of installers for several open-source operating systems * Booting of Live-environments for several open-source OS. * A selection of system-tools, like disk-shredder, partitioning tools, disk-backup and antivirus * Support for chainloading other net-boot mechanisms. The setup is based on pxelinux, a part of the syslinux tools. In general, PXE-booting will be useful for booting x86/ia32-related hardware. ===== Prerequisites ===== Naturally, a boot-server requires some components apart from configuration files and such. Noteable components: * An operating system for the boot server. I am using Debian 5 "Lenny" as my server-platform * A TFTP daemon. From recommendations of other Debian users, I am switching to atftpd. * A DHCP server. As this setup is done for my home-network, this role is filled by my OpenBSD box. * An NFS server. I am using the same box for tftpd and nfs, and I am running nfs-kernel-server. ===== Installing the tftp dæmon ===== My choice of tftpd-dæmon fell on atftpd. This is a modern TFTP server using multi-threading, supports multicast tftp, option extension, large file-sizes and more. Particularly important for PXE is the support for the [[http://tools.ietf.org/html/rfc2349|RFC2349]] Transfer Size option. Installing atftpd is basically as simple as: <code> apt-get install atftpd </code> It may be noted that as a dependency, atftpd pulls in "inetutils-inetd". As this is done on a Debian system, the package maintainers of atftpd has placed the tftpboot (aka tftp root) directory according to Debian standard at /var/lib/tftpboot. If you are using a different platform, it is highly probable that atftpd will be referring to /tftpboot instead. On the other hand, if you are using Debian, and want /tftpboot in stead of /var/lib/tftpboot, either symlink, or edit /etc/default/atftpd to relocate. ===== Adding TFTP/bootpd settings to DHCP server ===== Note that this is from my OpenBSD DHCP server. These settings however should be directly compatible with the DHCPd in most common Linux distributions, and at least ISC DHCPd. <code> subnet 10.0.3.0 netmask 255.255.255.0 { option domain-name-servers 10.0.2.2; option routers 10.0.3.1; option tftp-server-name "10.0.2.13"; next-server 10.0.2.13; filename "pxelinux.0"; range 10.0.3.130 10.0.3.250; } </code> ===== Installing syslinux to get the pxelinux files... ===== PXELinux, the PXE Boot environment used in my, and most other linux-oriented, net-boot-setups, is not a stand-alone package, but part of the larger [[http://syslinux.zytor.com/wiki/index.php/The_Syslinux_Project|syslinux]] project. To install, pull in the following packages: <code> apt-get install syslinux syslinux-common </code> The files we need to continue will be living in /usr/lib/syslinux. For starters, we will want to have a basic set of syslinux modules/files available. We will be adding on modules as features are added to the setup. * pxelinux.0 is the actual PXE environment/loader * menu.c32 allows us the creation of text-based menus * chain.c32 allows us to have "Boot from hard drive" as a boot option. These files are to be copied from /usr/lib/syslinux to /var/lib/tftpboot. We also need the directory where pxelinux configurations will be stored. <code> cp /usr/lib/syslinux/{pxelinux.0,menu.c32,chain.c32} /var/lib/tftpboot mkdir /var/lib/tftpboot/pxelinux.cfg chmod a+rx /var/lib/tftpboot/pxelinux.cfg </code> ===== Setting up a test ===== Our first test will be to see if our PXE environment works at all. To do this, we'll set up a "welcome message", a chainload of the first local harddrive and a faux linux boot. <code> cat > /var/lib/tftpboot/boot.txt <<END This is a PXELinux bootserver. To boot linux, type 'linux<enter>' To boot from local drive, press <enter> END cat > /var/lib/tftpboot/pxelinux.cfg/default <<END DISPLAY boot.txt DEFAULT boot_hd0 LABEL boot_hd0 COM32 chain.c32 APPEND hd0 LABEL linux kernel debian/lenny/i386/linux append vga=normal initrd=debian/lenny/i386/initrd.gz -- PROMPT 1 TIMEOUT 120 END </code> So, no menu yet, just a real simple test. Using any PXE-capable client computer, test this setup. You should be presented with quite a bit of pxelinux output, followed but the contents of boot.txt and a prompt. Trying to boot the 'linux' LABEL should naturally fail, but still confirms that things are working. Booting the default option 'boot_hd0' should boot your system normally (assuming the first BIOS drive is your boot device). ===== First 'real-world' boot setup ===== Now, we will introduce the simples PXE-bootable installer, the Debian netinstall, and a menu to select it. We start by fetching the netboot-kit for Lenny: <code> mkdir /tmp/pxetmp; cd /tmp/pxetmp wget ftp://ftp.uio.no/debian/dists/lenny/main/installer-i386/20090123lenny6/images/netboot/netboot.tar.gz tar zxvf netboot.tar.gz mkdir -p /var/lib/tftpboot/debian/i386/lenny cp /tmp/pxetmp/debian-installer/i386/initrd.gz var/lib/tftpboot/debian/lenny/i386 cp /tmp/pxetmp/debian-installer/i386/linux /var/lib/tftpboot/debian/lenny/i386 </code> Now, we change /var/lib/tftpboot/pxelinux.cfg/default a little bit to start using menus. Replace the contents: <code> DEFAULT menu.c32 MENU TITLE PXE Boot menu 0.1 LABEL linux MENU LABEL Debian Lenny i386 netinstall KERNEL debian/lenny/i386/linux APPEND vga=normal initrd=debian/lenny/i386/initrd.gz -- LABEL boot_hd0 MENU LABEL Boot from first hard drive MENU DEFAULT COM32 chain.c32 APPEND hd0 PROMPT 0 MENU WIDTH 80 MENU MARGIN 10 MENU ROWS 12 MENU TABMSGROW 18 MENU CMDLINEROW 12 MENU ENDROW 24 MENU TIMEOUTROW 20 ONTIMEOUT boot_hd0 TIMEOUT 200 </code> ===== Getting fancy ===== The setup will now introduce quite a few components: * "Graphical" menu using vesamenu.c32 * A fancy background image * Common menu-config with color and layout settings for vesamenu.c32 * Nested/chained menus. We will set the basic framework using the two working options we already have in our menu to introduce the concept. After this, all elements of the sub-menus are simply variations on the basic setup we make here, and all specifics for each menu/os/installer/tool will be presented on separate pages. ==== Preparing vesamenu.c32 ==== A text-based menu is swell, and probably recommended for some older platforms, but I wanted a menu with a tad of "bling" and a "modern" feel. Most of the boot-cds and images for Linux distributions these days use a VESA graphics syslinux/grub setup, and I wanted to do the same. The menu.c32 comboot module provides the menu we used in the previous step. To move from the text-only menu, to a 'graphical' menu with a background-image and more, we simple need to use vesamenu.c32 in place of menu.c32, and add some vesamenu-specific options. Pull in vesamenu.c32 from the syslinux packages: <code> cp /usr/lib/syslinux/vesamenu.c32 /var/lib/tftpboot </code> Next, get/create a suitable background image to use, and place it in the tftpboot-hierarchy. This is the background image I started out with, stored as /var/lib/tftpboot/menus/background.png {{:guides:pxemenu-background.png?160|background.png}} The specs for image-files that vesamenu.c32 accepts are fairly simple: A 640x480 pixels PNG or JPG image, displayable at 16bpp. So, more or less any 640x480 PNG will do. ==== Some words about directory hierarchy layout ==== Since I am going to be putting rather large amounts of files in both TFTP and NFS shares, it does not hurt to have a plan for structuring content. For the tftpboot directory: ^ TFTP ^^ ^ Directory ^ Use ^ | /var/lib/tftpboot/ | Root of TFTP data, and location for pxelinux/syslinux binaries| | /var/lib/tftpboot/pxelinux.cfg/ | Contains the default cfg-file | | /var/lib/tftpboot/menus/ | Location for all files used to create the actual pxelinux-menus | | /var/lib/tftpboot/menus/$dist.cfg | Sub-menu for a given OS distribution | | /var/lib/tftpboot/$dist/$ver/$arch | Files needed for TFTP-boot of OS Installer | | /var/lib/tftpboot/live/$dist/$ver/$arch | Files needed for TFTP boot of Live-system | ^ NFS ^^ ^ Directory ^ Use ^ | /srv/boot/install/$dist/$ver/$arch | NFS share for OS installer files | | /srv/boot/live/${DIST}/$dist/$ver/$arch | NFS share for Live-boot OS files | So, a 32-bit Ubuntu 10.4 Live environment will use the paths: * /var/lib/tftpboot/menus/ubuntu.cfg for its menu-option * /var/lib/tftpboot/live/ubuntu/10.4/i386 for kernel- and initrd * /srv/boot/live/ubuntu/10.4/i386 as NFS root for the Live-environment. Naturally, some installers will need various degrees of "fixed location" for files, but the above is the "standard" that these deviate from. ==== Common configuration ==== Aiming to use multiple sub-menus, it will be very useful to gather all common configuration to one location, and avoid having to retype/copy the same settings to all menu-configurations. Luckily the syslinux menu system allows us to include settings from different files, and this is the mechanism we'll use to centralize common settings. My common configuration looks like this: <code> # /var/lib/tftpboot/menus/common.cfg MENU BACKGROUND menus/background.png ALLOWOPTIONS 1 PROMPT 0 MENU WIDTH 77 MENU ROWS 14 MENU TABMSGROW 25 MENU CMDLINEROW 25 MENU HELPMSGROW 23 MENU MARGIN 15 MENU VSHIFT 4 MENU COLOR BORDER 30;44 #00000000 #00000000 none MENU COLOR SEL 7;37;40 #ffffffff #9090a0f0 std MENU COLOR HOTSEL 7;37;40 #ffffffff #204040f0 std MENU COLOR TIMEOUT_MSG 37;40 #aaaaaaaa #00000000 std MENU COLOR TIMEOUT 1;37;40 #ffaaaaff #00000000 std MENU SEPARATOR </code> Line for line description * Set the background image (path relative to tftp root) * ALLOWOPTIONS 1 * Disable the command/loader prompt * Set the width, in characters, of the menu * Set the height, in text-rows, of the menu. * Set the location of the "Press TAB" text * Set the location of the commandline when user presses TAB * Set the location of the HELP text/verbose info * Add a left-margin of 15 characters on the menu (move right) * Shift the menu 4 text-rows down from default location * Remove the border of the menu * Set the colors and shading of the selection-bar * Set the colors and shading of the menu hotkeys when selected * Set the color of the "Autoboot in" string * Set a different color for the TIME indicator. * Add a fixed "space" between the header and the menu items. Naturally, more look-and-feel options may be added here. Also, settings like password-protection are prime candidates for the common.cfg file. ==== Nested menus ==== So, we have our common configuration and COM32 modules ready. Let us modify pxelinux.cfg/default completely, and let it become our main menu. There are quite a few ways to build a complex menu system with syslinux. One approach is to use "MENU TITLE" to create submenus directly in the global configuration. This has the advantage that any LABEL of the menu and submenus can be typed directly on a prompt to boot. But, in my opinion, it also makes the menu vulnerable to errors in INCLUDE'd parts of the config. Another option is to chain-load the menus. This is related, but not as good, as the third option: loading each sub-menu as a COM32 module, with a separate complete config file for each sub-menu. This is a reliable approach, and a flexible one when debugging. Every time you select a sub-menu, or to return to the main menu, the entire config is re-read and applied. So, you can test changes to the menu by navigating back and forth in it. This naturally implies that the vesamenu.c32 and sub-menu config files will need to be transferred over TFTP every time you change menus, but in regard of the flexibility it gives for changing the menu on-the-fly is in my eyes a big plus, and the final selling point for me is the fact that a borken sub-config will not break my entire setup. The initial main menu configuration looks like this: <code> # /var/lib/tftpboot/pxelinux.cfg/default DEFAULT vesamenu.c32 MENU INCLUDE menus/common.cfg MENU TITLE PXE Boot menu 0.1 LABEL debian MENU LABEL ^1 Debian TEXT HELP Debian installers and live-boot options. ENDTEXT COM32 vesamenu.c32 APPEND menus/debian.cfg MENU SEPARATOR LABEL boot_hd0 MENU LABEL Boot from first hard drive MENU DEFAULT TEXT HELP Boots your system as normal from the first BIOS drive ENDTEXT COM32 chain.c32 APPEND hd0 ONTIMEOUT boot_hd0 TIMEOUT 300 </code> I choose to use the COM32 loader-keyword, opposed to KERNEL. Using KERNEL will normally auto-detect what type of image/boot-program it is trying to load by looking at the file suffix or magic number, it just feels more correct to say COM32 when I know that is what I am going to load. Note that the pxelinux.cfg/default is the only configuration file in my setup that has the line "DEFAULT vesamenu.c32" included. This is because for all the sub-menus, the module is already loaded by being the actual image "booted". In all the sub-menus, I include a "Return to Main Menu" option on the top, to loads the default config and thus the main menu. <code> # /var/lib/tftpboot/menus/debian.cfg MENU INCLUDE menus/common.cfg MENU TITLE Debian Installers LABEL mainmenu MENU LABEL ^R Return to Main Menu COM32 vesamenu.c32 APPEND ~ MENU SEPARATOR LABEL lenny_i386_install MENU LABEL ^1 Debian Lenny i386 netinstall KERNEL debian/lenny/i386/linux APPEND vga=normal initrd=debian/lenny/i386/initrd.gz -- TIMEOUT 900 </code> In the menus I am extensively using hotkeys. Hotkeys are identified my a caret (^) directly infront of the character used as the hot-key. Hotkeys should be in the A-Z,0-9 range, to make sure that you are independent of misc keyboard layouts. Hotkeys can also (naturally) only be assigned once in a single menu. If you asssign the same hotkey to multiple options, they will display as hot-keys, but none of them will be selected by pressing the key. Seeing how I load the menus using the COM32 keyword with an APPEND line, you should be able to notice that there is really no limit on how deep you can nest your menus, and that it is fully possible to use the same menu as a "sub" in multiple places.