#!/usr/bin/env bash # install arch linux on zfs root, stage one # Craig Jennings # # https://openzfs.github.io/openzfs-docs/Getting%20Started/Arch%20Linux/Root%20on%20ZFS.html # set -e # halt on any error # -------------------------- Prerequisites -------------------------- sed -i "s/^#ParallelDownloads = 5$/ParallelDownloads = 15/" /etc/pacman.conf # These are now done in stage 0 # pacman-key --init # pacman-key --refresh-keys # pacman --noconfirm -Sy archlinux-keyring loadkeys us timedatectl set-ntp true ### --------------------------- Choose Disk --------------------------- all_disk_ids=( $(ls /dev/disk/by-id/) ) echo ""; echo "Select the disk id to use. All data will be erased." select disk_id in "${all_disk_ids[@]}"; do # ensure valid selection if [[ -n $disk_id ]]; then selection=$disk_id break else echo "Invalid. Try again." fi done # Confirm the selected disk read -p "Confirm: '$selection' [y/n]? " choice if [[ "$choice" != "y" ]]; then echo "Exiting..." exit 1 fi DISK="/dev/disk/by-id/$selection" MNT=/mnt # Set a mount point SWAPSIZE=4 # Set swap size in GB RESERVE=1 # Set how much space to leave at the end of disk, minimum 1GB ### --------------------------- Erase Disk ------------------------- echo ""; echo "### Erasing Disk" blkdiscard -f "${DISK}" || true # discard all sectors on flash-based storage sgdisk --zap-all "${DISK}" # clear the disk ### ------------------------- Partition Disk ------------------------ echo ""; echo "### Partitioning Disk" parted --script --align=optimal "${DISK}" -- \ mklabel gpt \ mkpart EFI 2MiB 1GiB \ mkpart bpool 1GiB 5GiB \ mkpart rpool 5GiB -$((SWAPSIZE + RESERVE))GiB \ mkpart swap -$((SWAPSIZE + RESERVE))GiB -"${RESERVE}"GiB \ mkpart BIOS 1MiB 2MiB \ set 1 esp on \ set 5 bios_grub on \ set 5 legacy_boot on ### ---------------------- Setup Encrypted Swap --------------------- echo ""; echo "### Encrypted Swap" for i in ${DISK}; do cryptsetup open --type plain --key-file /dev/random "${i}"-part4 "${i##*/}"-part4 mkswap /dev/mapper/"${i##*/}"-part4 swapon /dev/mapper/"${i##*/}"-part4 done # ------------------- Create Boot And Root Pools ------------------ # This step creates a separate boot pool for /boot with the features limited to # only those that GRUB supports, allowing the root pool to use any/all features. echo ""; echo "### Checking ZFS Module" modprobe zfs # ensure zfs module is loaded echo ""; echo "### Creating Boot Pool" # shellcheck disable=SC2046 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 \ -R "${MNT}" \ bpool \ $(for i in ${DISK}; do printf '%s ' "${i}-part2"; done) echo ""; echo "### Creating Root Pool" # shellcheck disable=SC2046 zpool create \ -o ashift=12 \ -o autotrim=on \ -R "${MNT}" \ -O acltype=posixacl \ -O canmount=off \ -O compression=zstd \ -O dnodesize=auto \ -O normalization=formD \ -O relatime=on \ -O xattr=sa \ -O mountpoint=/ \ rpool \ $(for i in ${DISK}; do printf '%s ' "${i}-part3"; done) echo ""; echo "### Creating Unencrypted Root System Container" # create UNENCRYPTED root system container zfs create \ -o canmount=off \ -o mountpoint=none \ rpool/archlinux # --------------------- Create System Datasets -------------------- echo ""; echo "### Creating System Datasets" zfs create -o canmount=noauto -o mountpoint=/ rpool/archlinux/root zfs mount rpool/archlinux/root zfs create -o mountpoint=legacy rpool/archlinux/home mkdir "${MNT}"/home mount -t zfs rpool/archlinux/home "${MNT}"/home zfs create -o mountpoint=legacy rpool/archlinux/var zfs create -o mountpoint=legacy rpool/archlinux/var/lib zfs create -o mountpoint=legacy rpool/archlinux/var/log zfs create -o mountpoint=none bpool/archlinux zfs create -o mountpoint=legacy bpool/archlinux/root mkdir "${MNT}"/boot mount -t zfs bpool/archlinux/root "${MNT}"/boot mkdir -p "${MNT}"/var/log mkdir -p "${MNT}"/var/lib mount -t zfs rpool/archlinux/var/lib "${MNT}"/var/lib mount -t zfs rpool/archlinux/var/log "${MNT}"/var/log # ---------------------- Format And Mount ESP --------------------- echo ""; echo "### Format And Mount ESP" for i in ${DISK}; do mkfs.vfat -n EFI "${i}"-part1 mkdir -p "${MNT}"/boot/efis/"${i##*/}"-part1 mount -t vfat -o iocharset=iso8859-1 "${i}"-part1 "${MNT}"/boot/efis/"${i##*/}"-part1 done mkdir -p "${MNT}"/boot/efi mount -t vfat -o iocharset=iso8859-1 "$(echo "${DISK}" | sed "s|^ *||" | cut -f1 -d' '|| true)"-part1 "${MNT}"/boot/efi ### -------------------------- Install Base ------------------------- echo ""; echo "### Installing Base" # install packages with pacstrap pacstrap "${MNT}" \ base \ base-devel \ dkms \ efibootmgr \ git \ grub \ intel-ucode \ linux-firmware \ linux-lts \ linux-lts-headers \ man-db \ man-pages \ vi # create fstab and remove all zroot entries genfstab -U -p "${MNT}" >> "${MNT}"/etc/fstab sed -i '/^# zroot/d' "${MNT}"/etc/fstab sed -i '/^zroot/d' "${MNT}"/etc/fstab sed -i '/^$/d' "${MNT}"/etc/fstab echo "" >> "${MNT}"/etc/fstab # one blank line at the end # copy over dns settings to the new system cp -v /etc/resolv.conf "${MNT}"/etc # copy stage2 script to the new system cp ./stage2.sh "${MNT}"/root # ----------------------------- Chroot ---------------------------- echo ""; echo "Done with Stage One" chroot "${MNT}" /usr/bin/env DISK="${DISK}" /root/stage2.sh # -------------------------- After Chroot ------------------------- umount -Rl "${MNT}" zfs snapshot -r rpool@initial-installation zfs snapshot -r bpool@initial-installation zpool export -a echo ""; echo "Done with Stage Two"