The purpose of this post is to describe different Ubuntu installer tools and to present Ubuntu 22.04 (Jammy) installing methods for desktop and server.
I assume you have functional DHCP, TFTP, HTTP server.
This example shows how to configure ISC DHCP server to boot a machine using a TFTP server.
allow booting;
allow bootp;
option arch code 93 = unsigned integer 16;
host ubuntu {
hardware ethernet xx:xx:xx:xx:xx:xx;
if option arch = 00:07 {
filename "boot/bootx64.efi";
} else {
filename "boot/pxelinux.0";
}
next-server x.x.x.x;
fixed-address x.x.x.x;
}
Get installer ISO file and copy the following grub files to the TFTP directory.
Jammy ISO: /boot/fonts/unicode.pf2 /EFI/boot/bootx64.efi /EFI/boot/grubx64.efi
Download pxelinux packages and extract the following files to the TFTP directory.
$ apt download pxelinux syslinux-common pxelinux: /usr/lib/PXELINUX/pxelinux.0 syslinux-common: /usr/lib/syslinux/modules/bios/ldlinux.c32 /usr/lib/syslinux/modules/bios/libutil.c32 /usr/lib/syslinux/modules/bios/menu.c32
The following example file layout can be used on the TFTP server.
. ├── boot │ ├── bootx64.efi │ ├── grubx64.efi │ ├── grub │ │ ├── font.pf2 │ │ ├── grub.cfg │ │ └── x86_64-efi │ │ ├── command.lst │ │ ├── crypto.lst │ │ ├── fs.lst │ │ └── terminal.lst │ ├── jammy │ │ ├── initrd │ │ └── vmlinuz │ ├── ldlinux.c32 -> syslinux/bios/ldlinux.c32 | ├── libutil.c32 -> syslinux/bios/libutil.c32 | ├── menu.c32 -> syslinux/bios/menu.c32 │ ├── pxelinux.cfg │ │ └── default │ ├── pxelinux.0 | └── syslinux | └── bios │ ├── ldlinux.c32 │ ├── libutil.c32 │ └── menu.c32 └── grub -> boot/grub
Sample configuration for grub in grub.cfg.
set timeout=30
loadfont unicode
set menu_color_normal=white/black
set menu_color_highlight=black/light-gray
menuentry "Install Ubuntu Jammy (22.04)" {
set gfxpayload=keep
linux /boot/jammy/vmlinuz ip=dhcp cloud-config-url=/dev/null url=http://x.x.x.x/jammy-live-server-amd64.iso autoinstall ds="nocloud-net;s=http://x.x.x.x/jammy/" --- # Don't forget the slash at the end.
initrd /boot/jammy/initrd
}
An example configuration in pxelinux.cfg/default.
default menu.c32
menu title Ubuntu installer
label jammy
menu label Install Ubuntu J^ammy (22.04)
menu default
kernel jammy/vmlinuz
initrd jammy/initrd
append ip=dhcp cloud-config-url=/dev/null url=http://x.x.x.x/jammy-live-server-amd64.iso autoinstall ds=nocloud-net;s=http://x.x.x.x/jammy/ # Don't forget the slash at the end.
prompt 0
timeout 300
At least two files needs to be placed on the webserver.
While Canonical announces autoinstall as a server installer, it can be used to install both server and desktop systems.
Two important differencies from Debian Installer, d-i:
An easy way to obtain a working user-data autoinstall configuration file is installing a machine by hand. Then copy the /var/log/installer/autoinstall-user-data file onto the webserver and customize it.
The following configuration examples are made using a QEMU virtual machine:
Kernel parameters
Partitioning examples are made with UEFI, go to BIOS boot disk layout if you have BIOS.
#cloud-config
autoinstall:
identity:
hostname: jammy-minimal
password: $6$gnqbMUzHhQzpDEw.$.cCNVVDsDfj5Feebh.5O4VbOmib7tyjmeI2ZsFP7VK2kWwgJFbfjvXo3chpeAqCgXWVIW9oNQ/Ag85PR0IsKD/
username: ubuntu
version: 1
The password is ubuntu. And that can be generated using the following command.
mkpasswd --method=sha-512 ubuntu
#cloud-config
autoinstall:
identity:
hostname: jammy-desktop
password: $6$5lpwCLsKLEzMkSJc$keOAhA6aO/5RocGThmhVA7LSNuW911Rx5HHXFEa75oGK20cEdAAgn14H5f5nGeq6QgcSyLPrWcg1.JvjXbhrN/
realname: Ubuntu user
username: ubuntu
keyboard:
layout: hu
toggle: null
variant: ''
locale: hu_HU.UTF-8
storage:
config:
# Partition table
- { ptable: gpt, path: /dev/vda, wipe: superblock, preserve: false, name: '', grub_device: false, type: disk, id: disk-vda }
# EFI boot partition
- { device: disk-vda, size: 536870912, wipe: superblock, flag: boot, number: 1, preserve: false, grub_device: true, type: partition, id: partition-0 }
- { fstype: fat32, volume: partition-0, preserve: false, type: format, id: format-0 }
# Linux boot partition
- { device: disk-vda, size: 1073741824, wipe: superblock, flag: '', number: 2, preserve: false, grub_device: false, type: partition, id: partition-1 }
- { fstype: ext4, volume: partition-1, preserve: false, type: format, id: format-1 }
# Partition for LVM, VG
- { device: disk-vda, size: -1, wipe: superblock, flag: '', number: 3, preserve: false, grub_device: false, type: partition, id: partition-2 }
- { name: ubuntu-vg, devices: [ partition-2 ], preserve: false, type: lvm_volgroup, id: lvm_volgroup-0 }
# LV for root
- { name: ubuntu-lv, volgroup: lvm_volgroup-0, size: -1, wipe: superblock, preserve: false, type: lvm_partition, id: lvm_partition-0 }
- { fstype: ext4, volume: lvm_partition-0, preserve: false, type: format, id: format-2 }
# Mount points
- { path: /, device: format-2, type: mount, id: mount-2 }
- { path: /boot, device: format-1, type: mount, id: mount-1 }
- { path: /boot/efi, device: format-0, type: mount, id: mount-0 }
# Swapfile on root volume
swap:
swap: 1G
late-commands:
- 'echo "ubuntu ALL=(ALL) NOPASSWD:ALL" > /target/etc/sudoers.d/ubuntu-nopw'
- chmod 440 /target/etc/sudoers.d/ubuntu-nopw
- curtin in-target --target=/target -- sed -i 's/GRUB_CMDLINE_LINUX_DEFAULT=""/GRUB_CMDLINE_LINUX_DEFAULT="quiet splash"/' /etc/default/grub
- curtin in-target --target=/target -- apt-get install -y ubuntu-desktop plymouth-theme-ubuntu-logo grub-gfxpayload-lists
version: 1
Size of the LVM partition and size of the root LV is -1 which instruct the installer to use all the remaining space. A partition or volume with size: -1 must be the last in the config. In the above example: installer creates the last partition on all the available space and creates the last defined logical volume on all the available space in the volume group.
#cloud-config
autoinstall:
identity:
hostname: jammy-desktop-crypt
password: $6$5lpwCLsKLEzMkSJc$keOAhA6aO/5RocGThmhVA7LSNuW911Rx5HHXFEa75oGK20cEdAAgn14H5f5nGeq6QgcSyLPrWcg1.JvjXbhrN/
realname: Ubuntu user
username: ubuntu
keyboard:
layout: hu
toggle: null
variant: ''
locale: hu_HU.UTF-8
storage:
config:
- { ptable: gpt, path: /dev/vda, wipe: superblock, preserve: false, name: '', grub_device: false, type: disk, id: disk-vda }
- { device: disk-vda, size: 536870912, wipe: superblock, flag: boot, number: 1, preserve: false, grub_device: true, type: partition, id: partition-0 }
- { fstype: fat32, volume: partition-0, preserve: false, type: format, id: format-0 }
- { device: disk-vda, size: 1073741824, wipe: superblock, flag: '', number: 2, preserve: false, grub_device: false, type: partition, id: partition-1 }
- { fstype: ext4, volume: partition-1, preserve: false, type: format, id: format-1 }
- { device: disk-vda, size: -1, wipe: superblock, flag: '', number: 3, preserve: false, grub_device: false, type: partition, id: partition-2 }
# DM crypt
- { volume: partition-2, key: ubuntu, preserve: false, type: dm_crypt, id: dm_crypt-0 }
- { name: ubuntu-vg, devices: [ dm_crypt-0 ], preserve: false, type: lvm_volgroup, id: lvm_volgroup-0 }
- { name: ubuntu-lv, volgroup: lvm_volgroup-0, size: -1, wipe: superblock, preserve: false, type: lvm_partition, id: lvm_partition-0 }
- { fstype: ext4, volume: lvm_partition-0, preserve: false, type: format, id: format-2 }
- { path: /, device: format-2, type: mount, id: mount-2 }
- { path: /boot, device: format-1, type: mount, id: mount-1 }
- { path: /boot/efi, device: format-0, type: mount, id: mount-0 }
swap:
swap: 1G
late-commands:
- 'echo "ubuntu ALL=(ALL) NOPASSWD:ALL" > /target/etc/sudoers.d/ubuntu-nopw'
- chmod 440 /target/etc/sudoers.d/ubuntu-nopw
- curtin in-target --target=/target -- sed -i 's/GRUB_CMDLINE_LINUX_DEFAULT=""/GRUB_CMDLINE_LINUX_DEFAULT="quiet splash"/' /etc/default/grub
- curtin in-target --target=/target -- apt-get install -y ubuntu-desktop plymouth-theme-ubuntu-logo grub-gfxpayload-lists
version: 1
The DM crypt key is ubuntu in cleartext.
#cloud-config
autoinstall:
identity:
hostname: jammy-server
password: $6$5lpwCLsKLEzMkSJc$keOAhA6aO/5RocGThmhVA7LSNuW911Rx5HHXFEa75oGK20cEdAAgn14H5f5nGeq6QgcSyLPrWcg1.JvjXbhrN/
realname: Ubuntu user
username: ubuntu
keyboard:
layout: hu
toggle: null
variant: ''
locale: hu_HU.UTF-8
ssh:
allow-pw: false
authorized-keys: [ '<SSH KEY>' ]
install-server: true
storage:
config:
- { ptable: gpt, path: /dev/vda, wipe: superblock, preserve: false, name: '', grub_device: false, type: disk, id: disk-vda }
- { device: disk-vda, size: 536870912, wipe: superblock, flag: boot, number: 1, preserve: false, grub_device: true, type: partition, id: partition-0 }
- { fstype: fat32, volume: partition-0, preserve: false, type: format, id: format-0 }
- { device: disk-vda, size: 1073741824, wipe: superblock, flag: '', number: 2, preserve: false, grub_device: false, type: partition, id: partition-1 }
- { fstype: ext4, volume: partition-1, preserve: false, type: format, id: format-1 }
- { device: disk-vda, size: -1, wipe: superblock, flag: '', number: 3, preserve: false, grub_device: false, type: partition, id: partition-2 }
- { name: ubuntu-vg, devices: [ partition-2 ], preserve: false, type: lvm_volgroup, id: lvm_volgroup-0 }
- { name: ubuntu-lv, volgroup: lvm_volgroup-0, size: 10G, wipe: superblock, preserve: false, type: lvm_partition, id: lvm_partition-0 }
- { fstype: ext4, volume: lvm_partition-0, preserve: false, type: format, id: format-2 }
- { path: /, device: format-2, type: mount, id: mount-2 }
- { path: /boot, device: format-1, type: mount, id: mount-1 }
- { path: /boot/efi, device: format-0, type: mount, id: mount-0 }
# Swap LV
- { name: swap, volgroup: lvm_volgroup-0, size: 1073741824B, wipe: superblock, preserve: false, type: lvm_partition, id: lvm_partition-1 }
- { fstype: swap, volume: lvm_partition-1, preserve: false, type: format, id: format-3 }
- { path: '', device: format-3, type: mount, id: mount-3 }
late-commands:
- 'echo "ubuntu ALL=(ALL) NOPASSWD:ALL" > /target/etc/sudoers.d/ubuntu-nopw'
- chmod 440 /target/etc/sudoers.d/ubuntu-nopw
version: 1
An ssh public key can be copied to the newly installed machine. Just replace <SSH KEY> placeholder with your ssh public key (for example with the output of cat ~/.ssh/id_rsa.pub). Password SSH authentication is disabled.
This example describes the setup of a swap LV instead of a swapfile on root volume.
#cloud-config
autoinstall:
identity:
hostname: jammy-server-raid
password: $6$5lpwCLsKLEzMkSJc$keOAhA6aO/5RocGThmhVA7LSNuW911Rx5HHXFEa75oGK20cEdAAgn14H5f5nGeq6QgcSyLPrWcg1.JvjXbhrN/
realname: Ubuntu user
username: ubuntu
keyboard:
layout: hu
toggle: null
variant: ''
locale: hu_HU.UTF-8
ssh:
allow-pw: false
authorized-keys: [ '<SSH KEY>' ]
install-server: true
storage:
config:
# Partition table of two disks
- { ptable: gpt, path: /dev/vda, wipe: superblock-recursive, preserve: false, name: '', grub_device: false, type: disk, id: disk-vda }
- { ptable: gpt, path: /dev/vdb, wipe: superblock-recursive, preserve: false, name: '', grub_device: false, type: disk, id: disk-vdb }
# Install GRUB on first disk
- { device: disk-vda, size: 536870912, wipe: superblock, flag: boot, number: 1, preserve: false, grub_device: true, type: partition, id: partition-3 }
- { fstype: fat32, volume: partition-3, preserve: false, type: format, id: format-2 }
# Install GRUB on second disk
- { device: disk-vdb, size: 536870912, wipe: superblock, flag: boot, number: 1, preserve: false, grub_device: true, type: partition, id: partition-8 }
- { fstype: fat32, volume: partition-8, preserve: false, type: format, id: format-5 }
- { device: disk-vda, size: 1073741824, wipe: superblock, flag: '', number: 2, preserve: false, grub_device: false, type: partition, id: partition-9 }
- { device: disk-vdb, size: 1073741824, wipe: superblock, flag: '', number: 2, preserve: false, grub_device: false, type: partition, id: partition-10 }
- { device: disk-vda, size: -1, wipe: superblock, flag: '', number: 3, preserve: false, grub_device: false, type: partition, id: partition-11 }
- { device: disk-vdb, size: -1, wipe: superblock, flag: '', number: 3, preserve: false, grub_device: false, type: partition, id: partition-12 }
# RAID1 for boot partition and root volume
- { name: md0, raidlevel: raid1, devices: [ partition-10, partition-9 ], spare_devices: [], preserve: false, wipe: superblock, type: raid, id: raid-0 }
- { name: md1, raidlevel: raid1, devices: [ partition-11, partition-12 ], spare_devices: [], preserve: false, wipe: superblock, type: raid, id: raid-1 }
# An ext4 boot filesystem on MD
- { fstype: ext4, volume: raid-0, preserve: false, type: format, id: format-3 }
# LVM on MD
- { name: vg0, devices: [ raid-1 ], preserve: false, type: lvm_volgroup, id: lvm_volgroup-0 }
- { name: lv-0, volgroup: lvm_volgroup-0, size: 10737418240B, wipe: superblock, preserve: false, type: lvm_partition, id: lvm_partition-0 }
- { fstype: ext4, volume: lvm_partition-0, preserve: false, type: format, id: format-4 }
- { path: /, device: format-4, type: mount, id: mount-4 }
- { path: /boot, device: format-3, type: mount, id: mount-3 }
# Install GRUB on both disks
- { path: /boot/efi, device: format-2, type: mount, id: mount-2 }
- { path: /boot/efi2, device: format-5, type: mount, id: mount-5 }
# Swap
- { name: swap, volgroup: lvm_volgroup-0, size: 1073741824B, wipe: superblock, preserve: false, type: lvm_partition, id: lvm_partition-1 }
- { fstype: swap, volume: lvm_partition-1, preserve: false, type: format, id: format-6 }
- { path: '', device: format-6, type: mount, id: mount-6 }
late-commands:
- 'echo "ubuntu ALL=(ALL) NOPASSWD:ALL" > /target/etc/sudoers.d/ubuntu-nopw'
- chmod 440 /target/etc/sudoers.d/ubuntu-nopw
version: 1
GRUB is installed on both disks and then the two EFI partitions are also mounted under /boot.
An MD RAID1 array is configured for boot and for LVM.
#cloud-config
autoinstall:
identity:
hostname: jammy-server-raid-bond
password: $6$5lpwCLsKLEzMkSJc$keOAhA6aO/5RocGThmhVA7LSNuW911Rx5HHXFEa75oGK20cEdAAgn14H5f5nGeq6QgcSyLPrWcg1.JvjXbhrN/
realname: Ubuntu user
username: ubuntu
keyboard:
layout: hu
toggle: null
variant: ''
locale: hu_HU.UTF-8
network:
bonds:
bond0:
addresses:
- 192.168.1.5/24
gateway4: 192.168.1.1
interfaces:
- ens10
- ens3
nameservers:
addresses:
- 192.168.1.2
search:
- example.com
parameters:
mode: balance-rr
ethernets:
ens10: {}
ens3: {}
version: 2
ssh:
allow-pw: false
authorized-keys: [ '<SSH KEY>' ]
install-server: true
storage:
config:
- { ptable: gpt, path: /dev/vda, wipe: superblock-recursive, preserve: false, name: '', grub_device: false, type: disk, id: disk-vda }
- { ptable: gpt, path: /dev/vdb, wipe: superblock-recursive, preserve: false, name: '', grub_device: false, type: disk, id: disk-vdb }
- { device: disk-vda, size: 536870912, wipe: superblock, flag: boot, number: 1, preserve: false, grub_device: true, type: partition, id: partition-3 }
- { fstype: fat32, volume: partition-3, preserve: false, type: format, id: format-2 }
- { device: disk-vdb, size: 536870912, wipe: superblock, flag: boot, number: 1, preserve: false, grub_device: true, type: partition, id: partition-8 }
- { fstype: fat32, volume: partition-8, preserve: false, type: format, id: format-5 }
- { device: disk-vda, size: 1073741824, wipe: superblock, flag: '', number: 2, preserve: false, grub_device: false, type: partition, id: partition-9 }
- { device: disk-vdb, size: 1073741824, wipe: superblock, flag: '', number: 2, preserve: false, grub_device: false, type: partition, id: partition-10 }
- { device: disk-vda, size: -1, wipe: superblock, flag: '', number: 3, preserve: false, grub_device: false, type: partition, id: partition-11 }
- { device: disk-vdb, size: -1, wipe: superblock, flag: '', number: 3, preserve: false, grub_device: false, type: partition, id: partition-12 }
- { name: md0, raidlevel: raid1, devices: [ partition-10, partition-9 ], spare_devices: [], preserve: false, wipe: superblock, type: raid, id: raid-0 }
- { name: md1, raidlevel: raid1, devices: [ partition-11, partition-12 ], spare_devices: [], preserve: false, wipe: superblock, type: raid, id: raid-1 }
- { fstype: ext4, volume: raid-0, preserve: false, type: format, id: format-3 }
- { name: vg0, devices: [ raid-1 ], preserve: false, type: lvm_volgroup, id: lvm_volgroup-0 }
- { name: lv-0, volgroup: lvm_volgroup-0, size: 10737418240B, wipe: superblock, preserve: false, type: lvm_partition, id: lvm_partition-0 }
- { fstype: ext4, volume: lvm_partition-0, preserve: false, type: format, id: format-4 }
- { path: /, device: format-4, type: mount, id: mount-4 }
- { path: /boot, device: format-3, type: mount, id: mount-3 }
- { path: /boot/efi, device: format-2, type: mount, id: mount-2 }
- { path: /boot/efi2, device: format-5, type: mount, id: mount-5 }
- { name: swap, volgroup: lvm_volgroup-0, size: 1073741824B, wipe: superblock, preserve: false, type: lvm_partition, id: lvm_partition-1 }
- { fstype: swap, volume: lvm_partition-1, preserve: false, type: format, id: format-6 }
- { path: '', device: format-6, type: mount, id: mount-6 }
late-commands:
- 'echo "ubuntu ALL=(ALL) NOPASSWD:ALL" > /target/etc/sudoers.d/ubuntu-nopw'
- chmod 440 /target/etc/sudoers.d/ubuntu-nopw
version: 1
A complete netplan configuration is found in this autoinstall example using two cards in bond.
Partition layout needs to be changed when system firmware is BIOS. Partition table type is still GPT, but first partition is a special BIOS boot partition.
storage:
config:
# Install GRUB in MBR
- { ptable: gpt, path: /dev/vda, wipe: superblock, preserve: false, name: '', grub_device: true, type: disk, id: disk-vda }
# BIOS boot partition
- { device: disk-vda, size: 1048576, flag: bios_grub, number: 1, preserve: false, grub_device: false, type: partition, id: partition-0 }
# boot
- { device: disk-vda, size: 1073741824, wipe: superblock, flag: '', number: 2, preserve: false, grub_device: false, type: partition, id: partition-1 }
- { fstype: ext4, volume: partition-1, preserve: false, type: format, id: format-1 }
- { device: disk-vda, size: -1, wipe: superblock, flag: '', number: 3, preserve: false, grub_device: false, type: partition, id: partition-2 }
- { name: ubuntu-vg, devices: [ partition-2 ], preserve: false, type: lvm_volgroup, id: lvm_volgroup-0 }
- { name: ubuntu-lv, volgroup: lvm_volgroup-0, size: -1, wipe: superblock, preserve: false, type: lvm_partition, id: lvm_partition-0 }
- { fstype: ext4, volume: lvm_partition-0, preserve: false, type: format, id: format-2 }
- { path: /, device: format-2, type: mount, id: mount-2 }
- { path: /boot, device: format-1, type: mount, id: mount-1 }
#cloud-config
chpasswd:
list:
- installer:$6$gnqbMUzHhQzpDEw.$.cCNVVDsDfj5Feebh.5O4VbOmib7tyjmeI2ZsFP7VK2kWwgJFbfjvXo3chpeAqCgXWVIW9oNQ/Ag85PR0IsKD/
ssh_authorized_keys:
- <SSH KEY>
autoinstall:
identity:
hostname: jammy-minimal
password: $6$gnqbMUzHhQzpDEw.$.cCNVVDsDfj5Feebh.5O4VbOmib7tyjmeI2ZsFP7VK2kWwgJFbfjvXo3chpeAqCgXWVIW9oNQ/Ag85PR0IsKD/
username: ubuntu
version: 1
The chpasswd and ssh_authorized_keys cloud-init modules configure installer credentials. Be aware, that chpasswd, ssh_authorized_keys and autoinstall are on the same level. Password is ubuntu.
Integrating OpenStack Ussuri and a single node Hyper-V 2019 Server.
Installing Ubuntu on cheap Acer Aspire notebooks can be a bit tricky but not impossible.
I had to made a firmware re-flashing of my Eaton 5P 1150 after replacing batteries.
Setting up static IP configuration, DNS resolver and Open vSwitch on Ubuntu 18.04: netplan, ifupdown, systemd-networkd.
Using a serial port connected UPS on OpenWrt with NUT.
Disable Intel Hyper-Threading on Linux in software, not in BIOS/UEFI.
Migration of BIND and OpenDNSSEC to PowerDNS 4 with DNSSEC.
Installation of Altera Quartus II 14.0 and setting up of ModelSim Altera Edition on Ubuntu 14.10
JTAG programming of an Altera FPGA, through an SSH tunnel with Quartus II. The device is on the network, connected to a remote machine through USB Blaster.