October 22, 2011

Setting up a PXE Netboot Server for Network Installations of GNU/Linux

Filed under: Uncategorized — aspensmonster @ 11:07 pm

Flattr this!

Note: All commands are run as root unless otherwise specified

On a whim, I decided to give this a shot. Network booting has always been interesting to me, but I never got around to fiddling with it. Now I have. The general process was as so:

  1. Obtain a DVD of CentOS 6 and install on the box that will become the boot server. In my case, I have the dhcp, tftp, and httpd services all on the same box and this guide is for that scenario (though in principle there is nothing stopping you from having different boxes for each service).
  2. Configure CentOS 6 (upgrade and configure network devices)
  3. Mount the DVD and copy its contents to disk
  4. Install and configure the netboot software (tftp, syslinux, dhcp)
  5. BONUS: getting a pretty background image for the menu 😛
  6. TODO: Using kickstart files to completely automate the process.

I will not cover step one in detail. Suffice it to say I downloaded the CentOS 6 DVD and chose –I believe– “Server Environment” when prompted for a type of installation.

2.) Setting up CentOS 6

After I had CentOS installed, the next step was to set up the network and upgrade:

 dhclient eth0
 yum upgrade
 shutdown -r now
 dhclient eth0
 service iptables restart

“system-config-network-tui” simply sets up the networking devices. In my case, eth0. “dhclient eth0″ grabs an IP address for the NIC with label “eth0″ from an available DHCP server (my router in this case). I then upgrade and reboot. I then get another IP for the NIC, and then set up the firewall. Specifically, I make sure that ssh and tftp are enabled so that clients can talk to the netboot server over port 69 (tftp’s port).

3.) Mount DVD and copy files to disk

We now need to place our installation files somewhere where the installer can get to them. Two common methods are via NFS or HTTP. That is, either set up your netboot server to have an NFS and give the client read-only access to an NFS root that contains the installation files, or else set up apache and let the installer pull the files via HTTP. Seeing as I work in the web hosting industry, I went with Apache :)

 yum install httpd
 mkdir /var/www/html/centos
 mount /dev/cdrom1 /mnt
 cd /mnt
 cp -R * /var/www/html/centos

Your mount command is probably going to be somewhat different. The key point is that you can pull the files from the DVD onto the filesystem. This will probably take at least 20 minutes. I took a break and came back an hour later.

4.) Install and configure tftp, dhcp, syslinux

This is the meat and potatoes of the guide. First install everything:

 yum install tftp-server syslinux dhcpd

And now I have a brief overview of each configuration file and its architecture before I just flood you with different configuration layouts.

  • /etc/xinetd.d/tftp : This is the main configuration file for the tftpd daemon (which in our case is handled by the xinetd daemon). It specifies the root of the tftp server, usually either “/tftpboot” or in my case “/var/lib/tftpboot” via the “server_args” option. Any files for PXE booting, such as kernel images, need to go in this area. I will go into further detail below.
  • /etc/dhcp/dhcpd.conf : This is the main configuration file for the dhcpd daemon. In particular, if we want our dhcpd daemon to run a certain program, such as a pxelinux binary in our case, it will need to be told to permit pxe booting and be told where that binary is. Note: The dhcpd daemon only sees inside the tftpd root directory, such as “/tftpboot” or “/var/lib/tftpboot”. I.e., dhcpd daemon’s visibility is determined by the “server_args” option in the “/etc/xinetd.d/tftp” configuration file. This is because the “-s” flag you’ll probably see in the “server_args” option of the /etc/xinetd.d/tftp conf file stands for “secure” and sets up a chroot at the given directory that dhcpd will be stuck in.
  • /var/lib/tftpboot/pxelinux.cfg/default : This configuration file describes the menu layout that will be presented to netbooting clients. I.e., boot locally (from whatever is already on the hard drive) or boot from network to install CentOS (or any other distro files you have). It takes lots of different arguments. It is not created by default. It is something we will make further below.

Populate our chroot

At this point, it’s time to populate our tftp chroot, in my case located at “/var/lib/tftpboot/”, with the files necessary for PXE to do its job. When we installed syslinux, it gave us some important files that we will need to copy to “/var/lib/tftpboot/”. Let’s start there:

 cd /usr/share/syslinux
 cp pxelinux.0 menu.c32 memdisk mboot.c32 chain.32 /var/lib/tftpboot

Ok, so we’ve got all of the basic PXE stuff we need. But what about the kernel images we will be sending the client so that they can begin the installation process? Indeed, we need to place those here as well. Specifically, the “/var/lib/tftpboot/pxelinux.cfg/default” configuration file has arguments that will search a directory inside “/var/lib/tftpboot” for those images. Let’s make the directory structure that will hold our images and then put them there:

 cd /var/lib/tftpboot
 mkdir -p images/centos/x86_32/6.0
 cd /mnt/images/pxeboot
 cp initrd.img vmlinuz /var/lib/tftpboot/images/centos/x86_32/6.0

The directory “images/centos/x86_32/6.0″ is arbitrary, you can name it differently. Just be sure to be consistent. After making the directory, I cd’d into the DVD (mounted at /mnt, remember?) and copied the initrd.img and vmlinuz specific for pxe booting to the directory I made inside of /var/lib/tftpboot.

At this point, all of the files are in their proper places and now we can muck around with config files.

Set up /etc/xinetd.d/tftp

I prefer to start with “/etc/xinetd.d/tftp”. This is how mine looks:

# default: off
# description: The tftp server serves files using the trivial file transfer \
#       protocol.  The tftp protocol is often used to boot diskless \
#       workstations, download configuration files to network-aware printers, \
#       and to start the installation process for some operating systems.
service tftp
        socket_type             = dgram
        protocol                = udp
        wait                    = yes
        user                    = root
        server                  = /usr/sbin/in.tftpd
        server_args             = -s /var/lib/tftpboot
        disable                 = no
        per_source              = 11
        cps                     = 100 2
        flags                   = IPv4

I’ve highlighted the important lines. Notice the server_args has the “-s” flag which sets up a chroot at /var/lib/tftpboot where tftpd and dhcpd will reside. Most importantly, you’ll want to set “disable” to “no” (it is set to “yes” by default). That’s all you really need to do here.

Set up /etc/dhcp/dhcpd.conf

Now, onto “/etc/dhcp/dhcpd.conf”. Mine is below:

# DHCP Server Configuration file.
#   see /usr/share/doc/dhcp*/dhcpd.conf.sample
#   see 'man 5 dhcpd.conf'
allow booting;
allow bootp;

subnet netmask {

filename "/pxelinux.0";
default-lease-time 86400;
max-lease-time 86400;

option routers;

option broadcast-address;
option subnet-mask;

option domain-name-servers;
option domain-name-servers;


I’ve highlighted the lines that you will need to have in your configuration (the ones at the top). They tell the dhcpd daemon to:

  • Permit pxeboot : “allow bootp” and “allow booting”
  • Load the pxe file : “file name “/pxelinux.0″ ; recall that this is actually at /var/lib/tftpboot/pxelinux.0 but we’re inside of a chroot.

Depending on your network topology and setup, the options that go here may vary. In my case, with pxe/tftp, dhcp, apache all on one box, this works fine. I believe the “option routers″ tells dhcpd that it’s actually behind a router at the address, for example, and that’s why I’ve included it in the configuration file (though I don’t honestly know if its necessary). There are many other options you can throw at dhcpd.conf for various topologies. I’m no expert with DHCP –just another line in my personal “TODO” file I suppose 😛 — but there are various other guides that have different advise for dhcpd.conf for different scenarios:

Set up /var/lib/tftpboot/pxelinux.cfg/default

You might have noticed that the “pxelinux.cfg” directory doesn’t exist. Just make it:

cd /var/lib/tftpboot
mkdir pxelinux.cfg
cd pxelinux.cfg
touch default

What this has done is create an empty “default” file at “/var/lib/tftpboot/pxelinux.cfg/default”. This is what mine looks like:

default menu.c32
prompt 0
timeout 500


LABEL local
        MENU LABEL Boot to local hard drive
        LOCALBOOT 0

LABEL CentOS 6.0 x86_32
        MENU LABEL CentOS 6.0 x86_32
        kernel images/centos/x86_32/6.0/vmlinuz
        APPEND initrd=images/centos/x86_32/6.0/initrd.img ip=dhcp

This sets up a basic menu from which to chose different options. The “LABEL” markings are for internal use in the config files. The “MENU LABEL” are what will actually be printed to the menu. Notice that my “LABEL” known as “local” has a “MENU LABEL” of “Boot to local hard drive” and below it the “LOCALBOOT 0″ option. Selecting this option will boot from the disk. As well, the “ONTIMEOUT” argument at the top specifies this as the default option should the “timeout” be reached. However, what’s more important is the second entry.

The “kernel” specifies where the vmlinuz file is. Absolutely, it’s at “/var/lib/tftpboot/images/centos/x86_32/6.0/vmlinuz” but this configuration file only sees within the chroot, so specify the path as just “images/centos/x86_32/6.0/vmlinuz” (or whatever your path is). Same story goes for the next line that will “APPEND” various arguments. Specifically, this will append arguments to the kernel when it loads. The “initrd=” argument should have the path specified in the same manner as the vmlinuz path. The “ip=dhcp” is another parameter that can be passed to the kernel to specify that network hardware should grab an ip address via DHCP. Strictly speaking this isn’t necessary. If you leave it off, then the installer will just go through the prompts of asking you how your NIC should obtain an IP address, rather than if you had left “ip=dhcp” on. Left on, the installer knows right off the bat to tell eth0 or whatever network device is default to grab an IP via DHCP.

Restart services and test

At this point, you’re ready to restart services and see if you can get a network install successfully 😀

service httpd restart
service xinetd restart
service dhcpd restart

Ideally, these will all restart the services without throwing you any errors. I only got one it was because of a typo in one of the configs. Fixing the typo permitted a successful restart of the services. I then proceeded to install CentOS 6.0 on an old laptop via the network. When it asked for the installation medium, I chose “URL” and then specified “”. That is the IP address of the netboot server (which is also running apache) and it loads the files at /var/www/html/centos that we copied way back in step three 😛

BONUS: Menu Background Images

So you want a fancy background image a la something like this?

clean menu background image/p>

Fortunately, it’s not too difficult to achieve. Instead of using “menu.c32″, use “vesamenu.c32″ :

cp /usr/share/syslinux/vesamenu.c32 /var/lib/tftpboot/

Then, be sure to download a .png image file that is 640×480 and place it in the tftp chroot ( /var/lib/tftboot/ in our case ). Well, download or get it to the right location through some other means. Just make sure it’s there.

cd /var/lib/tftpboot

And then tweak the “/var/lib/tftpboot/pxelinux.cfg/default” config file to look like this:

default vesamenu.c32
prompt 0
timeout 500

MENU BACKGROUND /somefile.png

LABEL local
        MENU LABEL Boot to local hard drive
        LOCALBOOT 0

LABEL CentOS 6.0 x86_32
        MENU LABEL CentOS 6.0 x86_32
        kernel images/centos/x86_32/6.0/vmlinuz
        APPEND initrd=images/centos/x86_32/6.0/initrd.img ip=dhcp

The leading slash is important. I couldn’t get the menu background image to load or show without it.

Side note:

The image can be larger, such as 1024×768. Just place it in the appropriate location and specify the resolution in your default file as such:

MENU BACKGROUND /somefile.png

TODO: Kickstart Files

Usually, the entire goal of a PXE boot is for rapid imaging of systems without need for manual intervention on each box. This is accomplished via Kickstart files. However, I have run out of time at this point between work and school to investigate the issue myself. It looks like the general principle is to make a kickstart script, place it in Apache’s document root, and then add a line to the APPEND directive inside the “/var/lib/tftpboot/pxelinux.cfg/default” config file.

vim mykickstart.cfg
cp mykickstart.cfg /var/www/html/
vim /var/lib/tftpboot/pxelinux.cfg/default

And make the APPEND line look something like this:

LABEL CentOS 6.0 x86_32
        MENU LABEL CentOS 6.0 x86_32
        kernel images/centos/x86_32/6.0/vmlinuz
        APPEND initrd=images/centos/x86_32/6.0/initrd.img ks= ip=dhcp #use whatever your ip address is for the web server

A few links that look promising:

Good luck and happy hacking 😀