The Problem

Migrate from PXELINUX/TFTP deployment environment to gPXE/HTTP based environment with easy roll out and back out, and zero changes to PXELINUX menu/configuration files and production application code that drives deployment operations. Eventually replace 01-xx-xx-xx-xx-xx–xx mac based configuration files on the file system with rewrite rules to an application server for configuration generation.


  • Slow
  • Prone to failure
  • Limited entry points for extensibility


  • 24/7/365 production
  • RHEL4/5 deployment servers
  • tftp-hpa (serving from /tftpboot/)
    • MAC based configuration files automatically written to /tftpboot/PXELINUX.cfg/.
  • Apache web server
    • Serving up installation and other content to the deployment network.

Original TFTP Setup

  • xinetd based
    • Starting a new process for each connection seemed more stable than running the service as a daemon.
  • /etc/xinetd.d/tftp
  # 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             = -vvvvs /tftpboot -m /tftpboot/tftpd.map
          disable                 = no
          per_source              = 11
          cps                     = 100 2
          flags                   = IPv4
  • tftpd.map is only used to changing Windows paths (\) to Linux paths (/)
  rg \\ /

Original DHCPD Setup

  • dhcpd.conf
  ddns-update-style none;
  ignore client-updates;
  allow bootp;
  allow booting;
  default-lease-time 600;
  max-lease-time 7200;
  option dhcp-parameter-request-list = concat(option dhcp-parameter-request-list, 3a, 3b);
  subnet  netmask {
          default-lease-time 7200;
          max-lease-time 14400;
          option subnet-mask;
          option routers;
          option domain-name-servers;
          filename "pxelinux.0";

gPXE to the rescue

The undionly image should do the trick as we are already booting PXELINUX via the BIOS PXE ROM on all of our machines and we do not want to attempt to burn gPXE into the bios for the large number of current and future motherboards we might have. We did attempt to use the gPXELINUX image with and without keeppxe but undionly chaining in PXELINUX produced more reliable and expected behavior with our boot images in respect to the previous PXELINUX/tftp implementation.

As stated earlier we wanted easy roll out/back while testing and for initial production deployment in the event things went wrong. The following requirements had to be met:

  • The current tftp service must not be altered.
  • The current tftp folder must not change location.
  • The new implementation should be fast and easy to roll out/back.

Configure Apache for gPXE

This was done with a simple Alias and Directory entry in our vhost configuration:

   Alias "/gpxe" "/tftpboot"
   <Directory "/tftpboot">
     Order allow,deny
     Allow from all

Create boot script for gPXE

We simply want to chain in PXELINUX. We could have embedded this in the undionly image or used a simple text file, but this script might eventually contain more logic/features.

  • /tftpboot/boot.php
  echo "#!gpxe\n";
  echo 'chain pxelinux.0' ."\n";

Note that we are not passing any HTTP, IP, etc etc information in this script, gPXE will simply Do the Right Thing.

Changes to DHCP

  • dhcpd.conf
          #filename "pxelinux.0";
          if ((exists user-class) and (option user-class = "gPXE")) {
            filename "";
          } else {
           filename "undionly.kpxe";

The above changes now load undionly.kpxe if the client is not gPXE. This prevents an infinite loop.

Now we simply restart dhcpd and clients will start loading PXELINUX configurations and images from without any changes needed to menus, kernel/append paths, etc as long as your setup was already using relative paths for /tftpboot/.

Roll back is as simple as commenting out the new filename block, uncommenting the original filename, and restarting dhcpd:

  • dhcpd.conf
          filename "pxelinux.0";
          #if ((exists user-class) and (option user-class = "gPXE")) {
          #  filename "";
          #} else {
          # filename "undionly.kpxe";

Gotchas and Issues Encountered

  • Use recent versions of gPXE and PXELINUX.
  • If you are using comboot modules for PXELINUX make sure they are all from the same Syslinux version.
  • COM32 modules from Syslinux 4.00+ can not be used with gPXE directly. gpxe/gpxelinux.0 (In Syslinux official distribution) is undionly.kkpxe, PXELINUX and a special script that does work.
  • If you are running selinux you may need to relabel the /tftpboot directory as public content:
    • chcon -R -t public_content_t /tftpboot/
    • semanage fcontext -a -t public_content_t '/tftpboot(/.*)?'

We also experienced DHCP timeouts on some of our older switches. It seems that although the link was “up” it was not yet passing traffic (spanning-tree portfast did not seem to be the issue in this case). The easiest way around the issue was to increase the gPXE banner timeout in src/config/general.h to 10 seconds and rebuild the undionly image:

   * Timer configuration
  #define BANNER_TIMEOUT 100              /* Tenths of a second for which the shell
                                     banner should appear */

QR Code
QR Code appnotes:pxelinux_tftp_to_http_migration (generated for current page)