How-To: Unattended Ubuntu Deployment over Network

there is many ways of installing Linux. Nowadays, the most common one is probably by using a CD. Download the CD, stick it in your CDRom drive and let's roll!!!

If you intent to deploy Ubuntu over several computers, this can easily become cumbersome.

This tutorial will explain how to install Ubuntu/Debian through the network using preseed files so you can turn on your computer, walk away and come back later with your fresh install up and running.

When deploying Linux over the network, there is a good amount of server that have to be part of the stucture.
Basically, the computer you want to install is going to boot up on the network, get an IP address from a DHCP server. This server will tell the machine to contact a TFTP server which is going to provide it with a boot loader: PXELinux.
Finaly, the machine will pick up a kernel and a initrd file and start the process of installing its OS using a preconfiguration file preseed.
The debian-installer is going to be downloaded from Ubuntu repository as well as the rest of the packages.

This tutorial explain how to install each of the services and build the whole thing up so you can easily deploy Linux over the network.

Please note even though most of the idea could be use to deploy non debian based distro, the part concerning the installer is pretty tight to Ubuntu/Debian and any other debian based distro.

1. The Big Picutre

pxe-install-diagrampxe-install-diagram
This is what infrastructure will look like. A DHCP server which will provide our client with an IP address and informations on where to get the boot lader.
A TFTP server hosting PXE boot loader and kernel/initrd images. Those will be loaded by the Client in order to start the Installer.
Get network details (yet again).
Fetch the preseed file and carries on with installing and fetching package from the internet.

This diagram roughly represent what will be involved in this process.

So, let's roll and start configuring our first element involved: our DHCP server.


How-To: Unattended Ubuntu Deployment over Network -- page 2 -- DHCP server

For the purpose of this tutorial, I decided to choose dnsmasq to act as a DNS/DHCP server. The reason behind this is that dnsmasq is simple to configure and does a good job in providing DNS and DHCP services for a small LAN.

2. DHCP server:

The DHCP server is going to be involved twice in this scenario. First, when our client is going to boot on its network interface, the DHCP server is going to provide the client with an IP address to be able to communicate with other servers. Also, on this first contact, the DHCP server is going to supply our client with a filename and a server address where to get the bootloader using TFTP protocol.

Let's get started with dnsmasq installation and configuration. In this example, I will consider that our network is using the network address range 192.168.0.0/24.

2.1. Installing dnsmasq

To install dnsmasq simply type:

$ sudo apt-get install dnsmasq

No, we need to define a pool of IPs to be given through DHCP.

2.2. Configuring dnsmasq

In /etc/dnsmasq.conf make sure the following line is defined:

dhcp-range=192.168.0.20,192.168.0.50,24h

This will give IP address ranging from 192.168.0.20 to 192.168.0.50 to clients in your network.

You can also define some permanent IPs for certain host with the following:

dhcp-host=XX:XX:XX:XX:XX:XX,tftpserver,192.168.0.3,48h

Which will attribute IP 192.168.0.3 and hostname "tftpserver" to the client with a MAC address of XX:XX:XX:XX:XX:XX.

Finally, in order to inform computers booting using PXE where to get the bootloader, we need to add:

dhcp-boot=pxelinux.0,tftpserver,192.168.0.3

Which tells clients to get pxelinux.0 from host tftpserver which is located at 192.168.0.3.

Now reload dnsmasq settings with the following command:

$ sudo /etc/init.d/dnsmasq restart
Restarting DNS forwarder and DHCP server: dnsmasq.

Now, when our clients will ask for an IP using DHCP, they will be supplied with a location and filename to get in order to boot.

So, next step, setting up our TFTP server.


How-To: Unattended Ubuntu Deployment over Network -- page 3 -- TFTP server

3. TFTP server

There is a couple of tftp server around there. The one chosen for this tutorial is tftpd-hpa does the job.tftpd package could not handle PXE protocol.

3.1. Installing tftp:

You can install tftpd-hpa with this command line:

$ sudo apt-get install tftpd-hpa

tftpd-hpa is pretty straightforward to configure, you just have to make sure /etc/default/tftpd-hpa looks like:

RUN_DAEMON="yes"
OPTIONS="-l -s /var/lib/tftpboot"

Then restart tftpd-hpa:

$ sudo /etc/init.d/tftpd-hpa restart

Finally, we just have to copy files to /var/lib/tftpboot to share them through TFTP.

3.2. What's next?

Nice, we now have a tftp server ready to answer request, but remember, our DHCP server tells PXE clients to get pxelinux.0 from our TFTP server. So far there is nothing to get from this TFTP server, we need to populate it.

We will now install PXELinux files on our TFTP server. The PXE clients will be able to download pxelinux.0 and use pxelinux configuration files to provide different installation method. In every case, the PXE client will at least need to be able to get a linux kernel and initrd.img to load into its memory and start booting with.


How-To: Unattended Ubuntu Deployment over Network -- page 4 -- PXELinux

4. PXELinux

PXELinux is a boot loader similar to syslinux. As syslinux is used for booting from a CD, Pxelinux is designed for PXE booting.

To get PXE Boot Loader and anything required to set up a netboot install, you will need to get the archive netboot.tar.gz from ubuntu repositories.

Let's go to our TFTP server root directory and get PXELinux set up.

$ cd /var/lib/tftpboot
$ sudo wget http://archive.ubuntu.com/ubuntu/dists/feisty/main/installer-i386/current/images/netboot/netboot.tar.gz
$ sudo tar -xzvf netboot.tar.gz

If you "ls -l" in this directory, you will see that the file pxelinux.0 and the directory pxelinux.cfg are actually symlinks to ubuntu-installer/i386/ where you can also find a kernel, linux, and an initrd image, initrd.gz.

What basically pxelinux.0 does is to read a configuration files in pxelinux.cfg in a specific order:

Where xx-xx-xx-xx-xx-xx-xx is the MAC address of our client and C0A80025 the hexadecimal form of the client's IP address.

If it can't find none of those it will fall back onto default.

If default can't be found, it will try to load a default kernel (named linux) and if it still don't have any success, you will be left in front of a boot prompt where you will be able to type your custom boot command.

Anyway, the default settings of netboot.tar.gz are enough to start a network installation.

The boot screen you get upon boot up proposes different entry. Each entry will propose a different installation method, but all of them load ubuntu-installer/i386/linux kernel and ubuntu-installer/i386/initrd.gz intrd image.

People who simply wants to deploy a boot installation (installing ubuntu on a system with no booting device like cdrom, floppy or usb bar) can stop their reading here.
The next section is going to explain how you can automatize the installation process so you won't be prompted by questions such as "select language", "select keymap" ....


How-To: Unattended Ubuntu Deployment over Network -- page 5 -- Preseed File

5. Preseed: Installation automation:

Like Red Hat's kickstart file, Debian based distribution can use a preseed file. The preseed file will contain the different information that the installer will require in order to proceed with the installation.

Basically, this file is going to contain language, keymap layout, repositories, distro version, partitioning, timezone and package selection informations.
An example of this file can be found here: http://www.debian.org/releases/stable/example-preseed.txt .

There is many ways to get the installer loading the preseed file: floppy, harddrive, http... Because we are performing a net install here, it is logical to get the preseed file from the network. In this example our http server will be called http-preseed.

Because we are getting the preseed file from the network, the preseed file will be downloaded only once the installer acquires an IP address. Therefore, we will need to inject a few preseed command to the installer using the append part of pxelinux.cfg/default .
Once the network will be set up, the preseed file will be downloaded and the installer will use its content.

In our example, we will set an en_GB locale, keyboard, the hostname will be provided by our DHCP server, timezone will be Europe/Dublin.

You can find available locales in /usr/share/locale/ . Available timezone can be found in /usr/share/zoneinfo/

Our repository is going to be running apt-cacher and will be accessible at 192.168.0.1:9999.

If you intend to set many systems with netinstall, it is wise running your own repository to minimize bandwidth utilisation.

We will be partitioning our disk on /dev/sda with separate /, /usr, /var, /tmp, /home and we will create a first user called ubuntuadmin with the password mypassword.

Our default install will install an ubuntu lamp server.

A password MD5 can be generated with echo "mypassword" | mkpasswd -s -H MD5

Here is how my preseed file look like:

d-i debian-installer/locale string en_GB
d-i console-setup/layoutcode string en_GB
d-i netcfg/choose_interface select auto
# Any hostname and domain names assigned from dhcp take precedence over
# values set here. However, setting the values still prevents the questions
# from being shown, even if values come from dhcp.
d-i netcfg/get_hostname string unassigned-hostname
d-i netcfg/get_domain string unassigned-domain
d-i netcfg/wireless_wep string
### Mirror settings
# If you select ftp, the mirror/country string does not need to be set.
d-i mirror/country string enter information manually
d-i mirror/protocol string http
d-i mirror/http/hostname string 192.168.0.1:9999
d-i mirror/http/directory string /ubuntu
d-i mirror/http/proxy string
# Suite to install.
#d-i mirror/suite string testing
# Suite to use for loading installer components (optional).
#d-i mirror/udeb/suite string testing
d-i mirror/suite string feisty
### Partitioning
# If the system has free space you can choose to only partition that space.
# Note: this must be preseeded with a localized (translated) value.
#d-i partman-auto/init_automatically_partition \
# select Guided - use the largest continuous free space

# Alternatively, you can specify a disk to partition. The device name
# can be given in either devfs or traditional non-devfs format.
# For example, to use the first disk:
#d-i partman-auto/disk string /dev/discs/disc0/disc
d-i partman-auto/disk string /dev/sda
# In addition, you'll need to specify the method to use.
# The presently available methods are: "regular", "lvm" and "crypto"
d-i partman-auto/method string lvm
# If one of the disks that are going to be automatically partitioned
# contains an old LVM configuration, the user will normally receive a
# warning. This can be preseeded away...
d-i partman-auto/purge_lvm_from_device boolean true
# And the same goes for the confirmation to write the lvm partitions.
d-i partman-lvm/confirm boolean true
# You can choose from any of the predefined partitioning recipes.
# Note: this must be preseeded with a localized (translated) value.
d-i partman-auto/choose_recipe \
select Separate /home, /usr, /var, and /tmp partitions
# This makes partman automatically partition without confirmation.
d-i partman/confirm_write_new_label boolean true
d-i partman/choose_partition \
select Finish partitioning and write changes to disk
d-i partman/confirm boolean true
### Clock and time zone setup
# Controls whether or not the hardware clock is set to UTC.
d-i clock-setup/utc boolean true
# You may set this to any valid setting for $TZ; see the contents of
# /usr/share/zoneinfo/ for valid values.
d-i time/zone string Europe/Dublin
### Apt setup
# You can choose to install non-free and contrib software.
d-i apt-setup/multiverse boolean true
d-i apt-setup/universe boolean true
# To create a normal user account.
d-i passwd/user-fullname string Ubuntu Server Administrator
d-i passwd/username string ubuntuadmin
# Normal user's password, either in clear text
#d-i passwd/user-password password insecure
#d-i passwd/user-password-again password insecure
# or encrypted using an MD5 hash.
d-i passwd/user-password-crypted password $1$ApZFpRq5$X38skX90ZL36YOnbYt/3J
# This is fairly safe to set, it makes grub install automatically to the MBR
# if no other operating system is detected on the machine.
d-i grub-installer/only_debian boolean true
# This one makes grub-installer install to the MBR if it also finds some other
# OS, which is less safe as it might not be able to boot that other OS.
d-i grub-installer/with_other_os boolean true
### Package selection
tasksel tasksel/first multiselect standard, lamp-server
# Individual additional packages to install
d-i pkgsel/include string openssh-server
### Finishing up the first stage install
# Avoid that last message about the install being complete.
d-i finish-install/reboot_in_progress note
xserver-xorg xserver-xorg/autodetect_monitor boolean true
xserver-xorg xserver-xorg/config/monitor/selection-method \
select medium
xserver-xorg xserver-xorg/config/monitor/mode-list \
select 1024x768 @ 60 Hz

Now, it is time to explain our installer where to get the preseed file from. Go and edit /var/lib/tftpboot/pxelinux.cfg/default and change the line where refering to APPEND for the server from :

LABEL server
kernel ubuntu-installer/i386/linux
append base-installer/kernel/linux/extra-packages-2.6= tasks=standard pkgsel/language-pack-patterns= pkgsel/install-language-support=false vga=normal initrd=ubuntu-installer/i386/initrd.gz --

To :

LABEL server
kernel ubuntu-installer/i386/linux
append ramdisk_size=14984 locale=en_GB console-setup/layoutcode=en_GB netcfg/wireless_wep= netcfg/choose_interface=eth0 netcfg/get_hostname= url=http://http-preseed/preseed.cfg vga=normal initrd=ubuntu-installer/i386/initrd.gz --

As you can see here, we inform the installer of a few required informations such as the locale and the keyboard layout. We also force the installer to pick up eth0 and finally, we let it know that our preseed file can be accessed through HTTP, the file is called preseed.cfg and is served by server http-preseed.

That's it, now you should be able to boot the client using PXE, this client will get a network address, download a kernel and initrd, will start the configuration using the arguments passed to the APPEND entry, get an address through DHCP, get the preseed file and proceed with the installation answering the question with the values found in preseed.cfg.