Beta 42

Research and Development

Menu

Install Ubuntu with Manual LVM Setup

The problem with installing Ubuntu with LVM using the installer will only give you 1 GB of swap space, which is insufficient for 16 GB of RAM. Also, it would install everything into a single root partition. Should more flexibility and control over the partitioning is required with encrypted LVM setup, read on.

Boot Modes

Even before starting the installer it is critical to select the correct boot mode. Ubuntu (and flavours like Kubuntu, Lubuntu, Xubuntu, etc.) uses hybrid bootable images that have two alternate boot-loaders:

  1. GRUB (GRand Unified Bootloader)
  2. Syslinux

The ISO images can boot in several possible combinations of mode and partitioning:

  1. ISO-9660 El-Torito (the CD/DVD optical media boot mechanism - uses Syslinux)
  2. GPT + EFI-SP (GUID Partition Table and EFI System Partition - uses GRUB)
  3. MBR + EFI-SP (Master Boot Record and EFI System Partition - uses GRUB)
  4. GPT + PC (GUID Partition Table and BIOS boot - uses Syslinux)
  5. MBR + PC (Master Boot Record and BIOS boot - uses Syslinux)

More on boot modes here.

Install Linux

If the boot hasn't been interrupted to choose a language the Welcome dialog with start-up options will be displayed. Choose Try Ubuntu.

Once the Live Desktop environment has started use the terminal shell command-line to issue a series of commands to pre-prepare the target device before executing the Installer itself.

Pre-Prepare Encrypted Partitions

For all or most of the commands the elevated privileges will be needed:

$ sudo -i

Identify Installation Target Device:

$ lsblk

NAME  MAJ:MIN RM   SIZE RO TYPE MOUNTPOINT
loop0   7:0    0     2G  1 loop /rofs
loop1   7:1    0 217.9M  1 loop /snap/gnome-3-34-1804/60
loop2   7:2    0  55.3M  1 loop /snap/core18/1885
loop3   7:3    0  50.7M  1 loop /snap/snap-store/481
loop4   7:4    0  30.9M  1 loop /snap/snapd/9721
loop5   7:5    0  62.1M  1 loop /snap/gtk-common-themes/1506
sda     8:0    0    54G  0 disk 
sr0    11:0    1   2.7G  0 rom  /cdrom

Here the installation target device is sda but it may vary so examine the SIZE to ensure the correct target.

Set up an environment variable to re-use in all future commands. Doing this will allow to copy and paste the instructions directly into the terminal. In this example it will be /dev/sda:

$ export DEV="/dev/sda"

On systems with NVME storage devices the naming scheme is /dev/nvme${CONTROLLER}n${NAMESPACE}p${PARTITION}, so if there is only one device it is likely it would require:

$ export DEV="/dev/nvme0n1"

Finally, set an environment variable for the encrypted device-mapper naming that omits the leading path /dev/ part:

$ export DM="${DEV##*/}"

If NVME devices needing a 'p' for partition suffix are needed:

$ export DEVP="${DEV}$( if [[ "$DEV" =~ "nvme" ]]; then echo "p"; fi )"
$ export DM="${DM}$( if [[ "$DM" =~ "nvme" ]]; then echo "p"; fi )"

Partitioning

Create a disk label and add four partitions. We'll be creating a GPT (GUID Partition Table) so it is compatible with both UEFI and BIOS mode installations. We'll also create partitions for both modes in addition to the partitions for the encrypted /boot/ and / file-systems.

The sgdisk tool will be used in this tutorial. To understand its options, please read man 8 sgdisk.

First check for any existing partitions on the device and if some are found consider to keep them or not. If they should be kept, DO NOT USE sgdisk --zap-all command detailed next. Instead, consider freeing up disk space by shrinking or deleting individual existing partitions.

$ sgdisk --print $DEV

Creating new GPT entries in memory.
Disk /dev/sda: 113246208 sectors, 54.0 GiB
Model: VMware Virtual S
Sector size (logical/physical): 512/512 bytes
Disk identifier (GUID): 51FA5074-ACC1-4111-968E-1CDCC7DE5377
Partition table holds up to 128 entries
Main partition table begins at sector 2 and ends at sector 33
First usable sector is 34, last usable sector is 113246174
Partitions will be aligned on 2048-sector boundaries
Total free space is 113246141 sectors (50.0 GiB)

If it is safe to delete everything on this device, wipe out the existing partitioning metadata - DO NOT DO THIS if you are installing alongside existing partitions:

$ sgdisk --zap-all $DEV

Creating new GPT entries in memory.
GPT data structures destroyed! You may now partition the disk using fdisk or
other utilities.

Now create the partitions: A small bios_boot (2MB) partition for BIOS-mode GRUB's core image, an 128MB EFI System Partition, a 768MB /boot/ and a final partition for the remaining space for the operating system.

Syntax: sgdisk --new=<partition_number>:<start>:<end> where start and end can be relative values and when zero (0) adopt the lowest or highest possible value respectively.

$ sgdisk --new=1:0:+768M $DEV
$ sgdisk --new=2:0:+2M $DEV
$ sgdisk --new=3:0:+128M $DEV
$ sgdisk --new=4:0:0 $DEV
$ sgdisk --typecode=1:8301 --typecode=2:ef02 --typecode=3:ef00 --typecode=4:8301 $DEV
$ sgdisk --change-name=1:/boot --change-name=2:GRUB --change-name=3:EFI-SP --change-name=4:rootfs $DEV
$ sgdisk --hybrid 1:2:3 $DEV
$ sgdisk --print $DEV

Disk /dev/sda: 113246208 sectors, 50.0 GiB
Model: VMware Virtual S
Sector size (logical/physical): 512/512 bytes
Disk identifier (GUID): 5B10576E-9A21-43EA-A0AD-58FDA9C337E3
Partition table holds up to 128 entries
Main partition table begins at sector 2 and ends at sector 33
First usable sector is 34, last usable sector is 113246174
Partitions will be aligned on 2048-sector boundaries
Total free space is 2014 sectors (1007.0 KiB)

Number  Start (sector)    End (sector)  Size       Code  Name
   1            2048         1574911   768.0 MiB   8301  /boot
   2         1574912         1579007   2.0 MiB     EF02  GRUB
   3         1579008         1841151   128.0 MiB   EF00  EFI-SP
   4         1841152       113246174   49.1 GiB    8301  rootfs

LUKS Encrypt

The default LUKS (Linux Unified Key Setup) format used by the cryptsetup tool has changed since the release of 18.04 Bionic. 18.04 used version 1 (luks1) but more recent Ubuntu releases default to version 2 (luks2). GRUB only supports opening version 1 so we have to explicitly set luks1 in the commands we use or else GRUB will not be able to install to, or unlock, the encrypted device.

In summary, the LUKS container for /boot/ must currently use LUKS version 1 whereas the container for the operating system's root file-system can use the default LUKS version 2.

First the /boot/ partition:

$ cryptsetup luksFormat --type=luks1 ${DEVP}1

WARNING!
========
This will overwrite data on /dev/sda1 irrevocably.

Are you sure? (Type uppercase yes): YES
Enter passphrase for /dev/sda1: 
Verify passphrase: 

Now the operating system partition:

$ cryptsetup luksFormat ${DEVP}4

WARNING!
========
This will overwrite data on /dev/sda4 irrevocably.

Are you sure? (Type uppercase yes): YES
Enter passphrase for /dev/sda4: 
Verify passphrase: 

LUKS unlock

Now open the encrypted devices:

$ cryptsetup open ${DEVP}1 boot
Enter passphrase for /dev/sda1: 

$ cryptsetup open ${DEVP}4 os
Enter passphrase for /dev/sda5: 

$ ls /dev/mapper/
control boot os

After the Ubuntu installation is finished we will be adding key-files to both of these devices so that you'll only have to type the pass-phrase once for GRUB and thereafter the operating system will use embedded key-files to unlock without user intervention.

Format File-systems

IMPORTANT: This step must be done otherwise the Installer's partitioner will disable the ability to write a file-system to this device without it having a partition table (Man-page for mkfs.ext4):

$ mkfs.ext4 -L boot /dev/mapper/boot

mke2fs 1.44.6 (5-Mar-2019)
Creating filesystem with 196096 4k blocks and 49056 inodes
Filesystem UUID: 659410fb-29a7-40af-9a5f-4dc31b72ad0a
Superblock backups stored on blocks: 
        32768, 98304, 163840

Allocating group tables: done                            
Writing inode tables: done                            
Creating journal (4096 blocks): done
Writing superblocks and filesystem accounting information: done

Format the EFI-SP as FAT16 (Man-page for mkfs.vfat):

$ mkfs.vfat -F 16 -n EFI-SP ${DEVP}3
mkfs.fat 4.1 (2017-01-24)

LVM (Logical Volume Management)

Now create the operating system LVM Volume Group (VG) and a Logical Volume (LV) for the root file-system.

Also create a 6GB LV device for swap which, as well as being used to provide additional memory pages when free RAM space is low, is used to store a hibernation image of memory so the system can be completely powered off and can resume all applications where they left off. More on swap partitions here.

Man-pages for pvcreate, vgcreate and lvcreate.

$ pvcreate /dev/mapper/os
  Physical volume "/dev/mapper/os" successfully created.

$ vgcreate vg1 /dev/mapper/os
  Volume group "vg1" successfully created

$ lvcreate -L 6G -n swap vg1
  Logical volume "swap" created.

$ lvcreate -L 30G -n root vg1
  Logical volume "root" created.

$ lvcreate -l 100%FREE -n home vg1
  Logical volume "home" created.

Install Ubuntu

Now minimise the Terminal window and start the Installer.

Choose the installation language and keyboard and then the software installation choices.

In the Installation Type options choose Something Else.

Manual Partitioning

Select the boot file-system device for formatting (/dev/mapper/boot), press the Change button. Choose Use as Ext4... and Mount point /boot.

Select the home file-system device for formatting (/dev/mapper/vg1-home), press the Change button, choose Use As Ext4... and Mount point /home.

Select the root file-system device for formatting (/dev/mapper/vg1-root), press the Change button, choose Use As Ext4... and Mount point /.

Select the swap device (/dev/mapper/vg1-swap), press the Change button, choose Use as swap area.

Select the boot-loader device (/dev/sda as used here). Boot-loader device should always be a raw disk, not a partition or device-mapper node.

Press the Install Now button to write the changes to the disk and press the Continue button.

Enable Encrypted GRUB

As soon as you have completed those forms switch to the Terminal to configure GRUB. These commands wait until the installer has created the GRUB directories and then adds a drop-in file telling GRUB to use an encrypted file-system. The command will not return to the shell prompt until the target directory has been created by the installer. In most cases that will have been done before this command is executed so it should instantly return:

$ while [ ! -d /target/etc/default/grub.d ]; do sleep 1; done; echo "GRUB_ENABLE_CRYPTODISK=y" > /target/etc/default/grub.d/local.cfg

This has to be done before the installer reaches the Install Bootloader stage at the end of the installation process.

If installation is successful choose the Continue Testing option.

Post-Installation Steps

Return to the Terminal and create a change-root environment to work in the newly installed OS (Man-pages for mount, chroot):

$ mount /dev/mapper/vg1-root /target
$ for n in proc sys dev etc/resolv.conf; do mount --rbind /$n /target/$n; done 
$ chroot /target

$ mount -a

Note: The cryptsetup-initramfs package is not available in 18.04 Bionic because the files are included in the main cryptsetup package.

$ apt install -y cryptsetup-initramfs

This allows the encrypted volumes to be automatically unlocked at boot-time. The key-file and supporting scripts are added to the /boot/initrd.img-$VERSION files.

This is safe because these files are themselves stored in the encrypted /boot/ which is unlocked by the GRUB boot-loader (which asks you to type the passphrase) which then loads the kernel and initrd.img into RAM before handing execution over to the kernel. (Man-page for initramfs.conf):

$ echo "KEYFILE_PATTERN=/etc/luks/*.keyfile" >> /etc/cryptsetup-initramfs/conf-hook 
$ echo "UMASK=0077" >> /etc/initramfs-tools/initramfs.conf 

Create a randomised key-file of 4096 bits (512 bytes), secure it, and add it to the LUKS volumes (Man-pages for dd, chmod):

$ mkdir /etc/luks
$ dd if=/dev/urandom of=/etc/luks/boot_os.keyfile bs=512 count=1

1+0 records in u=rx,go-rwx /etc/luks
1+0 records out
512 bytes copied, 0.00136846 s, 374 kB/s

$ chmod u=rx,go-rwx /etc/luks
$ chmod u=r,go-rwx /etc/luks/boot_os.keyfile

$ cryptsetup luksAddKey ${DEVP}1 /etc/luks/boot_os.keyfile 
Enter any existing passphrase: 

$ cryptsetup luksAddKey ${DEVP}4 /etc/luks/boot_os.keyfile 

WARNING: Locking directory /run/cryptsetup is missing!
Enter any existing passphrase:

Add the keys to the crypttab (Man-pages for crypttab, blkid):

$ echo "boot UUID=$(blkid -s UUID -o value ${DEVP}1) /etc/luks/boot_os.keyfile luks,discard" >> /etc/crypttab
$ echo "os UUID=$(blkid -s UUID -o value ${DEVP}4) /etc/luks/boot_os.keyfile luks,discard" >> /etc/crypttab

Finally update the initialramfs files to add the cryptsetup unlocking scripts and the key-file:

$ update-initramfs -u -k all

If everything has gone well the system is now ready to reboot.