Now is the time to actually install Gentoo. First import the pool again: ``` shell-session sh# zpool import -N -R /mnt rpool sh# zfs load-key -L file:///tmp/rpool.key rpool ``` Then mount the datasets and the ESP on `/mnt`: ``` shell-session sh# mount -t zfs rpool/root/gentoo /mnt sh# mkdir /mnt/var sh# mount -t zfs rpool/root/gentoo/var /mnt/var sh# mkdir /mnt/efi sh# mount -t vfat /dev/disk/by-label/esp /mnt/efi ``` Now we're going to fetch a stage3 tarball for on the root of the system. Replace the `` with the latest tarball release. ``` shell-session sh# cd /mnt sh# wget https://distfiles.gentoo.org/releases/amd64/autobuilds/current-stage3-amd64-musl-hardened/stage3-amd64-musl-hardened-.tar.xz ``` This should have placed a tarball at `/mnt/stage3-amd64-musl-hardened-*-.tar.xz`. There are also other mirrors like `https://ftp.snt.utwente.nl/pub/os/linux/gentoo/releases/amd64/autobuilds/current-stage3-amd64-musl-hardened/` which might provide a faster download depending on your location. Check out for other mirrors. > It is also possible to use `links` instead of `wget` which provides a small user interface for navigation: `# links https://distfiles.gentoo.org/releases/amd64/autobuilds/current-stage3-amd64-musl-hardened` Unpack it in the new root: ``` shell-session sh# tar xpvf stage3-*.tar.xz --numeric-owner -C /mnt ``` Then before finally chrooting into the system simply copy over the `resolv.conf` for internet connection inside the chroot. ``` shell-session sh# cp /etc/resolv.conf /mnt/etc/. sh# cp /tmp/rpool.key /mnt/tmp sh# for i in dev proc sys run; do > mount --rbind --make-rslave /$i /mnt/$i > done sh# chroot /mnt ``` ## Configuring the system ### Portage Before installing any software first edit `/etc/portage/make.conf` which acts as the main configuration file for portage. A Gentoo installation is highly personal so diverting from these settings is encouraged. Here's an example file: ``` title="/etc/portage/make.conf" # Please consult /usr/share/portage/config/make.conf.example for a more # detailed example. COMMON_FLAGS="-march=native -O2 -pipe" CFLAGS="${COMMON_FLAGS}" CXXFLAGS="${COMMON_FLAGS}" FCFLAGS="${COMMON_FLAGS}" FFLAGS="${COMMON_FLAGS}" RUSTFLAGS="${RUSTFLAGS} -C target-cpu=native" # MakeOpts MAKEOPTS="-j7 -l5" # WARNING: Changing your CHOST is not something that should be done lightly. # Please consult https://wiki.gentoo.org/wiki/Changing_the_CHOST_variable before changing. CHOST="x86_64-pc-linux-musl" # NOTE: This stage was built with the bindist USE flag enabled # This sets the language of build output to English. # Please keep this setting intact when reporting bugs. LC_MESSAGES=C.utf8 # Logging PORTAGE_ELOG_CLASSES="log warn error" PORTAGE_LOGDIR="/var/log/portage" PORTAGE_LOGDIR_CLEAN="find \"\${PORTAGE_LOGDIR}\" -type f ! -name \"summary.log*\" -mtime +7 -delete" # Only accept free licenses ACCEPT_LICENSE="-* @FREE" # USE flags USE="${USE} networkmanager -modemmanager wayland dbus elogind -systemd policykit pam apparmor man udev pipewire initramfs secureboot modules-sign dist-kernel" # .... # Emerge settings EMERGE_DEFAULT_OPTS="${EMERGE_DEFAULT_OPTS} --with-bdeps y" # For secureboot (will be necessary later) SECUREBOOT_SIGN_KEY="/var/lib/sbctl/keys/db/db.key" SECUREBOOT_SIGN_CERT="/var/lib/sbctl/keys/db/db.pem" MODULES_SIGN_KEY="${SECUREBOOT_SIGN_KEY}" MODULES_SIGN_CERT="${SECUREBOOT_SIGN_CERT}" MODULES_SIGN_HASH="sha512" ``` > Don't forget to change the `MAKEOPTS` to match your CPU and also the `USEFLAGS` to your liking by i.e. adding `-gtk-doc`. Now finally sync the repositories and try installing a package like `vim`. ``` shell-session sh# emaint sync ... Action: sync for repo: gentoo, returned code = 0 sh# emerge --ask --verbose app-editors/vim >>> Completed (3 of 4) app-editors/vim-*::gentoo ``` Then try running `vim` and it theory it should work! ### Fstab Simply add these lines to the systems `fstab`: ``` shell title="/etc/fstab" rpool/root/gentoo / zfs rw,noatime,xattr,posixacl,casesensitive 0 1 rpool/root/gentoo/var /var zfs rw,noatime,nosuid,nodev,xattr,posixacl,casesensitive 0 2 /dev/disk/by-label/esp /efi vfat defaults,nodev,nosuid,noexec,umask=0077 0 2 tmpfs /tmp tmpfs rw,nodev,nosuid,noexec,mode=1777 0 0 proc /proc proc nodev,nosuid,noexec,hidepid=2 0 0 ``` ### Date and time Musl does not come with timezone's installed by default. Install `timezone-data` with: ``` shell-session sh# emerge -av sys-libs/timezone-data ``` Select the correct timezone with: ``` shell title="/etc/env.d/00local" TZ="/usr/share/zoneinfo//" ``` Update the environment of your shell-session: ``` shell-session sh# env-update && source /etc/profile ``` To sync your system's time with a server set up a *Network Time Protocol daemon*. It's recommended to use OpenBSD's `openntpd` which aims to be as secure and minimal as possible: ``` shell-session sh# emerge -av net-misc/openntpd sh# rc-update add ntpd default sh# rc-service ntpd start ``` ### Set up locales Musl also does not support locales out of the box. They aren't necessary but some programs rely on them to set the language of their application. To be able to use locales install the `musl-locales` package: ``` shell-session sh# emerge -av sys-apps/musl-locales ``` And to allow the system to know where the locales are located: ``` shell title="/etc/env.d/01musl_locales" MUSL_LOCPATH="/usr/share/i18n/locales/musl" ``` There are a multiple locales to choose from. In most situations choosing `en_US` is the standard but selecting a different one should not break the system. Choose the desired locale with $n \in \mathbb{N}$: ``` shell-session sh# env-update && source /etc/profile sh# eselect locale list sh# eselect locale set ``` ### Setting the hostname The system's hostname is the name given to the machine. Other systems on a network will also be able to see this name. To set it replace with the desired name: ``` shell-session sh# echo "" > /etc/hostname ``` ### Internet NetworkManager is an easy to use network manager. It has compatibility with most VPN protocols, works with Eduroam etc. and also has multiple graphical interfaces. On top of this `dnsmasq` can be used for managing DNS queries. Before emerging them, consider adding some USE flags to your liking: ``` title="/etc/portage/package.use/network" net-misc/networkmanager dhcpcd -wext -ppp net-dns/dnsmasq dnssec ``` Also make sure the `networkmanager` USE flag is enabled in your `make.conf`. Then emerge `networkmananger` and `dnsmasq`: ``` shell-session sh# emerge -av net-misc/networkmanager net-dns/dnsmasq ``` Now configure NetworkManager and Dnsmasq. This is a generally secure recommended setup: ``` title="/etc/NetworkManager/NetworkManager.conf" [main] hostname-mode=none plugins=ifupdown,keyfile dns=dnsmasq [ifupdown] managed=true [device] wifi.scan-rand-mac-address=yes [connection-mac-randomization] ethernet.cloned-mac-address=random wifi.cloned-mac-address=random ``` ``` title="/etc/NetworkManager/dnsmasq.d/dnssec" dnssec trust-anchor=.,20326,8,2,E06D44B80B8F1D39A95C0B0D7C65D08458E880409BBC683457104237C7F8EC8D trust-anchor=.,38696,8,2,683D2D0ACB8C9B712A1948B27F741219298D0A450D612C483AF444A4C0FB2B16 dnssec-check-unsigned ``` Then disable any other network services before enabling the `NetworkManager`service: ``` shell-session sh# rc-update add NetworkManager default * service NetworkManager added to runlevel default ``` ### Adding GURU GURU is an extra repository which contains packages not available in the main Gentoo repository. Although the packages it contains might not be as well tested as in the main repo they are still necessary for some setups. Add Guru with: ``` shell-session sh# emerge -av app-eselect/eselect-repository sh# eselect repository enable guru sh# emaint sync --repo guru ``` To allow unstable packages from GURU set the `~amd64` keyword for it: ``` title="/etc/portage/package.accept_keywords/guru" */*::guru ~amd64 ``` ## Making the system boot ### Sbctl `sbctl` is a simple tool which allows for the management of Secureboot settings on a system. It can create, deploy and sign keys with ease. First off install `sbctl`: ``` shell-session sh# emerge -av sbctl ``` > Verify that Secureboot mode is on and in setup mode with `sbctl status` Then create and enroll keys into the system. ``` shell-session sh# sbctl create-keys Created Owner UUID abcde.... Creating secure boot keys...✔ Secure boot keys created! sh# sbctl enroll-keys <--microsoft> ... Enrolled keys to the EFI variables! ``` Use the `--microsoft` flag if the system is unable to use custom keys or when dual booting with Windows. ### Zlevis' auto decryption `zlevis` is able to unlock an encrypted ZFS root pool with keys saved in a TPM, currently it's only available in the `portage-ample` repository and also has some dependencies in the `guru` repository. Add the `portage-ample` repository with: ``` shell-session sh# eselect repository add portage-ample git https://git.bijl.us/lnorg/portage-ample sh# emaint sync -r portage-ample ``` Then before emerging add the `dracut` flag for zlevis: ``` title="/etc/portage/package.use/zlevis" app-crypt/zlevis dracut ``` Then simply install it: ``` shell-session sh# emerge -av app-crypt/zlevis ``` Now add `zlevis` to the pool with ``` shell-session sh# zfs set tpm:jwe=$(zlevis-encrypt '{}' < /tmp/rpool.key) rpool ``` ### UKI's UKI's in conjuction with secureboot make for a pretty secure bootchain. It bundles the command line, initramfs, efi-stub and more in one file which can then easily be signed for Secureboot. We use `dracut` as initramfs generator and `ukify` as UKI generator. Configure the kernelinstall to use `dracut` and `ukify`: ``` title="/usr/lib/kernel/install.conf" layout=uki initrd_generator=dracut uki_generator=ukify ``` ``` title="/etc/kernel/uki.conf" [UKI] SecureBootSigningTool=sbsign ``` Portage also has to be told to generate a UKI when installing a kernel. Set the corresponding required USE flags: ``` title="/etc/portage/package.use/uki" sys-apps/systemd-utils kernel-install boot ukify sys-kernel/installkernel dracut ukify uki ``` These USE flags tell portage also to install `systemd-boot` which can automatically detect UKI's and because of the `secureboot` flag in `/etc/portage/make.conf` it will also automatically sign the bootloader when it gets installed or updated on the ESP. For a desktop to function it will also require firmware. On Linux this is usually the `linux-firmware` package. Allow the licenses required for `linux-firmware`: ``` title="/etc/portage/package.license" # Accepting the license for linux-firmware and redistributable licenses sys-kernel/linux-firmware linux-fw-redistributable @BINARY-REDISTRIBUTABLE ``` Then to allow `zlevis` to unlock the root pool it will need to be added to the initramfs. Enable the `zlevis` module for dracut: ``` shell title="/etc/dracut.conf.d/zlevis.conf" nofsck="yes" add_dracutmodules+=" zlevis " ``` Before installing a kernel define a minimal kernel command line which allows the initramfs to find the root: ``` title="/etc/kernel/cmdline" rw root=ZFS=rpool/root/gentoo quiet splash ``` Then finally install the packages mentioned which are required for a running system: ``` shell-session sh# emerge -av sbsigntools systemd-utils linux-firmware gentoo-kernel-bin zfs-kmod ``` > Note that `gentoo-kernel-bin` was installed which is the pre-compiled Gentoo kernel. Later on we will compile our own custom kernel. It should have done this without throwing any errors. Because Gentoo generates UKI's for all the kernels installed on a system it would be nice to be able to choose upon boot which one. For a nice boot interface install `systemd-boot` on the ESP: ``` shell-session sh# bootctl install Copied "/usr/lib/systemd/boot/efi/systemd-bootx64.efi.signed" to "/efi/EFI/systemd/systemd-bootx64.efi". Copied "/usr/lib/systemd/boot/efi/systemd-bootx64.efi.signed" to "/efi/EFI/BOOT/BOOTX64.EFI". Random seed file /efi/loader/random-seed successfully refreshed (32 bytes). Created EFI boot entry "Linux Boot Manager". ``` The last thing to do is adding a few ZFS services on boot: ``` shell-session sh# rc-update add zfs-import sysinit sh# rc-update add zfs-mount sysinit ``` Now exit the chroot and unmount the filesystem with: ``` shell-session sh# umount -lf /mnt ``` The system should be functional after a reboot!