Optional Configuration

Skip to bootloader section if no optional configuration is needed.

Boot environment manager

A boot environment is a dataset which contains a bootable instance of an operating system. Within the context of this installation, boot environments can be created on-the-fly to preserve root file system states before pacman transactions.

Install rozb3-pac pacman hook and bieaz from AUR to create boot environments. Prebuilt packages are also available.

Supply password with SSH

  1. Install mkinitcpio tools:

    pacman -S mkinitcpio-netconf mkinitcpio-dropbear openssh
  2. Store public keys in /etc/dropbear/root_key:

    vi /etc/dropbear/root_key
  3. Edit mkinitcpio:

    tee /etc/mkinitcpio.conf <<- 'EOF'
    HOOKS=(base udev autodetect modconf block keyboard netconf dropbear zfsencryptssh zfs filesystems)
  4. Add ip= to kernel command line:

    # example DHCP
    echo 'GRUB_CMDLINE_LINUX="ip=::::::dhcp"' >> /etc/default/grub

    Details for ip= can be found at here.

  5. Generate host keys:

    ssh-keygen -Am pem
    dropbearconvert openssh dropbear /etc/ssh/ssh_host_ed25519_key /etc/dropbear/dropbear_ed25519_host_key

    mkinitcpio-dropbear lacks support for converting ed25519 host key, see this pull request.

Encrypt boot pool

Note: This will disable password with SSH.

  1. LUKS password:


    You will need to enter the same password for each disk at boot. As root pool key is protected by this password, the previous warning about password strength still apply.

    Double-check password here. Complete reinstallation is needed if entered wrong.

  2. Create encryption keys:

    mkdir /etc/cryptkey.d/
    chmod 700 /etc/cryptkey.d/
    dd bs=32 count=1 if=/dev/urandom of=/etc/cryptkey.d/rpool_$INST_UUID-${INST_ID}-key-zfs
    for i in ${DISK[@]}; do
      dd bs=32 count=1 if=/dev/urandom of=/etc/cryptkey.d/${i##*/}-part2-bpool_$INST_UUID-key-luks
  3. Backup boot pool:

    zfs snapshot -r bpool_$INST_UUID/$INST_ID@pre-luks
    zfs send -Rv bpool_$INST_UUID/$INST_ID@pre-luks > /root/bpool_$INST_UUID-${INST_ID}-pre-luks
  4. Unmount EFI partition:

    umount /boot/efi
    for i in ${DISK[@]}; do
     umount /boot/efis/${i##*/}-part1
  5. Destroy boot pool:

    zpool destroy bpool_$INST_UUID
  6. Create LUKS containers:

    for i in ${DISK[@]}; do
     cryptsetup luksFormat -q --type luks1 --key-file /etc/cryptkey.d/${i##*/}-part2-bpool_$INST_UUID-key-luks $i-part2
     echo $LUKS_PWD | cryptsetup luksAddKey --key-file /etc/cryptkey.d/${i##*/}-part2-bpool_$INST_UUID-key-luks $i-part2
     cryptsetup open ${i}-part2 ${i##*/}-part2-luks-bpool_$INST_UUID --key-file /etc/cryptkey.d/${i##*/}-part2-bpool_$INST_UUID-key-luks
     echo ${i##*/}-part2-luks-bpool_$INST_UUID ${i}-part2 /etc/cryptkey.d/${i##*/}-part2-bpool_$INST_UUID-key-luks discard >> /etc/crypttab
  7. Embed key file in initrd:

    echo 'FILES=(/etc/cryptkey.d/* )' >> /etc/mkinitcpio.conf
  8. Recreate boot pool with mappers as vdev:

    zpool create \
    -d -o feature@async_destroy=enabled \
    -o feature@bookmarks=enabled \
    -o feature@embedded_data=enabled \
    -o feature@empty_bpobj=enabled \
    -o feature@enabled_txg=enabled \
    -o feature@extensible_dataset=enabled \
    -o feature@filesystem_limits=enabled \
    -o feature@hole_birth=enabled \
    -o feature@large_blocks=enabled \
    -o feature@lz4_compress=enabled \
    -o feature@spacemap_histogram=enabled \
        -o ashift=12 \
        -o autotrim=on \
        -O acltype=posixacl \
        -O canmount=off \
        -O compression=lz4 \
        -O devices=off \
        -O normalization=formD \
        -O relatime=on \
        -O xattr=sa \
        -O mountpoint=/boot \
        bpool_$INST_UUID \
        $INST_VDEV \
        $(for i in ${DISK[@]}; do
           printf "/dev/mapper/${i##*/}-part2-luks-bpool_$INST_UUID ";
  9. Restore boot pool backup:

    zfs recv bpool_${INST_UUID}/${INST_ID} < /root/bpool_$INST_UUID-${INST_ID}-pre-luks
    rm /root/bpool_$INST_UUID-${INST_ID}-pre-luks
  10. Mount boot dataset and EFI partitions:

    mount /boot
    mount /boot/efi
    for i in ${DISK[@]}; do
     mount /boot/efis/${i##*/}-part1
  11. Change root pool password to key file:

    zfs change-key -l \
    -o keylocation=file:///etc/cryptkey.d/rpool_$INST_UUID-${INST_ID}-key-zfs \
    -o keyformat=raw \
  12. Import encrypted boot pool from /dev/mapper:

    curl -L https://git.io/Jsfwj > /etc/systemd/system/zfs-import-bpool-mapper.service
    systemctl enable zfs-import-bpool-mapper.service
  13. Remove zfsencryptssh hook. Encrypted boot pool is incompatible with password by SSH:

    sed -i 's|zfsencryptssh||g' /etc/mkinitcpio.conf

    If zfsencryptssh is not removed, initrd will stuck at fail to load key material and fail to boot.

  14. As keys are stored in initrd, set secure permissions for /boot:

    chmod 700 /boot
  15. Enable GRUB cryptodisk:

    echo "GRUB_ENABLE_CRYPTODISK=y" >> /etc/default/grub
  16. Important: Back up root dataset key /etc/cryptkey.d/rpool_$INST_UUID-${INST_ID}-key-zfs to a secure location.

    In the possible event of LUKS container corruption, data on root set will only be available with this key.

Persistent swap and hibernation

  1. Optional: enable persistent swap partition. By default encryption key of swap partition is discarded on reboot:

    # fstab
    # remove all existing swap entries
    sed -i '/ none swap defaults 0 0/d' /etc/fstab
    # add single swap entry for LUKS encrypted swap partition
    echo "/dev/mapper/${INST_SWAPMAPPER} none swap defaults 0 0" >> /etc/fstab
    # comment out entry in crypttab
    sed -i "s|^${INST_PRIMARY_DISK##*/}-part4-swap|#${INST_PRIMARY_DISK##*/}-part4-swap|" /etc/crypttab
    # create key and format partition as LUKS container
    dd bs=32 count=1 if=/dev/urandom of=${INST_SWAPKEY};
    cryptsetup luksFormat -q --type luks2 --key-file ${INST_SWAPKEY} ${INST_PRIMARY_DISK}-part4;
    cryptsetup luksOpen ${INST_PRIMARY_DISK}-part4 ${INST_SWAPMAPPER} --key-file ${INST_SWAPKEY}
    # initialize swap space
    mkswap /dev/mapper/${INST_SWAPMAPPER}
  2. Optional: after enabling persistent swap partition, enable hibernation:

    # add hook in initrd
    sed -i 's| zfs | encrypt resume zfs |' /etc/mkinitcpio.conf
    # add kernel cmdline to decrypt swap in initrd
    echo "GRUB_CMDLINE_LINUX=\" \
    zfs_import_dir=${INST_PRIMARY_DISK%/*} \
    cryptdevice=PARTUUID=$(blkid -s PARTUUID -o value ${INST_PRIMARY_DISK}-part4):${INST_SWAPMAPPER}:allow-discards \
    cryptkey=rootfs:${INST_SWAPKEY} \
    resume=/dev/mapper/${INST_SWAPMAPPER}\"" \
    >> /etc/default/grub

    Note that hibernation might not work with discrete graphics or AMD APU integrated graphics. This is not specific to this guide.

    Computer must resume from a continuous swap space, resume from multiple swap partitions is not supported.

    encrypt hook can only decrypt one container at boot. sd-encrypt can decrypt multiple devices but is not compatible with zfs hook.

    Do not touch anything on disk while the computer is in hibernation, see kernel documentation.

Boot Live ISO with GRUB

GRUB can be configured to boot ISO file directly.

In this section, we will download Live ISO to ESP and configure GRUB to boot from it. This enables system recovery and re-installation.

  1. Download Live iso to EFI system partition:

    mkdir /boot/efi/iso
    cd /boot/efi/iso
    # select a mirror # curl -O https://mirrors.ocf.berkeley.edu/archlinux/iso/2021.05.01/archlinux-2021.05.01-x86_64.iso
    curl -O https://archlinux.org/iso/2021.05.01/archlinux-2021.05.01-x86_64.iso.sig
    gpg --auto-key-retrieve --verify archlinux-2021.05.01-x86_64.iso.sig

    Additionally you can build your own live image with archiso package.

    GRUB supports verifying checksum. See manual page for details.

  2. Add custom GRUB entry for /boot/efi/iso/archlinux-*.iso:

    curl -L https://git.io/Jsfr3 > /etc/grub.d/43_archiso
    chmod +x /etc/grub.d/43_archiso

    You can also boot Live ISO for other distros, see glim configurations.

    ISO is not mirrored to other devices due to its size. Change $ESP_MNT to adapt to other ESP.

  3. Generate grub.cfg in the next step. If a new file has been added later, regenerate grub.cfg.