One of the nice things about all current network cards is that virtually all of them are capable of booting to a network server. This tutorial will show you how to set up a server using the Preboot Execution Environment, or PXE (pronounced Pixie). It is very easy to set up and can be immensely useful. For the purposes of this tutorial, I will be using CentOS 5.5 x86_64 as the host system. All packages can be found in the official CentOS repositories. For the tutorial, I will use CentOS 5.5 x86_64 as the PXE boot OS as well. I will also have examples of some other systems you can set up to boot to, though I will not go into as much detail about them.

Install the Required Packages

First, we need to install some packages on our CentOS system. Some or all of these may already be installed on your system for other purposes.

yum install tftp-server syslinux httpd dhcpd

If you already have a DHCP server on your network somewhere, make sure you leave dhcpd off of the install list. Having two DHCP servers on a network can cause serious problems if they are not properly configured to work together. If you have a home router that functions as your DHCP server, check to see if it supports custom dnsmasq configurations. If it does (most custom Linux firmwares do), you can see my note at the bottom of this tutorial for setting up dnsmasq with the proper DHCP options.

Create and Configure the Boot Environment

The next step is to create a directory somewhere to hold all PXE boot files, menus, and OS images. The default location in the TFTP configuration file is /tftpboot, which is what I’ll use in this tutorial. Note that you can place the directory anywhere you like, but it has to be an actual directory. In my experience, it doesn’t seem to work with symbolic links in the path. So if you place it at /var/tftpboot, you can’t just create a symlink at /tftpboot -> /var/tftpboot to make it work with the defaults.

After we create the directory, we can configure the TFTP system so that it’s enabled and knows where to find its files. To do that, edit /etc/xinetd.d/tftp and change the following two lines:

disable = yes
server_args = -s /tftpboot

The disable option will need to change to no, obviously. The server_args option should point to the absolute path of whatever directory you created in the previous step. After you’re done, it should look like this:

service tftp
{
 socket_type = dgram
 protocol = udp
 wait = yes
 user = root
 server = /usr/sbin/in.tftpd
 server_args = -s /data/tftpboot
 disable = yes
 per_source = 11
 cps = 100 2
 flags = IPv4
}

Once that is configured, restart xinetd to force the changes to take effect.

/sbin/service xinetd restart

Copy Boot Files

The next step is to copy the required syslinux files into the /tftpboot directory. These files will make up the actual system that boots the remote machine into the initial menu.

cp /usr/lib/syslinux/{pxelinux.0,menu.c32,memdisk,mboot.c32,chain.c32} /tftpboot

Create the directory to place your PXE menu files in next. Also, create a base directory for the OS image files to go.

mkdir /tftpboot/pxelinux.cfg
mkdir /tftpboot/images

Create a subdirectory for the CentOS image files.

mkdir -p /tftpboot/images/centos/x86_64/5.5

Then mount the CentOS 5.5 x86_64 DVD disc 1 somewhere on your system. We will need to copy some files off of it into the image directory we just created.

mount -o loop /path/to/CentOS-5.5-x86_64-bin-DVD-1of2.iso /mnt

Copy vmlinuz and initrd.img from the DVD to the images directory.

cp /mnt/images/pxeboot/{vmlinuz,initrd.img} /tftpboot/images/centos/x86_64/5.5

Configure DHCP

Now we need to configure our DHCP server to tell clients using the BOOTP protocol where to find our PXE server. Replace the xxx.xxx.xxx.xxx in the following code with the IP address of your PXE boot server.

allow booting;
allow bootp;
option option-128 code 128 = string;
option option-129 code 129 = text;
next-server xxx.xxx.xxx.xxx;
filename "/pxelinux.0";

The filename option won’t have to change no matter where you put your tftpboot directory. The filename is absolute within that directory because the client doesn’t see any of the rest of your file system. It is confined to just that tftpboot directory, much like a jail would accomplish. Again, if you use a home router with a firmware that supports dnsmasq, see my notes below about setting it up to accomplish this same task for you.

Now restart your DHCP server.

service dhcpd restart

Set Up the Menus

The only step left is to create the menu that the client will see. This is actually the trickiest part because each Linux system you want to include will contain its own kernel boot parameters. You will need to consult with the documentation for each system to determine how to set it up for PXE booting. I will demonstrate using CentOS 5.5 x86_64 with and without a kickstart file. I will also show you how to create multi-tiered menus for more organized and sophisticated systems.

Single Tier Menu

To create a single tier menu, you only need to create one file. In /tftpboot/pxelinux.cfg, create a file named default. That will serve as our entire menu for now. At the top of this file, add the following text:

default menu.c32
prompt 0
timeout 300
ONTIMEOUT local

MENU TITLE PXE Menu

LABEL local
 MENU LABEL Boot local hard drive
 LOCALBOOT 0

You can change the values for timeout and MENU TITLE as you like. The local hard drive label is designed as a default in case the user does not select an option before the timeout period is reached.

After that, you will add an entry for each system you want to boot. The structure of each entry will be similar even though the values will be different. Basically, each will look like this:

LABEL xxxxx
 MENU LABEL xxxxx
 KERNEL path/to/kernel
 APPEND option1=xxxx option2=xxxx
 

For instance, to boot CentOS without using a kickstart file, you would set up the menu this way:

LABEL CentOS 5.5 x86_64
 MENU LABEL CentOS 5.5 x86_64
 KERNEL images/centos/x86_64/5.5/vmlinuz
 APPEND initrd=images/centos/x86_64/5.5/initrd.img ramdisk_size=100000 ip=dhcp url --url http://url.com/path/to/DVD/files/

The LABEL line is an internal label for that entry. The MENU LABEL parameter is what is displayed to the user. I usually keep them the same for clarity’s sake, but you can set them to whatever you like. The KERNEL parameter tells PXE where to find the kernel to boot. In this case, it’s in the images/centos/x86_64/5.5 directory inside our /tftpboot root directory. Always remember that any time you reference a file in that directory, you treat it as if you are sitting inside that directory. In the menu’s case, you do NOT use a leading / to indicate you are at the root tftpboot directory.

The APPEND option is what gets passed to the kernel when it loads. You can pass any valid kernel parameters you wish to tweak how the kernel will boot. In this case, I have specified the side of the RAMDisk to create and where the base CentOS images is at. I’ve also specified that the installation should use DHCP to obtain IP address information. The url kernel parameter is designed to tell it where to find the remainder of the installation files, but at the moment it appears to ignore that option. I’ll post back when I get a working parameter to force network booting of the OS files.

If you wish to make an entry that uses a kickstart file, it would look like this:

LABEL CentOS 5.5 x86_64 KS
 MENU LABEL CentOS 5.5 x86_64 KS
 KERNEL images/centos/x86_64/5.5/vmlinuz
 APPEND ks=http://url.com/path/to/kickstart.cfg initrd=images/centos/x86_64/5.5/initrd.img ramdisk_size=100000 ksdevice=eth0 ip=dhcp url --url http://url.com/path/to/DVD/files/

The main difference here is that there are two additional kernel parameters. The ks parameter tells the kernel where to find the kickstart file. It must be located on an FTP, HTTP, or NFS server that is accessible from the client. You cannot specify a file within the /tftpboot directory because the CentOS installation itself is what will read the file. The client PXE system that has booted is completely unaware of the PXE environment it booted from. The other additional paremeter is the ksdevice parameter. This tells the client which ethernet device to use to attempt to find the kickstart file. On multi-NIC systems, each NIC could be attached to a separate network segment, and that could cause problems if you don’t tell it which NIC to search on.

Multi-Tier Menus

The second menu type is multi-tiered. There is a main menu and one or more submenus that allow you to categorize different systems to boot to. For this, we will still create a default menu file in additional to one or more other menu files. To start with, lets take a look at the default menu.

default menu.c32
prompt 0
timeout 300
ONTIMEOUT local

MENU TITLE Main Menu

LABEL local
 MENU LABEL Boot local hard drive
 LOCALBOOT 0

This part of the menu is identical. However, the rest looks very different.

LABEL x86_64 Servers
 MENU LABEL x86_64 Servers
 KERNEL menu.c32
 APPEND pxelinux.cfg/x86_64_Servers

Basically, this tells PXE to use the same kernel that it’s currently using (menu.c32) and to load the menu file located at pxelinux.cfg/x86_64_Servers. What you would do next would be create a menu file called x86_64_Servers. It will look very similar to the main menu without much of the default options at the top.

MENU TITLE x86_64 Server Menu

LABEL Main Menu
 MENU LABEL Main Menu
 KERNEL menu.c32
 APPEND pxelinux.cfg/default

LABEL CentOS 5.5 x86_64
 MENU LABEL CentOS 5.5 x86_64
 KERNEL images/centos/x86_64/5.5/vmlinuz
 APPEND initrd=images/centos/x86_64/5.5/initrd.img ramdisk_size=100000 ip=dhcp url --url http://url.com/path/to/DVD/files/

LABEL CentOS 5.5 x86_64 KS
 MENU LABEL CentOS 5.5 x86_64 KS
 KERNEL images/centos/x86_64/5.5/vmlinuz
 APPEND ks=http://url.com/path/to/kickstart.cfg initrd=images/centos/x86_64/5.5/initrd.img ramdisk_size=100000 ksdevice=eth0 ip=dhcp url --url http://url.com/path/to/DVD/files/

As you can see, I also added a Main Menu option to return to the default menu. This is not necessary, but it provides some more convenient navigation capabilities to the end user. Once this is all saved, you should be able to connect your client to your network with any PXE compliant network card and boot to your remote system!

Dnsmasq and Linux Home Routers

As promised, I’m including a small section about using dnsmasq on your custom Linux home router. I use Tomato at home, and I have it set up to perform the same task as my DHCP configuration earlier in this tutorial. Go to your dnsmasq custom configuration page in your router’s online configuration site or the dnsmasq configuration file on the router’s file system. In Tomato 1.25, this is located at Advanced -> DHCP/DNS. Under the custom configuration section, type the following:

dhcp-boot=pxelinux.0,,xxx.xxx.xxx.xxx

Once again, we specify the pxelinux.0 file as if we were in the /tftpboot directory. The commas separate parameters for the dhcp-boot command. In between the two commas, you can place the hostname of the PXE server, but it is not necessary. The xxx.xxx.xxx.xxx is the IP address of the PXE boot server. Once you save the configuration and restart the built-in DHCP server (which happens automatically when you save in Tomato), your new clients will all receive the correct information for booting to a PXE server.

Additional Systems

I will post some additional systems here as I get more and more working. I will highlight custom paths that you will need to change. Some parts of paths will need to stay fixed as they are contained on the ISO of that Linux distribution.

Clonezilla 1.2.5-17

LABEL Clonezilla
 MENU LABEL Clonezilla
 KERNEL images/clonezilla/live/vmlinuz
 APPEND initrd=images/clonezilla/live/initrd.img boot=live union=aufs noswap noprompt vga=788 fetch=http://url.com/path/to/live/filesystem.squashfs

OpenSUSE 11.2

LABEL OpenSUSE 11.2
 MENU LABEL OpenSUSE 11.2
 KERNEL images/opensuse/linux
 APPEND initrd=images/opensuse/initrd splash=silent vga=0x314 showopts install=http://url.com/path/to/mounted/dvd/iso/