How To Install Gentoo With LVM and Disk Encryption

16 Jan 2019

Hey there. Lately, I switched my laptops and servers from a pair of Debian/OpenBSD to Gentoo. I did it because I wanted to know and master only one OS everywhere, but none of them were completely suitable for that: OpenBSD doesn't work well on laptops and lacks some things that are important for me 1, while Debian uses systemd init system which I find unnecessarily complex and almost impossible to master. 2

As for Gentoo, it is a Linux-based OS which comes with a relatively lightweight OpenRC init system; it allows you to build and use secure alternatives from the OpenBSD world (libressl, OpenNTPD, etc.) as well. The biggest downside could be the time spent on building everything from source code, but nowadays it's not that bad. Another problem is to find a hosting provider which supports Gentoo; luckily the one I use (Vultr) does it.

This article is a quick installation checklist for experienced users. It will help you with Gentoo installation on LVM-managed disk with encryption. I'd like to stress out that it's not a full-disk encryption because it doesn't encrypt /boot partition. It won't be suitable, for example, in the case when someone would like to implant malicious software into the kernel and spy on you. As for me, I'd like to prevent bad people from accessing my personal information when my laptop is lost or stolen, so it's enough to only encrypt the data partitions.

Booting Up

I believe that you already know how to dump Gentoo ISO onto USB drive and boot from it; you can read about it in Gentoo Handbook if not.

The first thing after you boot up is to check that your network connection is working. You can do it by inspecting network interfaces via ifconfig. Run net-setup <interface> to set up a network interface if it wasn't done automatically.

Create Partitions

It is assumed throughout the guide that you're installing Gentoo on /dev/sda disk. If it's not correct, check available devices with lsblk command and replace /dev/sda appearances with a correct device.

Partition Schema (UEFI systems)

PartitionFilesystemSizeDescription
/dev/sda1FAT32256MBUEFI ESP
/dev/sda2ext4256MB (at least)/boot
/dev/sda3Crypto+LVMRest of the diskLVM Volumes

Partition Schema (BIOS systems)

PartitionFilesystemSizeDescription
dev/sda1(none)2MBBIOS Boot
/dev/sda2ext4256MB (at least)/boot
/dev/sda3Crypto+LVMRest of the diskLVM Volumes

Run parted on a selected device with optimal alignment for partitions:

# parted -a optimal /dev/sda

Then execute the following parted commands depending on the type of a system you're on.

For UEFI systems:

# Make new GPT partition table
mklabel gpt

# Create an UEFI ESP
mkpart primary 1MiB 257MiB
name 1 efi
set 1 esp on

# Create a boot partition
mkpart primary 257MiB 513MiB
name 2 boot
set 2 boot on

# Create a LVM partition
mkpart primary 513MiB 100%
name 3 data-encrypted
set 3 lvm on

# Check that everything is correct and quit
print
quit

For BIOS systems:

# Make new GPT partition table
mklabel gpt

# Create a BIOS Boot partition
mkpart primary 1MiB 3MiB
name 1 biosboot
set 1 bios_grub on

# Create a boot partition
mkpart primary 3MiB 259MiB
name 2 boot
set 2 boot on

# Create a LVM partition
mkpart primary 259MiB 100%
name 3 data-encrypted
set 3 lvm on

# Check that everything is correct and quit
print
quit

Encrypt Data Partition

Create encrypted partition

# cryptsetup -s 512 --use-random luksFormat /dev/sda3

Make encrypted partition available

# cryptsetup luksOpen /dev/sda3 data-decrypted

After that, the decrypted partition should be available via /dev/mapper/data-decrypted.

Create LVM Partitions

Create physical volume

# pvcreate /dev/mapper/data-decrypted

Create volume group

# vgcreate datavg /dev/mapper/data-decrypted

Optionally you can also create a swap volume. The recommendation is to create a swap volume of a size twice the size of the available RAM.

# lvcreate -L 1GiB -n swap datavg

Finally, create the root volume

# lvcreate -l 100%VG -n root datavg

After that, the root volume should be available via /dev/mapper/datavg-root.

Create Filesystems And Mount

Format ESP partition (UEFI systems only)

# mkfs.fat -F 32 /dev/sda1

Format /boot partition

# mkfs.ext4 -L boot /dev/sda2

Format and mount / partition

# mkfs.btrfs -L root /dev/mapper/datavg-root
# mount /dev/mapper/datavg-root /mnt/gentoo

Format and mount swap partition if you've created it earlier

# mkswap /dev/mapper/datavg-swap
# swapon /dev/mapper/datavg-swap

Change directory to a place where the root partition is mounted

# cd /mnt/gentoo

Install The Base System

Now we need to download precompiled base system (so-called "Stage 3" tarball), extract it and configure Portage so that we could compile the kernel and other programs.

Get And Unpack Stage3

First of all, set the correct date and time so that you won't have any issues with newly created files later.

# ntpd -qg

It is almost always better to install the latest base system. To find out the filename of its tarball, we can request a list of files from the Gentoo FTP server. Here is a command to query files for the Hardened Gentoo for amd64 architecture

# curl --list-only ftp://gentoo.osuosl.org/pub/gentoo/releases/amd64/autobuilds/current-stage3-amd64-hardened/

You need a file with a name like stage3-*.tar.xz. Once you found it, download and unpack it into /mnt/gentoo

# wget ftp://gentoo.osuosl.org/pub/gentoo/releases/amd64/autobuilds/current-stage3-amd64-hardened/stage3-amd64-hardened-20190113T214502Z.tar.xz
# tar xpvf stage3*.tar.xz --xattrs-include='*.*' --numeric-owner

Next step is to select a Portage mirror to download ebulds from. Below is the command to do it. 3

# mirrorselect -i -o >> /mnt/gentoo/etc/portage/make.conf

Chroot Into The System

Copy DNS information to the chroot

# cp -L /etc/resolv.conf /mnt/gentoo/etc/

Mount necessary filesystems

# mount --types proc  /proc   /mnt/gentoo/proc
# mount --rbind       /sys    /mnt/gentoo/sys
# mount --make-rslave         /mnt/gentoo/sys
# mount --rbind       /dev    /mnt/gentoo/dev
# mount --make-rslave         /mnt/gentoo/dev

Chroot to the new system

# chroot /mnt/gentoo /bin/bash
(chroot) # source /etc/profile
(chroot) # export PS1="(chroot) $PS1"

Mount boot partition

(chroot) # mkdir /boot
(chroot) # mount /dev/sda2 /boot

Mount ESP partition (UEFI systems only)

(chroot) # mkdir -p /boot/efi
(chroot) # mount /dev/sda1 /boot/efi

Configure Portage And Update The World

Download latest ebuilds

(chroot) # emerge-webrsync
(chroot) # emerge --sync

Choose the right profile

(chroot) # eselect profile list
(chroot) # eselect profile set <prof-num>

Now it's time to configure Make, CC and USE flags.4 They highly depend on what kind of system you're building and the hardware you're running on. My usual choice is

COMMON_FLAGS

  • -O2 to enable reasonably safe compiler optimizations

  • -march=native -mtune=native to allow GCC to generate the code specific to the architecture of your CPU

  • -pipe to use piped IO instead of temporary files for communication between various stages of compilation

MAKEOPTS

  • -jN where N is the number of cores/CPUs you have in the system. It enables parallel execution of make targets.

USE for all systems

  • bash-completion to install completers for Bash if available

  • hardened to activate security enhancements for compiler toolchain

  • -jit to disable JIT compilation which may not play well with Hardened Gentoo

  • libressl to use LibreSSL library instead of OpenSSL 5

  • vim-syntax to install vim syntax files if available

  • xattr to add support for extended filesystem attributes

USE for desktop systems

  • alsa to enable ALSA sound system support

  • dbus to enable DBUS messaging system support

  • -gnome -gnome-keyring to disable GNOME support

  • -kde to disable KDE support

  • -pulseaudio to disable Pulseaudio support

  • xft to enable the X FreeType interface library

  • X to enable X11 support 6

Finally edit Portage configuration

(chroot) # $EDITOR /etc/portage/make.conf

Update the @world 7

(chroot) # emerge -avuDN @world

Configure The System

Set the timezone (see /usr/share/zoneinfo for available timezones)

(chroot) # echo "Europe/Berlin" > /etc/timezone
(chroot) # emerge --config sys-libs/timezone-data

Generate locales to use in the system

(chroot) # $EDITOR /etc/locale.gen
(chroot) # locale-gen
(chroot) # locale -a

Set system-wide locale settings and reload the environment

(chroot) # eselect locale list
(chroot) # eselect locale set <locale-num>
(chroot) # env-update
(chroot) # source /etc/profile
(chroot) # export PS1="(chroot) $PS1"

Set the hostname

(chroot) # $EDITOR /etc/conf.d/hostname
(chroot) # $EDITOR /etc/hosts

Set root password

(chroot) # passwd

Add a regular user if necessary

(chroot) # useradd -g users -G <group1>,<group2> -m <username>

Change keyboard settings if necessary. If you switch Ctrl and CapsLock as I do, set EXTENDED_KEYMAPS="ctrl".

(chroot) # $EDITOR /etc/conf.d/keymaps

Change hardware clock settings if necessary

(chroot) # $EDITOR /etc/conf.d/hwclock

Edit /etc/fstab to set up system mount points. There are a couple of things to consider:

  • The preferred format is UUID=<partition-uuid> <mount-point> <fs-type> <opts> <dump> <pass>. UUIDs are more reliable that labels or paths. To get partitions UUID, use blkid tool.

  • <dump> should be 0 most of the time. AFAIK it is a legacy flag for legacy filesystems.

  • <pass> is the order of fsck check at a start time; it should be 0 on BTRFS filesystems because fsck should be run on them rarely since they are self-healing. As for other filesystems, the rule is that the root partition should have 1, while all other partitions should have higher numbers.

  • <opts> are the options to pass to mount; I'd recommend using noatime,nodiratime pair unless you need to keep track of file access times; it will speed things up a bit.

(chroot) # $EDITOR /etc/fstab

Install Necessary Programs

gentoolkit contains a bunch of handy utilities that allow you to query and change the Portage system

(chroot) # emerge -av app-portage/gentoolkit

doas is a lightweight replacement for sudo

(chroot) # emerge -av app-admin/doas

Install system logger

(chroot) # emerge -av app-admin/metalog
(chroot) # rc-update add metalog default

Install cron daemon

(chroot) # emerge -av sys-process/cronie
(chroot) # rc-update add cronie default

Install DHCP client

(chroot) # emerge -av net-misc/dhcpcd

If you're on a system that frequently changes its network settings (e.g. a laptop connection over a wireless network), I'd suggest using a connection manager. I prefer connman

(chroot) # emerge -av net-misc/connman
(chroot) # rc-update add connman default

If you're on a system that has fixed network connection (e.g. desktop or server), then you can simply use netifrc

(chroot) # emerge -av net-misc/netifrc

If you'd like to set up eth0 interface using DHCP at start-up

(chroot) # echo 'config_eth0="dhcp"' >> /etc/conf.d/net
(chroot) # ln -s /etc/init.d/net.lo /etc/init.d/net.eth0
(chroot) # rc-update add net.eth0 default

Install any other utilities you'd like

(chroot) # emerge -av vim tmux mc ...

Configure The Kernel

Install kernel sources and firmware

(chroot) # emerge -av sys-kernel/gentoo-sources sys-kernel/linux-firmware

Install genkernel tool to build kernel, modules and initrd image

(chroot) # euse -p sys-apps/util-linux -E static-libs
(chroot) # euse -p sys-kernel/genkernel -E cryptsetup
(chroot) # emerge -av sys-kernel/genkernel

Install btrfs-progs for BTRFS support and dosfstools for FAT support

(chroot) # emerge -av sys-fs/btrfs-progs sys-fs/dosfstools

Configure genkernel

(chroot) # $EDITOR /etc/genkernel.conf
  • Set MENUCONFIG to use graphical kernel configuration tool

  • Set LVM, LUKS and BTRFS to enable their support in initrd

  • Set FIRMWARE to copy the firmware into initrd and load it early

  • If genkernel all on the next step fails to compress initrd image with XZ, switch to another algorithm by changing COMPRESS_INITRD_TYPE option.

Configure the kernel

(chroot) # genkernel all

Enable the following options so that you'll be able to start the system from the encrypted partition later

- Device drivers
  -> Multiple devices driver support (RAID and LVM)
    -> [*] Device mapper support
    -> [*] Crypt target support
- Cyptographic API
  -> [*] XTS Support
  -> [*] SHA224 and SHA256 digest algorithm
  -> [*] AES cipher algorithms (x86_64)
  -> [*] User-space interface for hash algorithms
  -> [*] User-space interface for symmetric key cipher algorithms

Check that the kernel is installed. The output should contain kernel-* and initramfs-* files

(chroot) # ls /boot/

Configure Bootloader

Select GRUB platform if necessary. Use "efi-64" for UEFI and "pc" for BIOS systems

(chroot) # echo 'GRUB_PLATFORMS="efi-64"' >> /etc/portage/make.conf

If you have other OSes, install os-prober to detect them and generate GRUB entries

(chroot) # euse -p sys-boot/grub -E mount
(chroot) # emerge -av sys-boot/os-prober

Alternatively, you can install only GRUB itself

(chroot) # emerge -av sys-boot/grub

Install GRUB (UEFI)

(chroot) # mount -o remount,rw /sys/firmware/efi/efivars
(chroot) # grub-install --target=x86_64-efi --efi-directory=/boot/efi

Install GRUB (BIOS)

(chroot) # grub-install /dev/sda

Configure GRUB.

(chroot) # $EDITOR /etc/default/grub

Insert dolvm crypt_root=UUID=<crypt-partition-uuid> in GRUB_CMDLINE_LINUX_DEFAULT to inform GRUB that you're starting system from an encrypted partition

Compile GRUB configuration

(chroot) # grub-mkconfig -o /boot/grub/grub.cfg

Reboot

Exit the chroot

(chroot) # exit
# cd

Unmount filesystems

# umount -l /mnt/gentoo/dev{/shm,/pts,}
# umount -R /mnt/gentoo

Reboot

# reboot

Welcome to your new Gentoo!


  1. Bluetooth subsystem is one example

  2. I honestly tried to learn it, and I would probably agree to live with it on a desktop machine where I don't care much about services, but I can't use it for a server where it's crucial. Most of the features implemented in systemd have no use for me there; they only increase the attack surface.

  3. To restrict a list of mirrors to a specific country use -c flag, e.g. mirrorselect -c Germany ...

  4. Additional information about available USE variables you can find in /usr/portage/profiles/use.desc

  5. If you enabled libressl USE flag, you'd also need to set CURL_SSL="libressl" in make.conf in order to avoid conflicts later because curl uses OpenSSL backend by default

  6. It would be also handy to set VIDEO_CARDS and/or INPUT_DEVICES variables in order to decrease the number of packages merged when you install the X11 server

  7. -avuDN flags in the line above correspond to --ask, --verbose, --update, --deep and --newuse