Advanced Partitioning in RHEL9 Text Mode Installer

Setting up LUKS/LVM/MDRAID on RHEL without a video card.

Advanced Partitioning in RHEL9 Text Mode Installer

Red Hat's Anaconda installer is a wonderful and intuitive thing, but it's bare bones if you do not have a graphics card in your machine. My HoneyComb LX2K is running with only a serial port and nothing else. Attached to it are 3 2TB hard drives that I wanted in an mdraid with encryption and LVM. The text based installer for RHEL9 does not support this at all. It will, however, find devices you've already setup and opened. So we'll go ahead and do that.

I'm going to assume you're a competent Linux user who can navigate the rest of the install yourself. This blog post will focus on disk setup.

My example consists of the following:

  • 3 hard drives
  • 3 partitions each for 3 raid volumes
  • 2 drives actively in RAID1, 1 for spare.
  • luks encryption on raid volume 3
  • lvm on top of luks

This should basically include an example of everything you want to do.

The text based installer is actually a tmux session. The highlighted bar at the bottom should help you navigate. Hit Ctrl+B and then press 2 to get into a shell.

Step 1: Partitioning

We need at least 3 volumes,

  • EFI System Partition
  • Boot partition
  • Everything else

Verify the drives you're using in /dev, mine are sda, sdb and sdc. Start with the first drive going into the raid.

fdisk /dev/sda

Press g to create a new GPT. n creates new partitions and t changes the partition type. Navigate the prompts and do the following:

  • n, select default start sector, then+200M, t, 1 - 200MB EFI partition.
  • n, select default start sector, then +1G, t, 29, - 1GB Boot partition.
  • n, select default start sector, then default last sector, t, 29, - remaining disk space.

Save your changes. Verify your layout like so:

[anaconda root@localhost ~]# fdisk -l /dev/sda

Disk /dev/sda: 1.82 TiB, 2000398934016 bytes, 3907029168 sectors
Disk model: Samsung SSD 870 
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: gpt
Disk identifier:

Device       Start        End    Sectors  Size Type
/dev/sda1     2048     411647     409600  200M EFI System
/dev/sda2   411648    2508799    2097152    1G Linux RAID
/dev/sda3  2508800 3907029134 3904520335  1.8T Linux RAID

We want to copy our exact partition table to our other drives (they should be identical drives), but with different UUIDs. We'll use sgdisk for this task. Example based on my disk layout.

[anaconda root@localhost ~]# sgdisk -b - /dev/sda | sgdisk -l - -Gg /dev/sdb
[anaconda root@localhost ~]# sgdisk -b - /dev/sda | sgdisk -l - -Gg /dev/sdc

You can use fdisk -l on the other devices to verify they have the same partition layout and different UUIDs.

Step 2: Create mdraid

I'm going to stop for a recommendation here: write down the serial numbers of all your drives and which SATA ports you plugged them into. The following mapping can change, but if you do ls -l /dev/disk/by-id you should see your devices with the serial numbers in their names, symlinked to their devices in /dev/. Decide which two you want in the raid and which one you want as a spare. In my case, we'll be using sda/sdb for the raid and sdc for the spare.

Create the ESP volume with older metadata version. The Arch Wiki advises that metadata version 1.0 is compatible with EFI volumes as the metadata goes to the end of the partition. This is working on my setup.

[anaconda root@localhost ~]# mdadm --create --verbose --level=1 --metadata=1.0 --raid-devices=2 /dev/md/ESP /dev/sda1 /dev/sdb1
[anaconda root@localhost ~]# mdadm --add-spare /dev/md/ESP /dev/sdc1

With the boot and crypt volumes, we can use the default metadata setting.

[anaconda root@localhost ~]# mdadm --create --verbose --level=1 --raid-devices=2 /dev/md/boot /dev/sda2 /dev/sdb2
[anaconda root@localhost ~]# mdadm --add-spare /dev/md/boot /dev/sdc2
[anaconda root@localhost ~]# mdadm --create --verbose --level=1 --raid-devices=2 /dev/md/root /dev/sda3 /dev/sdb3
[anaconda root@localhost ~]# mdadm --add-spare /dev/md/root /dev/sdc3

Run cat /proc/mdstat to verify your raid devices created successfully. The large one is likely still syncing.

Step 3: Encrypt main volume

It's worth checking to see what the best supported encryption methods for your device are, but chances are, it's aes-xts. As well, with the way luks splits keys, if we want AES256 bit encryption, we actually have to specify 512.

See what your hardware supports with cryptsetup benchmark.

The default when running cryptsetup is aes-xts-plain64.

[anaconda root@localhost ~]# cryptsetup -s 512 luksFormat /dev/md/root

This will overwrite data on /dev/md/root irrevocably.

Are you sure? (Type 'yes' in capital letters): YES
Enter passphrase for /dev/md/root: 
Verify passphrase:

Once this is complete, open the device so we can access it at /dev/mapper/rhel-crypt.

[anaconda root@localhost ~]# cryptsetup luksOpen /dev/md/root rhel-crypt
Enter passphrase for /dev/md/root:

Step 4: Configure LVM

My example will be a simple 2 partition scheme creating a swap volume and using the rest of the space for root. You can adjust to your needs.

[anaconda root@localhost ~]# pvcreate /dev/mapper/rhel-crypt
[anaconda root@localhost ~]# vgcreate rhelvg /dev/mapper/rhel-crypt
[anaconda root@localhost ~]# lvcreate -n swap -L 8G rhelvg
[anaconda root@localhost ~]# lvcreate -n root -l100%FREE rhelvg

Step 5: Reboot

In my experience, if we try to continue right now, the installer is just going to fail. It seems to work on the second try after opening all the devices you created. Just type reboot on the command prompt.

Step 6: Activate your devices

Jump into the shell again. Then, in order:

  • Assemble mdraid
  • Unlock luks
  • Activate volume group
[anaconda root@localhost ~]# mdadm --assemble --scan
mdadm: /dev/md/root has been started with 2 drives and 1 spare.
mdadm: /dev/md/boot has been started with 2 drives and 1 spare.
mdadm: /dev/md/ESP has been started with 2 drives and 1 spare.
[anaconda root@localhost ~]# cryptsetup luksOpen /dev/md/root rhel-crypt
Enter passphrase for /dev/md/root: 
[anaconda root@localhost ~]# vgchange -ay
  2 logical volume(s) in volume group "rhelvg" now active

Step 7: Navigate the installer

I'm going to assume you can sort out all other steps needed to install RHEL. When you're ready, select option 5 for Installation Destination.

First, we're going to select all drives.

Then, we're going to choose to manually assign mount points.

Your devices will appear as they were before you opened all of them. Enter s to rescan devices.

It will warn you that it'll undo your changes thus far. We haven't made any anyway, so confirm.

After rescanning, your should see devices that we can actually install to.

Make sure to format the ESP volume as efi. Adjust the others to your preference.

In the end, my setup looked like this:

Step 8: Begin installation

If you've completed all the other steps in the wizard, you should be able to proceed. If everything was done correctly, you'll see the formatting take place before packages begin to install.