Tutorial explaining how to configure an Ubuntu 16.04 server as a Preboot Execution Environment (PXE) server to support automated/unattended provisioning of additional unix-based hosts. Note that this is generally an old implementation but useful to learn and understand infrastructure components. This tutorial is an updated set of instructions from my archive of resources and details the instructions for the latest version of Ubuntu - 16.04.
Background
A somewhat older but still relevant and interesting concept is the method of PXE booting Unix-based hosts. In a PXE boot environment, a single Unix-based system is configured to provide several services and files/configurations to a network-attached resource in order for the resource to automatically provision itself as a Unix-based host defined by the configurations provided.
The base services and configuration required for a PXE-boot environment are as follows:
- DHCP Service: A DHCP service is required to exist in order to auto-allocate an IP address as well as tell the newly-created resource where to go in order to obtain its initialization RAM disk (initrd). This file is then loaded into memory and defines/tells the resource what to do next (obtain the files required to install and configure the operating system).
- TFTP Service: This service is used specifically to serve the initialization RAM disk file.
- Web Service: This is typically Apache or the like and is used to serve the Operating System installation and configuration files. Although it is possible to tell the host being provisioned to retrieve its OS files from an internet source, we are going to assume that provisioning is being done on an internal network in order to increase the full scope of this tutorial.
- OS-Specific Files: The HTTP service listed above serves the operating system files from a particular location and, as such, the files used to install the Operating System must be present and available for the web service in a format similar to a disk image layout.
- DNS Service: The DNS service will be configured on the PXE server to provide a full name to the resource(s) being provisioned.
Technology Ecosystem
It would be most scalable to configure resources within a cloud environment such as Amazon Web Services (AWS) or the like. However, in the interest of ensuring that network collisions are avoided (i.e. making sure there are not multiple DHCP broadcasts and such) within the same network, we will construct the resources for this tutorial using a locally-provisioned set of resources on a laptop through Oracle’s VirtualBox. The following Virtual Machines will be created in this tutorial:
PXE Boot Server
- OS: Ubuntu 16.04
- CPU: 1
- RAM: 1024MB
- Disk: 50GB
- Network: 1 Adapter attached to “NAT Network”
- IP: 10.0.2.15
Client Instance
- OS: (to be provisioned through PXE server)
- CPU: 1
- RAM: 1024MB
- Disk: 30GB
- Network: 1 Adapter attached to “NAT Network”
- IP: 10.0.2.121
As can be seen above, each device is attached to “NAT Network”. In order for communication to work, a new NAT Network must be created via VirtualBox and the same NAT Network must be specified for both hosts. To create the new NAT Network, perform the following in VirtualBox:
- Navigate to the menu “VirtualBox” -> “Preferences”.
- Select the “Network” tab.
- Under the “NAT Networks” option, select the “Add new NAT Network” icon (right side of list).
- Select the newly-created network and click the “Preferences” icon (tool icon).
- In the dialog that is presented, ensure “Enable Network” is checked, and provide a name and CIDR. Also, ensure that “Supports DHCP” is checked.
PXE Server
The first thing to do is to create a Virtual Machine to serve as the PXE boot server. Install the Ubuntu 16.04 operating system on a new Virtual Machine in VirtualBox with the specifications from the “Technology Ecosystem” section above. When prompted, specify the following for these relative sections - all other items can be accepted as defaults:
- Server Name: pxeserver
- User Account: test
- Password: Password123!
- Packages to Install: Add “OpenSSH Server” to the selected list
As a setup step, SSH to the instance and perform a repository metadata update:
DHCP Service
To install and configure the DHCP service, which is used for serving IP addresses to the hosts being automatically provisioned and specifying where to obtain the initrd file:
TFTP Service
The TFTP service is managed by xinetd. To configure it, perform the following:
Next, attach the Ubuntu 16.04 ISO to the Virtual Machine (can be found here) using the VirtualBox settings for the instance. Once the ISO has been attached, mount the drive and copy the initialization RAM disk and menu files into their respective locations:
Finally, configure the pxelinux.cfg
file for boot options - note that the append
statement below
contains many options (do not exclude any of them):
If you wish to test the TFTP service functionality, you can perform the following (again, replace the IP address 10.0.2.15 with your PXE server IP address):
Web Service (Apache)
To serve the Operating System files, we will install the Apache web server:
Next, we will copy the files required for the OS install to the respective directory (assumes the steps to mount the Ubuntu ISO in the “TFTP Service” steps has been completed/the mount is still present):
Now that the OS files are in place, we need to create a preseed file to tell the clients how to
configure their operating systems. You can either use a GUI for this (system-config-kickstart) or
start with a template from the documentation
here. Either way, ensure
the contents of the preseed are placed in a file at the location /var/www/html/ubuntu/preseed.seed
.
A sample preseed.seed
file is shown below for reference:
# /var/www/html/ubuntu/preseed.seed
# Locale
d-i debian-installer/locale string en_US
d-i console-setup/ask_detect boolean false
d-i keyboard-configuration/xkb-keymap select us
# Clock/Time Zone
d-i clock-setup/utc boolean true
d-i time/zone string US/Eastern
d-i clock-setup/ntp boolean true
# Networking
d-i netcfg/choose_interface select auto
d-i netcfg/get_hostname string unassigned-hostname
d-i netcfg/get_domain string unassigned-domain
d-i netcfg/wireless_wep string
# Mirrors
d-i mirror/country string manual
d-i mirror/http/hostname string archive.ubuntu.com
d-i mirror/http/directory string /ubuntu
d-i mirror/http/proxy string
# Account
d-i passwd/user-fullname string
d-i passwd/username string test
d-i passwd/user-password password Password123!
d-i passwd/user-password-again password Password123!
d-i user-setup/encrypt-home boolean false
# Partitioning
d-i partman-auto/method string lvm
d-i partman-lvm/device_remove_lvm boolean true
d-i partman-md/device_remove_md boolean true
d-i partman-lvm/confirm boolean true
d-i partman-lvm/confirm_nooverwrite boolean true
d-i partman-auto/choose-recipe select atomic
d-i partman-partitioning/confirm_write_new_label boolean true
d-i partman/choose_partition select finish
d-i partman/confirm boolean true
d-i partman/confirm_nooverwrite boolean true
# Package Selection
tasksel tasksel/first multiselect minimal
d-i pkgsel/include string openssh-server
d-i pkgsel/upgrade select none
popularity-contest popularity-contest/participate boolean false
# Finish
d-i finish-install/reboot_in_progress true
DNS Service
In order to ensure the client instances receive a Fully-Qualified Domain Name (FQDN) that is appropriate to the domain we wish to configure, we will set up a DNS service. We will use BIND as the DNS service, and set up a domain “test123.com”:
Next, we need to configure the zones:
Once the configuration files have been created, check the syntax of the files, and if all is well, restart the BIND service:
Next, to configure the PXE server to utilize the new DNS service, perform the following:
Once the above has been completed, your PXE server should be configured and ready to resolve IP
addresses for the hosts defined. If you inspect the /etc/resolv.conf
file, you will notice
that the IP address of the PXE server (now also a name server) is listed at the top of the
nameserver list of IP addresses.
Perform the following to ensure that the forward resolution is working as expected:
Next, confirm the reverse lookups:
If all commands above work as expected, your DNS environment is now ready for PXE booting.
PXE Client
Now that the PXE server has been configured, we can create a client to PXE boot. In VirtualBox, create a new Virtual Machine. Prior to launching the instance, ensure the resource has 1 network adapter attached to “NAT”. Also (VERY IMPORTANT) ensure that under the “System” -> “Boot Order” settings, the boot order for selected devices is:
- Hard Disk (checked)
- Network (checked)
Failure to ensure the hard disk is specified first can result in the VM continuously rebooting and PXE booting itself since it will always receive a DHCP Ack and continue down the PXE route even if it has a valid Operating System on its hard drive (which it should after the first successful PXE boot provisioning cycle).
Once the above are complete, start the instance.
Upon starting, several things will happen. The instance will broadcast a DHCP request for an IP address. If the configurations for the network interface for this instance are correct, it should receive an ACK from the DHCP server on your PXE boot server. Once an IP address is obtained, it will also make a request to the TFTP server on the PXE boot server for the initialization RAM disk file, which will kick off the process.
The preseed.seed
file will be retrieved and, based on the specifications within, the instance will
start to auto-provision itself based on the descriptions within. Note that there are many other steps
that are occurring between, but for the purposes of this tutorial, those details are out of scope.
Watch the instance as it cycles through the various menu items on the screen and auto-completes the various parts based on the definition in the seed file. Once complete, your VM will reboot and you can then log into the instance using the “test” user with the password “Password123!” as defined in the seed file - your PXE boot environment is now complete!
Summary
This PXE boot server has been configured with the very basic settings for PXE booting Ubuntu instances. However, there are likely more configuration items you should address, such as ensuring the DHCP configurations are appropriate for your environment (instead of a dynamic range of IP addresses in a single subnet), dynamic DNS to avoid having to map specific IP addresses to MAC addresses, etc. In addition, certain security issues should be addressed, such as using a hashed version of the user credentials in the seed file rather than clear-text (which was used in this tutorial to make it simpler to recall the default password). Overall, however, this tutorial lays the ground work for a PXE boot environment for auto-provisioning Ubuntu-based instances and can be expanded upon to handle more complicated scenarios, such as multiple Operating System installations beyond Ubuntu-based systems, etc.
Credit
The above tutorial was pieced together with some information from the following sites/resources: