When was the last time you installed a new OS? Or let me ask it differently: when was the last time you refreshed your work environment?

Ten years ago? Has it been five years since you last touched it? Or maybe just last year? If you're someone like me who enjoys trying out new things, this period could be reduced to months, weeks, or even days.

In this post, I will explain how I automated the process of refreshing my operating system. You could say this post is a summary or simplified version of Automate Ubuntu 22.04 LTS Bare Metal.

We will use two USB drives for the setup: one for booting a temporary OS and the other for providing the cloud-init autoinstall configuration.

Instead of modifying the ISO and changing the boot settings, I prefer to proceed with a standard ISO and move forward with the user's confirmation. The installation won't be completely "no-touch," but I believe we've automated it sufficiently.

  1. Find the latest live-server ISO at the bottom of the 22.04 releases page and create a bootable USB with it. Keep in mind that there may be differences between versions. For instance, 22.04.4 does not include the wpasupplicant and openvswitch-switch packages. This could be an issue if you're using WiFi.

  2. Create a second USB named CIDATA for a cloud-init datasource.

# ensure the NEW USB is not mounted
sudo umount /dev/sda

# format using the FAT32 (`-F 32`) format and name (`-n`) the volume 'CIDATA' (`-I` for ignoring safety checks)
sudo mkfs.vfat -I -F 32 -n 'CIDATA' /dev/sda

mkdir /tmp/cidata
sudo mount /dev/sda /tmp/cidata

cd /tmp/cidata
touch meta-data

cat <<'EOF' > user-data
#cloud-config
autoinstall:
  version: 1
  identity:
    hostname: ubuntu-server
    username: ubuntu
    # "ubuntu" - created with `docker run -it --rm alpine mkpasswd --method=SHA-512`
    password: "$5$r3Kl6AKBqjA78VCX$4.Vuc56PR2faX3vLuqBxHxF796qiLhxuS4MacXtTt5C"
EOF

My exact user-data file:

#cloud-config
autoinstall:
  apt:
    disable_components: []
    geoip: true
    preserve_sources_list: false
    primary:
    - arches:
      - amd64
      - i386
      uri: http://archive.ubuntu.com/ubuntu
    - arches:
      - default
      uri: http://ports.ubuntu.com/ubuntu-ports
  drivers:
    install: false
  identity:
    hostname: host
    password: password_hash_for_shadow  # you can create one by reading https://unix.stackexchange.com/questions/81240/manually-generate-password-for-etc-shadow
    realname: username
    username: username
  kernel:
    package: linux-generic
  keyboard:
    layout: en
    toggle: null
    variant: ''
  locale: en_US.UTF-8
  network:
    ethernets:
      enp38s0:
        dhcp4: true    
    version: 2
  early-commands:
    - echo 'linux-generic-hwe-22.04' > /run/kernel-meta-package
  source:
    id: ubuntu-server
    search_drivers: true
  late-commands:
    - rm /target/etc/netplan/00-installer-config.yaml
    - >-
      printf "network:\n  version: 2\n  wifis:\n    wlo1:\n      access-points:\n        access-point-name:\n          password: pass\n      dhcp4: true\n      dhcp6: false\n      addresses: [192.168.1.300/24]\n      routes:\n        - to: default\n          via: 192.168.1.1\n      nameservers:\n        addresses: [192.168.1.1]"
      >> /target/etc/netplan/00-installer-config.yaml
  ssh:
    allow-pw: true
    install-server: true
  packages:
  - wpasupplicant
  - openvswitch-switch
  storage:
    config:
    - ptable: gpt
      serial: disk_serial
      wwn: disk_wwn
      path: /dev/nvme0n1
      wipe: superblock-recursive
      preserve: false
      grub_device: false
      type: disk
      id: disk0
    - device: disk0
      size: 1127219200
      wipe: superblock
      flag: boot
      number: 1
      preserve: false
      grub_device: true
      offset: 1048576
      type: partition
      id: partition-0
    - fstype: fat32
      volume: partition-0
      preserve: false
      type: format
      id: format-0
    - device: disk0
      size: 920074824192
      wipe: superblock
      number: 2
      preserve: false
      grub_device: false
      offset: 1128267776
      type: partition
      id: partition-1
    - fstype: ext4
      volume: partition-1
      preserve: false
      type: format
      id: format-1
    - path: /
      device: format-1
      type: mount
      id: mount-1
    - path: /boot/efi
      device: format-0
      type: mount
      id: mount-0
  updates: all
  shutdown: poweroff
  version: 1

Now you can boot the server. When prompted for confirmation, simply type y to proceed. And voilà! 😀

Previous Post