1. Overview

Operating system installation doesn’t always need manual intervention. Similar to other processes, we might be able to define system settings beforehand through a configuration file.

This way, we can set up an autoinstallation that saves time and effort in system administration. Further, we can install the OS on multiple systems at the same time. As a result, this keeps things consistent.

In this tutorial, we’ll see how to perform an automatic installation of a Ubuntu 22.04 server. In general, we’ll perform the autoinstall over a network.

Notably, in our sample environment, a preconfigured Ubuntu server (192.168.29.45) provides the installation files from a predownloaded ISO. On the other hand, a VM is the client that boots in UEFI mode over the network.

2. Steps Summary

Ubuntu server installation has changed after version 20.04. It now uses autoinstall instead of preseeding.

The new autoinstall process is slightly different from the preseeding approach:

  • format: autoinstall uses YAML, while preseed relies on debconf-set-selections
  • defaults: for missing questions, autoinstall uses default options, whereas preseed halts and prompts the user
  • interaction: specific sections in autoinstall configs can be marked interactive to prompt the user

To summarize, we go through several steps for autoinstallation:

  1. set up the dnsmasq, TFTP server, and Apache web server
  2. mount the ISO file and transfer boot files to the TFTP root directory
  3. create autoinstallation files: meta-data and user-data
  4. set up GRUB
  5. set UEFI boot option on the client machine
  6. start the VM

With a UEFI boot, we can also use the secure boot option.

Let’s now set up a sample environment for autoinstalling Ubuntu 22.04.

3. Setting up Services

To begin with, let’s configure DNS, DHCP, and TFTP for file discovery and provision.

3.1. dnsmasq Setup

dnsmasq simplifies network-based installation. In particular, it provides DHCP and DNS services.

We can install dnsmasq using the apt package manager:

$ sudo apt install dnsmasq -y

Next, we adjust the /etc/dnsmasq.conf file:

$ cat /etc/dnsmasq.conf
...
interface=wlo1
bind-interfaces
dhcp-range=192.168.29.150,192.168.29.240,255.255.255.0,8h
dhcp-option=option:router,192.168.29.1
dhcp-option=option:dns-server,192.168.29.1
dhcp-boot=bootx64.efi,192.168.29.45

Specifically, we insert the desired DHCP configuration for IP ranges and boot settings.

Now, let’s restart the dnsmasq service:

$ sudo systemctl restart dnsmasq

At this point, we should have a working configuration for DNS and DHCP.

3.2. TFTP Server Setup

Next, we install the TFTP server:

$ sudo apt install tftpd-hpa

Then, *we set the *T**FTP_DIRECTORY in the file /etc/default/tftpd-hpa**:

$ cat /etc/default/tftpd-hpa
...
TFTP_USERNAME="tftp"
TFTP_DIRECTORY="/srv/tftp"
...

Finally, we restart the TFTP server:

$ sudo systemctl restart tftpd-hpa

In fact, we can change the value of TFTP_DIRECTORY to something else.

4. Setting Up Apache Web Server

Now, we continue with a Web server setup. Notably, we use the Web server to supply configuration files to cloud-init.

So, let’s install the Apache Web server:

$ sudo apt install -y apache2

Next, we create a new Apache config file to share the TFTP root directory:

$ cat /etc/apache2/conf-available/tftp.conf
<Directory /srv/tftp>
Options +FollowSymLinks +Indexes
Require all granted
</Directory>
Alias /tftp /srv/tftp

Let’s enable the new settings:

$ sudo a2enconf tftp

Finally, we restart the Web server:

$ sudo systemctl restart apache2

At this point, Apache is up and running, serving the /srv/tftp directory under the /tftp alias.

5. Mounting the ISO File

We proceed by mounting the ISO file.

To that end, let’s create a new subdirectory, jammy, in the TFTP root directory:

$ sudo mkdir /srv/tftp/jammy

Next, we move the ISO file to the jammy directory:

$ sudo mv /path/to/iso/file jammy/

Then, we create a mount subdirectory /mnt/iso:

$ sudo mkdir /mnt/iso

Now, we can mount the ISO file as a loop device:

$ sudo mount jammy/ubuntu-22.04.4-live-server-amd64.iso /mnt/iso -o loop
mount: /mnt/iso: WARNING: device write-protected, mounted read-only.

A loop device creates a virtual block device. This enables us to mount a file as if it were a physical disk.

Moving on, we copy some boot files from /mnt/iso to the jammy directory:

$ sudo cp -a /mnt/iso/. jammy/
$ sudo cp -rf /mnt/iso/* jammy/
$ sudo cp /mnt/iso/casper/{vmlinuz,initrd} jammy/

From here, we can unmount the ISO file:

$ sudo umount /mnt/iso

Also, we remove the file:

$ sudo rm jammy/ubuntu-22.04.4-live-server-amd64.iso

Removing the ISO file reclaims server space.

The ISO files are now ready to serve over the network.

6. Autoinstall Configuration

As mentioned earlier, Ubuntu uses a new autoinstall configuration. The new autoinstall mode needs two main files:

  • user-data
  • meta-data

Further, we use an autoinstall config via the cloud-init configuration. Autoinstall calls this config file user-data. Since cloud-init uses YAML, we write user-data in YAML as well.

Also, we need to keep the above files at the same base URL.

Let’s create the user-data file:

$ cat jammy/user-data 
# cloud-config
autoinstall:
  debconf-selections: tasksel tasksel/first multiselect standard, ssh-server
  identity:
    hostname: ubuntu-server
    password: "$6$exDY1mhS4KUYCE/2$zmn9ToZwTKLhCw.b4/b.ZRTIZM30JZ4QrOQ2aOXJ8yk96xpcCof0kxKwuX1kqLG/ygbJ1f8wxED22bTL4F46P0"
    realname: Mufti Muneer
    username: ubuntu
  keyboard:
    layout: us
  locale: en_US
  network:
    ethernets:
      any:
        addresses:
        - 192.168.29.61/24
        gateway4: 192.168.29.1
        match:
          name: en*
        nameservers:
          addresses:
          - 8.8.8.8
    version: 2
  storage:
    layout:
      name: lvm
  version: 1

In the above file, we’ve added some sections:

  • version: required field
  • identity: sets the real name, username, and password of the user
  • keyboard: sets the keyboard layout and language
  • network: sets the IP address and other network information
  • storage: creates an lvm partition layout

Also, we’ve set the credentials for the user under the identity section:

  • username: ubuntu
  • password: ubuntu

The password in the file is hashed. In general, we can adjust the file to add more options. For example, to preinstall packages, we can add a packages section.

Next, we use the autoinstall-generator tool to convert a Debian preseed file:

$ autoinstall-generator preseed.txt user-data --cloud

In this way, we convert a preseed file into a cloud-config format.

Similarly, we add an empty meta-data file:

$ sudo touch jammy/meta-data

In particular, cloud-init uses the meta-data file to set up the cloud server instances. For example, it specifies details like packages to install and commands to execute during the initial setup process. Cloud services can populate the meta-data file with data relevant to the instance during provisioning.

Since we’re working locally, we can keep the file empty.

There are several ways to provide user data and metadata to cloud-init. Markedly, we’re using a custom web server.

7. Setting GRUB Config File

The GRUB menu lets us choose which operating system to boot. It does this by using a file with instructions for each system.

Let’s create a subdirectory, grub, inside the TFTP root directory:

$ sudo mkdir grub

Then, we add a GRUB config file to the above directory:

$ cat grub/grub.cfg 
default=autoinstall
timeout=10
timeout_style=menu
menuentry "Jammy - OS" --id=autoinstall {
    linux /jammy/vmlinuz ip=dhcp url=http://192.168.29.45/tftp/jammy/ubuntu-22.04.4-live-server-amd64.iso autoinstall ds='nocloud-net;s=http://192.168.29.45/tftp/jammy/' cloud-config-url=/dev/null root=/dev/ram0
    echo "Loading Ram Disk Now..."
    initrd /jammy/initrd
}

Let’s see the meaning of the GRUB menu:

  • creates a menu entry as Jammy – OS
  • gets an IP address from the DHCP
  • points the URL of the ISO file to the Apache directory path on the server
  • path to the autoinstall files is given through nocloud-net data source
  • loads the compressed kernel vmlinuz
  • sets the initrd file
  • shows the Loading Ram Disk Now… message

Also, the cloud-config-url=/dev/null setting stops cloud-init from performing multiple downloads of the ISO file.

UEFI mode needs downloading signed binaries and a font file for the GRUB menu:

  • shimx64.efi.signed.latest
  • grubnetx64.efi.signed
  • unicode.pf2

Thus, we place the above files in the TFTP root directory.

8. Testing

Let’s set up a test machine in VMware.

First, we set up the VM to boot from the network via the I will install the operating system later in the New Virtual Machine Wizard option:

VMware New VM Wizard
After the VM is set up, we tweak the VM settings and set the firmware type to UEFI. Also, we keep the rest of the VM settings unchanged. Finally, we start the VM and wait for the boot menu.

The VM should automatically start installing the OS after 10 seconds in the boot menu. Thus, the server installation should proceed without any user interaction.

At last, we press the Return key to get to the login screen:

Ubuntu Login Screen
At this point, we can log in with our username and password.

9. Conclusion

In this article, we’ve seen how to install Ubuntu 22.04 automatically. We also looked at how we can get an autoinstall file from a preseed file.

In short, we’ve used netbooting to install the OS. Also, we don’t need to restart the system. We can directly log into the new installation.