Installing Ubuntu 20.04 over SSH

Created On:

I obtained a home server which I wanted to install Ubuntu 1 on. There was no serial port available and the only video out is VGA. I don’t have a VGA capable display so I was stumped on how to install Ubuntu. This post outlines my failed and successful attempts in case anyone has the same problem.

Failed Attempt 1: Installing on Another Host

My first attempt was to do the installation on another computer and then attach the hard drive to the server. This might work in cases where the other computer conducting the installation and the server are very similar. However, the only other available computers to me are MacBooks. Using a MacBook to to run the installer created two problems.

First, MacBooks only have EFI boot and the installer running on the MacBook will boot via EFI. The installer detects that it has been booted by EFI and partitions the hard drive for EFI2. Unfortunately, in my case the server has no EFI support so this results in an unbootable disk.

Second, my MacBook only has WiFi and no Ethernet whereas the server only has Ethernet. The installer will create netplan files based on the network devices available to the installer, meaning that there is no netplan file created to activate the Ethernet link and enable DHCP. Even if the hard drive was bootable on the server, it wouldn’t be able to get an IP address on start.

The combination of above meant that I couldn’t run the installer on my MacBook and then attach the hard drive to the server.

Failed Attempt 2: “Connecting to the installer over SSH”

The Ubuntu Server documentation says that it’s possible to connect to the installer over SSH:

If the only available terminal is very basic, an alternative is to connect via SSH. If the network is up by the time the installer starts, instructions are offered on the initial screen in basic mode. Otherwise, instructions are available from the help menu once networking is configured.

The help screen of the installer does list instructions on how to ssh into the host as the installer user. However the subiquity installer has a code snippet to generate a random password every time the installer is run:

passwd = rand_user_password()
cp = run_command('chpasswd', input=username + ':'+passwd+'\n')

Without serial or VGA access to the host, it’s not possible to see the generated password and therefore ssh into the installer.

What what actually worked

The only thing that worked for me was to modify the ISO to hard code the password of the installer user. It’s possible to do this because the Ubuntu Server documentation describes how the installation can be automated with cloud-init. The documentation suggests how to set up a user-data file that can fully automate the installer like so:

#cloud-config
autoinstall:
  version: 1
  ...

I didn’t want to autoinstall but I realized that the user-data file also supports a chpasswd section to set the password of a user. With this, it’s possible to create a user-data file like this:

#cloud-config
chpasswd:
    expire: false
    list:
        - installer:$6$exDY1mhS4KUYCE/2$zmn9ToZwTKLhCw.b4/b.ZRTIZM30JZ4QrOQ2aOXJ8yk96xpcCof0kxKwuX1kqLG/ygbJ1f8wxED22bTL4F46P0

Which will have cloud-init set the password of the installer user to ubuntu. To have the installer use this file, I needed to provide a nocloud cloud-init datasource. This means I needed to create a new Ubuntu Server ISO which has the above user-data file in it.

Creating a new ISO

To create a new ISO I first fetched a live-server ISO. Then extract it into a temporary directory:

$ 7z -y x ubuntu-20.04.3-live-server-amd64.iso -oiso

Inside the iso directory I created a new directory called nocloud and placed the user-data file and an empty meta-data file.

$ cd iso
$ mkdir nocloud
$ cd nocloud
$ vim user-data
$ touch `meta-data`

Then for the following files in the ISO:

I changed the kernel parameters to have ds=nocloud;s=/cdrom/nocloud set. These flags will be passed to cloud-init which will discover our user-data file and run chpasswd. I then made a new ISO by running:

$ mkisofs -o myiso.iso -ldots -allow-multidot -d -r -l -J  -no-emul-boot -boot-load-size 4 -boot-info-table -b isolinux/isolinux.bin -c isolinux/boot.cat iso

$ isohybrid myiso.iso

The resulting myiso.iso can be imaged on to a USB key, and inserted to the server. Once the server has obtained and IP address it’s possible to ssh into the host with the user name installer and password ubuntu. The subiquity installer will start up automatically.

Conclusion

It’s possible to install Ubuntu on a headless machine and use the installer over SSH by building a new ISO. This ISO passes in a configuration file for cloud-init which sets the password to the installer user. Once the installer has booted on the machine, just SSH in as the installer user.


  1. A HP ProLiant G7 N54L.↩︎

  2. This is actually a pretty reasonable assumption to make in 2021.↩︎