I had my once a year conundrum recently – install Gentoo or Ubuntu. This year I chose Gentoo and was immediately awash with nostalgia from seeing this screen.
The last time I ran Gentoo seriously was back in 2008 and now to see this in all its glory really brings me back.
In memory of those good times, I wanted to document the installation process on a modern 2020 PC. Overall, I would say not much has changed except the availability of systemd as a init option.
Initial setup
I began by downloading the Gentoo minimal install CD. For AMD64 it’s available here. As with all Gentoo installations it’s wise to have the handbook nearby for support. It’s available here for AMD64 here.
I burned the CD image to a USB stick using Etcher by Balena. It’s not my favourite tool but it’s reliably despite the ads. dd is also another alternative.
Next, I rebooted in the the USB stick via the UEFI boot menu and chose the default Grub menu. If you have a wired network configured then in most cases the network will already be working and configured with DHCP.
Configuring disks
The hardest part about configuring a fresh installation of Linux is deciding on the storing configuration. The usual deciding factors are tolerance for risk and available storage devices. In my case, I have a SSD solely dedicated to Linux and a pair of HDDs for longer term storage.
livecd ~ # lsblk NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT loop0 7:0 0 390.1M 1 loop /mnt/livecd sda 8:0 0 1.8T 0 disk └─md156 9:126 0 3.8T 0 raid0 ├─md156p1 259:0 0 128M 0 part └─md156p2 259:1 0 3.8T 0 part sdb 8:16 0 1.8T 0 disk └─md156 9:126 0 3.8T 0 raid0 ├─md156p1 259:0 0 128M 0 part └─md156p2 259:1 0 3.8T 0 part sdc 8:32 0 460.8G 0 disk ├─sdc1 8:33 0 512M 0 part ├─sdc2 8:34 0 244M 0 part └─sdc3 8:35 0 460G 0 part sde 8:64 1 14.6G 0 disk ├─sde1 8:65 1 427M 0 part /mnt/cdrom └─sde2 8:66 1 6.4M 0 part sr0 11:0 1 1024M 0 rom
Here you can see I have two 2TB drives already in RAID from an existing Linux installation, the USB stick mounted at /mnt/cdrom and the rootfs for the livecd mounted at /mnt/livecd.
For the filesystem, I usually select btrfs for the SSD and btrfs in RAID1 for the HDDs. This gives me the best balance of recoverability, reliability, and performance for my usecases. However, because I’m curious to try some of the latest technology this time round I’m going btrfs across all my drives.
Here’s the storage configuration:
- SSD: btrfs on LUKS with GPT
- EFI partition, 512M
- boot partition, 512M
- swap partition, 32G
- root partition, remaining space
- HDD: btrfs on LUKS (hdd1 & hdd2) with GPT
- EFI partition, 512M, empty
- root partition, remaining disk
Configuring the SSD
First before partitioning I usually erase the SSD. I have more than normal faith in the ATA secure erase or NVMe secure erase and commonly use it before partitioning drives. hdparm -I /dev/<drive> quickly tells me what my options are. In case I’m told my drive is frozen, a quick hotplug (while the computer is on) will unfreeze the device so you can send the secure erase command. I also had to make sure that the BIOS had the drives connected using AHCI.
Next I set up the partition table. MBR with DOS disklabel is deprecated (and has been for a while) so I’ll use GPT. I want the disk to be bootable in any case so I usually use a /boot partition that’s unencrypted, along with EFI and rootfs partitions. This setup can be changed later to a completely encrypted drive with boot USB.
After the partition table was created, it looked something like this:
livecd ~ # fdisk -l /dev/sdc Disk /dev/sdc: WW GiB, XX bytes, YY sectors Disk model: WDC WXXXXXXXXX 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: ZZ-ZZ-ZZ-ZZ-ZZ Device Start End Sectors Size Type /dev/sdc1 2048 1050623 1048576 512M EFI System /dev/sdc2 1050624 1550335 499712 244M Linux filesystem /dev/sdc3 X Y Z 450G Linux filesystem /dev/sdb4 X Y Z 32G Swap
mkfs.fat -F32 /dev/sdc1 (for the EFI system partition)
mkfs.ext2 /dev/scdc2 (for the boot partition)
Next I’ll turn the last partition into a LUKS container by using the cryptsetup command. Read more about LUKS here.
First the performance of the disk is evaluated by using cryptsetup benchmark. From the results and my risk profile, I can choose the configuration that makes the most sense for you.
cryptsetup --key-size 512 --hash whirlpool --iter-time 5000 --use-random --cipher aes-xts-plain64 --pbkdf-memory=4194304 --pbkdf=argon2id luksFormat /dev/sdc3 cryptsetup luksOpen /dev/sdc3 xtsroot
Next, I’ll set up btrfs on the encrypted root filesystem.
mkfs.btrfs -L broot /dev/mapper/xtsroot
I created a btrfs block device with label broot. Next, I mounted it with light compression turned on along with disk quotas. I made sure to have the rootfs and storage directories beneath the toplevel directory for ease of snapshots.
mkdir /toplevel mount -o compress=lzo /dev/mapper/xtsroot /toplevel # btrfs quota enable /toplevel # we will not be enabling this yet. btrfs subvolume create /toplevel/rootfs btrfs subvolume create /toplevel/rootfs/gentoo btrfs subvolume create /toplevel/savestate btrfs subvolume create /toplevel/storage btrfs subvolume create /toplevel/storage/home btrfs subvolume create /toplevel/storage/home/user mount -o subvol=/rootfs/gentoo,compress=lzo /dev/mapper/xtsroot /mnt/gentoo
Finally, I turned on swap from the filesystem I made earlier.
mkswap /dev/sdc4 swapon /dev/sdc4
Installing Gentoo
Before continuing I made sure the date is correct – date
. In most cases, it will already be set correctly. Next, I downloaded the multilib tarball from the Gentoo’s website.
wget https://bouncer.gentoo.org/fetch/root/all/releases/amd64/autobuilds/20200920T214503Z/stage3-amd64-systemd-20200920T214503Z.tar.xz \ wget https://bouncer.gentoo.org/fetch/root/all/releases/amd64/autobuilds/current-stage3-amd64/stage3-amd64-20200923T214503Z.tar.xz.CONTENTS.gz \ wget https://bouncer.gentoo.org/fetch/root/all/releases/amd64/autobuilds/current-stage3-amd64/stage3-amd64-20200923T214503Z.tar.xz.DIGESTS \ wget https://bouncer.gentoo.org/fetch/root/all/releases/amd64/autobuilds/current-stage3-amd64/stage3-amd64-20200923T214503Z.tar.xz.DIGESTS.asc tar xpvf stage3-amd64-systemd-20200920T214503Z.tar.xz --xattrs-include='*.*' --numeric-owner nano -w /mnt/gentoo/etc/portage/make.conf
For my compilation options, I chose the following: MAKEOPTS=”-j2″; EMERGE_DEFAULT_OPTS=”–jobs=3″; and COMMON_FLAGS=”-Ofast -flto -pipe -march=native -funroll-loops”.
Next, I continued following the guide by selecting mirrors and the ebuild repository. Finally, I chrooted into the new directory as per the Gentoo handbook.
For my profile, I opted to use default/linux/amd64/17.1/systemd. Next I set my default Python interpreter to python 3.7 by adding the lines below to /etc/portage/package.use
*/* PYTHON_TARGETS: python3_7 */* PYTHON_SINGLE_TARGET: -* python3_7
# For systemd, I added some specific use flags +cryptsetup +homed +pkcs11 +policykit and for python I added sqlite as a dependency.
After this I issued “emerge –ask –verbose –update –deep –newuse @world“. I commonly check the default USE flags for the profile before going further – it’s stored in /var/db/repos/gentoo/profiles/* and more information here.
Furthermore, when I need to check the current Portage configuration it’s just a “emerge –info“ away. The Gentoo wiki page also serves as a helpful reference.
For the kernel, I followed the handbook and made sure I had the following functionality:
- CONFIG_X86_CHECK_BIOS_CORRUPTION=y
- CONFIG_WATCHDOG=y
I also added the following to my bootflags kernel command line:
- resume=/dev/root
Next, for the initramfs I opted to use genkernel and I used the following configuration.
genkernel --lvm --mdadm --bcache --btrfs --e2fsprogs --dmraid --bootloader=grub2 --luks --busybox --install --kernel-config=/usr/src/linux/.config initramfs
For configuring systemd and grub2 you’ll need to add the following to /etc/default/grub
GRUB_CMDLINE_LINUX="init=/lib/systemd/systemd crypt_root=<device> dobtrfs"
Remember to specify the UUID of the real_root in GRUB_DEVICE and to uncomment GRUB_TERMINAL=console if you want to see errors during bootup.
I usually compile two kernels – one custom configured by me and the other by genkernel in case I get stuck. Also in the modern day and age, there’s no region to configure any framebuffers, so at best I only set the EFI framebuffer and simple framebuffer kernel option.
genkernel --kernel-append-localversion=-custom all grub-mkconfig -o /boot/grub/grub.cfg
Once finished, I rebooted, selected the new entry in Grub, entered my password for my encrypted root drive, and immediately started emerging Firefox.
Welcome home!