It's a common scenario: you've been given the task of rolling out dozens of Linux boxes, but you'd rather not have to go through the pain of installing every one them manually. Automated installations with Redhat are well documented, but what about Ubuntu?
Ubuntu inherits Debian's ability to preseed the answers to its installation questions, but the instructions for this are rather haphazard and seems to quickly become out of date as newer versions are released.
In this article, we'll look at setting up automated installations for Ubuntu Jaunty, entirely from the network. We'll start out with one assumption however - that the workstation being used has the ability to perform network boots using PXE. Most modern workstations and servers have this feature, which is usually enabled via the BIOS. If your computer doesn't have this, then you will most likely need to initial your boots from a CDROM, floppy disk drive or USB key.
The installation process
The process used for performing a networked installation is as follows:
- The workstation sends out a DHCP request for its IP address and boot location
- The DHCP server provides the address and the hostname of the tftp server and the path to the boot code (pxelinux.0)
- The workstation downloads pxelinux.0 via tftp and then boots this
- pxelinux then retrieves its configuration file from the tftp server
- pxelinux now retrieves a kernel, initrd and preseed file, and then boots the installer.
- The installer reads the settings given in the preseed file and installs the system
Setting up a TFTP server
The TFTP server allows the workstations to download the pxelinux bootloader, and the installer Linux kernel and initrd file. I'm using
tftpd-hpa, which has some specific requirements for PXE boots - the standard netkit tftpd will not work.
tftp-hpa serves up files from the /tftpboot directory on my server. Under this directory, I have the following files:
/tftpboot/pxelinux.0 - the pxelinux bootloader. This can be obtained from the Ubuntu archive,
here.
/tftpboot/pxelinux.cfg/ - a directory that contains pxelinux configuration files
/tftpboot/ubuntu/jaunty/i386/linux - the installer kernel, available
from
here.
/tftpboot/ubuntu/jaunty/i386/initrd.gz - the installer initrd, which can be retrieved from the link above.
This
script will set up the /tftpboot directory for you. Run it as root - but read through it to make sure you know what it does, first.
Setting up a DHCP server
We're going to assume that the computer being installed can load a kernel via PXE - most modern computers now have this capability.
First, you will need a DHCP server. My network uses a Linksys WRT-54GS running OpenWRT, for DHCP I'm using
dnsmasq. To configure dnsmasq so that it tells DHCP clients where to download the pxelinux bootloader, I added this line to my /etc/dnsmasq.conf file:
dhcp-boot=pxelinux.0,soeserver.example.com.,10.0.0.103
Here, soeserver.example.com (10.0.0.103) is my local host with the tftp server on it.
You're probably more likely to be using ISC dhcpd within your own network; in this case, use the "next-server" parameter within an entry for your specific workstation - something like this:
host workstation.example.com {
hardware ethernet 00:11:22:33:44:55;
fixed-address 10.0.0.230;
option host-name "workstation";
filename "pxelinux.0";
next-server soeserver.example.com;
}
The pxelinux configuration file
Once your workstation has been assigned an IP address by DHCP and told where to fetch the pxelinux.0 file from, it will download this file and then execute it. The first thing that pxelinux will do is attempt to fetch a configuration file from the tftpserver. It first attempts to download a file named with the workstation's ethernet card MAC address, from the /tftpboot/pxelinux.cfg/ directory. So if our workstation's ethernet MAC address is 00:11:22:33:44:55, then it will look for the file "/tftpboot/pxelinux.cfg/00-11-22-33-44-55". If it can't find that, it will look for a file named with the workstation's IP address in hexadecimal (eg, for 10.0.0.230, it will look for /tftpboot/pxelinux.cfg/0A0000D6), and then files with the most significant digits (eg, 0A0000D, 0A0000, 0A000, 0A00, 0A0, 0A, 0) ... and finally if it can't find any of those, it will look for a file named 'default'.
We'll just name the file 'default' for the moment. Create a file named /tftpboot/pxelinux.cfg/default with the following contents:
default harddisk
label harddisk
localboot 0x80
label install
kernel ubuntu/jaunty/i386/linux
append vga=normal locale=en_AU setup/layoutcode=en_AU console-setup/layoutcode=us initrd=ubuntu/jaunty/i386/initrd.gz preseed/url=http://10.0.0.103/ubuntu/jaunty/preseed.txt netcfg/get_hostname= -- quiet
prompt 1
timeout 300
(This file can be downloaded
here).
The above file creates two boot options for the pxelinux loader - the first one, named 'harddisk' will boot the workstation from its built-in disk drive. This is the default option and it will automatically run this if the user doesn't press any key within five minutes at boot time (this timeout is configured by the "timeout 300" line - ie, 300 seconds). The second option "install" is the auto-installation option.
The "kernel" directive tells the bootloader to load the kernel located at /tftpboot/ubuntu/jaunty/i386/linux, and within the append directive we've set a number of variables:
- initrd - load the initrd from /tftpboot/ubuntu/jaunty/i386/initrd.gz
- locale - set the locale to "en_AU" (Australian English) - this suppresses a question asked by the Ubuntu installer at a later stage
- console-setup/layoutcode=us - sets the keyboard to US (again, suppresses a question later on)
- preseed/url - fetch our preseed file from http://10.0.0.103/ubuntu/jaunty/preseed.txt
- netcfg/get_hostname - we set this to blank, again to suppress a question asked by the installer. The system will learn its hostname from DHCP
Creating a preseed file
A preseed file contains all the answers to the questions that the Ubuntu installer will ask during a normal installation sequence. In the above pxelinux configuration file, we've told the installer to load the preseed file from a webserver on our locale network. So now, we'll create the following file, which you can download
here.
d-i debian-installer/locale string en_AU
d-i console-setup/ask_detect boolean false
d-i console-setup/layoutcode string us
d-i clock-setup/utc boolean true
d-i time/zone string Australia/Melbourne
d-i clock-setup/ntp boolean true
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
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
d-i partman-auto/disk string /dev/sda
d-i partman-auto/method string lvm
d-i partman-auto-lvm/guided_size string max
d-i partman-lvm/device_remove_lvm boolean true
d-i partman-lvm/confirm boolean true
d-i partman-auto/choose_recipe select atomic
d-i partman/confirm_write_new_label boolean true
d-i partman/choose_partition select finish
d-i partman/confirm boolean true
d-i passwd/root-login boolean true
d-i passwd/make-user boolean false
d-i passwd/root-password-crypted password $1$HtK/7tAe$XFViy08BhswF7UMeaG4Cr1
tasksel tasksel/first multiselect standard
d-i pkgsel/include string openssh-server build-essential dpkg-dev fakeroot
d-i pkgsel/update-policy select none
d-i grub-installer/only_debian boolean true
d-i grub-installer/with_other_os boolean true
d-i finish-install/reboot_in_progress note
xserver-xorg xserver-xorg/config/monitor/selection-method \
select medium
xserver-xorg xserver-xorg/config/monitor/mode-list \
select 1024x768 @ 60 Hz
Put the above text into a file called
preseed.txt somewhere in the directory tree on a webserver on your local network, and make sure you adjust the
preseed/url directive in the pxelinux configuration file to match the file's url.
At this point, we have everything in place for the automatic installation to proceed. If you now boot your workstation, force it to perform a PXE boot (you may need to adjust the bios settings to enable this), it will then obtain an IP address from your DHCP server, load the pxelinux bootloader and display a "boot:" prompt. At the prompt, type "install" and press Enter. Your system will then automatically install a minimal version of Ubuntu, from the Ubuntu archive, without any X or Gnome packages - just the bare essentials.
Preseed file description
To finish off, I'll give a run through of the above preseed configuration file, explaining each of the directives.
d-i debian-installer/locale string en_AU
d-i console-setup/ask_detect boolean false
d-i console-setup/layoutcode string us
d-i clock-setup/utc boolean true
d-i time/zone string Australia/Melbourne
d-i clock-setup/ntp boolean true
The above lines set the language of the installation (in this case, Australian English - amongst the many other options, there are also en_CA, en_IE, en_UK and en_US), tell the installer not to request automatic keyboard detection, force the keyboard to be a US variety and then set up the clock - the server will use UTC for its hardware clock, it will have a local timezone of Australia/Melbourne and the server will syncronise its clock with an ntp server.
d-i netcfg/choose_interface select auto tells the installer to automatically choose which ethernet interface to use.
The next three lines exist purely to suppress some annoying questions that the installer would otherwise ask, about the host and domain names (which will be assigned from DHCP) and the wireless wep key (which we're not using):
d-i netcfg/get_hostname string unassigned-hostname
d-i netcfg/get_domain string unassigned-domain
d-i netcfg/wireless_wep string
Now, we set the name of the repository from which Ubuntu will be installed:
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
The first line tells the installer that we want to set the hostname manually, the second and third lines set the hostname and path respectively, and the fourth line we tell the installer that we don't wish to use a proxy (if you do want to use one, then give the url of the proxy here, for example http://proxy.server.name:3128/)
The next step will be setting up the disk:
d-i partman-auto/disk string /dev/sda
d-i partman-auto/method string lvm
d-i partman-auto-lvm/guided_size string max
d-i partman-lvm/device_remove_lvm boolean true
d-i partman-lvm/confirm boolean true
d-i partman-auto/choose_recipe select atomic
d-i partman/confirm_write_new_label boolean true
d-i partman/choose_partition select finish
d-i partman/confirm boolean true
For simplicity, I've chosen an automatic partitioning scheme, using LVM - this will use the entire disk, allocate a small partition to /boot and then use LVM across the remainder of the disk, with one large root logical volume within it.
Now to set up the root account. I loathe Ubuntu's default setup that doesn't have a password assigned to the root account, so I've set it up with a password, here:
d-i passwd/root-login boolean true
d-i passwd/make-user boolean false
d-i passwd/root-password-crypted password $1$HtK/7tAe$XFViy08BhswF7UMeaG4Cr1
The encrypted password, in this case, is simply "test123".
There's two ways of choosing which packages should be installed - the first is to select groups of packages - "tasks", using the tasksel directive. The second is using pkgsel to select individual packages:
tasksel tasksel/first multiselect standard
d-i pkgsel/include string openssh-server build-essential dpkg-dev fakeroot
d-i pkgsel/update-policy select none
Here, I've chosen the "standard" task (which is very basic Ubuntu installation), and I've also opted to install the openssh-server package and build-essential (which will pull in gcc and libc6 header files).
The last thing we need to do is install a bootloader - we'll use grub:
d-i grub-installer/only_debian boolean true
d-i grub-installer/with_other_os boolean true
d-i finish-install/reboot_in_progress note
You'll note that the configuration file has two xserver-xorg directives at the end; these are there simply to suppress two more questions from the installer that would halt the automated installation process.
That's all there is to it. You should now be able to take the above preseed configuration file and expand it to install an entire Ubuntu desktop, or perhaps even use it in a disaster recovery plan to quickly rebuild dead servers.
If you found this article helpful, consider making a donation to offset the costs of running this server, to one of these addresses: