196 lines
5.8 KiB
Bash
196 lines
5.8 KiB
Bash
|
#!/usr/bin/env bash
|
||
|
#
|
||
|
# Bootstrap a new Arch system from an installation ISO.
|
||
|
#
|
||
|
# Bootable USB:
|
||
|
# - [Download](https://archlinux.org/download/) ISO and GPG files
|
||
|
# - Verify the ISO file: `$ pacman-key -v archlinux-<version>-x86_64.iso.sig`
|
||
|
# - Create a bootable USB with: `# dd if=archlinux*.iso of=/dev/sdX && sync`
|
||
|
#
|
||
|
# UEFI setup:
|
||
|
#
|
||
|
# - Set boot mode to UEFI, disable Legacy mode entirely.
|
||
|
# - Temporarily disable Secure Boot.
|
||
|
# - Make sure a strong UEFI administrator password is set.
|
||
|
# - Delete preloaded OEM keys for Secure Boot, allow custom ones.
|
||
|
#
|
||
|
# Run installation:
|
||
|
#
|
||
|
# - Connect to wifi via: `# iwctl station wlan0 connect $SSID`
|
||
|
# - Run: `# bash <(curl -sL https://link.rafe.li/dot)`
|
||
|
#
|
||
|
|
||
|
set -uo pipefail
|
||
|
trap 's=$?; echo "$0: Error on line "$LINENO": $BASH_COMMAND"; exit $s' ERR
|
||
|
|
||
|
args=()
|
||
|
target_device=""
|
||
|
new_hostname=""
|
||
|
|
||
|
while [[ $# -gt 0 ]]
|
||
|
do
|
||
|
arg="$1"
|
||
|
|
||
|
case "$arg" in
|
||
|
"--device")
|
||
|
target_device="$2"
|
||
|
shift
|
||
|
shift
|
||
|
;;
|
||
|
"--hostname")
|
||
|
new_hostname="$2"
|
||
|
shift
|
||
|
shift
|
||
|
;;
|
||
|
*)
|
||
|
args+=("$arg")
|
||
|
shift;
|
||
|
esac
|
||
|
done
|
||
|
|
||
|
if [[ -z "$target_device" ]]; then
|
||
|
echo "Missing --device <device> argument" >&2
|
||
|
exit 2;
|
||
|
fi
|
||
|
|
||
|
if [[ -z "$new_hostname" ]]; then
|
||
|
echo "Missing --hostname <hostname> argument" >&2
|
||
|
exit 2;
|
||
|
fi
|
||
|
|
||
|
if [[ "${#args[@]}" -ne 0 ]]; then
|
||
|
echo "Unexpected extra arguments: ${args[*]}" >&2
|
||
|
exit 2
|
||
|
fi
|
||
|
|
||
|
if [ ! -f /sys/firmware/efi/fw_platform_size ]; then
|
||
|
echo >&2 "You must boot in UEFI mode to continue"
|
||
|
exit 2
|
||
|
fi
|
||
|
|
||
|
if [[ "$UID" -ne 0 ]]; then
|
||
|
echo "This script needs to be run as root!" >&2
|
||
|
exit 3
|
||
|
fi
|
||
|
|
||
|
read -rp "THIS SCRIPT WILL OVERWRITE ALL CONTENTS OF ${target_device}. Type uppercase yes to continue: " confirmed
|
||
|
|
||
|
if [[ "$confirmed" != "YES" ]]; then
|
||
|
echo "aborted" >&2
|
||
|
exit 128
|
||
|
fi
|
||
|
|
||
|
timedatectl set-ntp true
|
||
|
hwclock --systohc --utc
|
||
|
loadkeys de-latin1
|
||
|
|
||
|
# Partition
|
||
|
sgdisk --zap-all "${target_device}"
|
||
|
sgdisk --clear \
|
||
|
--new 1:0:+550MiB --typecode 1:ef00 --change-name 1:EFI \
|
||
|
--new 2:0:+8GiB --typecode 2:8200 --change-name 2:swap \
|
||
|
--new 3 --typecode 3:8304 --change-name 3:system \
|
||
|
"${target_device}"
|
||
|
|
||
|
# Reload partition table
|
||
|
sleep 5
|
||
|
partprobe -s "${target_device}"
|
||
|
sleep 3
|
||
|
|
||
|
# Encrypt root
|
||
|
echo -n "password" | cryptsetup luksFormat --type luks2 --pbkdf argon2id "/dev/disk/by-partlabel/system"
|
||
|
echo -n "password" | cryptsetup luksOpen --allow-discards --persistent "/dev/disk/by-partlabel/system" system
|
||
|
|
||
|
# Create file systems
|
||
|
mkfs.fat -F 32 -n "EFI" /dev/disk/by-partlabel/EFI
|
||
|
mkfs.btrfs --force --label system /dev/mapper/system
|
||
|
|
||
|
# Mount system subvolume and create additional subvolumes
|
||
|
o=defaults,x-mount.mkdir
|
||
|
o_btrfs=$o,compress=zstd,ssd,noatime
|
||
|
|
||
|
mount -t btrfs LABEL=system /mnt
|
||
|
btrfs subvolume create /mnt/@ # /
|
||
|
btrfs subvolume create /mnt/@home # /home
|
||
|
btrfs subvolume create /mnt/@snapshots # /.snapshots
|
||
|
btrfs subvolume create /mnt/@pkg # /var/cache/pacman/pkg
|
||
|
btrfs subvolume create /mnt/@aurbuild # /var/lib/aurbuild
|
||
|
btrfs subvolume create /mnt/@archbuild # /var/lib/archbuild
|
||
|
btrfs subvolume create /mnt/@log # /var/log
|
||
|
btrfs subvolume create /mnt/@tmp # /var/tmp
|
||
|
|
||
|
umount -R /mnt
|
||
|
mount -t btrfs -o subvol=@,$o_btrfs LABEL=system /mnt
|
||
|
mount -t btrfs -o subvol=@home,$o_btrfs,nodatacow LABEL=system /mnt/home
|
||
|
mount -t btrfs -o subvol=@snapshots,$o_btrfs LABEL=system /mnt/.snapshots
|
||
|
mount -t btrfs -o subvol=@pkg,$o_btrfs LABEL=system /mnt/var/cache/pacman/pkg
|
||
|
mount -t btrfs -o subvol=@aurbuild,$o_btrfs LABEL=system /mnt/var/lib/aurbuild
|
||
|
mount -t btrfs -o subvol=@archbuild,$o_btrfs LABEL=system /mnt/var/lib/archbuild
|
||
|
mount -t btrfs -o subvol=@log,$o_btrfs LABEL=system /mnt/var/log
|
||
|
mount -t btrfs -o subvol=@tmp,$o_btrfs LABEL=system /mnt/var/tmp
|
||
|
|
||
|
# Mount additional partitions
|
||
|
mount -o $o LABEL=EFI /mnt/efi
|
||
|
|
||
|
# Change default btrfs sub-volume (for DPS)
|
||
|
default_subvolume=$(btrfs subvolume list /mnt | grep "path @$" | cut -d ' ' -f2)
|
||
|
btrfs subvolume set-default ${default_subvolume} /mnt
|
||
|
|
||
|
# Disable CoW for /home due to large loopback files by systemd-homed
|
||
|
chattr +C /mnt/home
|
||
|
|
||
|
if ! grep "# Installer cache" /etc/pacman.conf > /dev/null; then
|
||
|
cat >> /etc/pacman.conf << EOF
|
||
|
# Installer cache
|
||
|
[options]
|
||
|
CacheDir = /mnt/var/cache/pacman/pkg
|
||
|
EOF
|
||
|
fi
|
||
|
|
||
|
# Bootstrap new chroot
|
||
|
reflector --country 'Germany' --protocol https --sort age --latest 5 --save /etc/pacman.d/mirrorlist
|
||
|
pacstrap /mnt base linux linux-firmware intel-ucode btrfs-progs dracut neovim iwd networkmanager
|
||
|
|
||
|
genfstab -L -p /mnt >> /mnt/etc/fstab
|
||
|
|
||
|
# Configure timezone, locale, keymap, network
|
||
|
sed -i 's/^#en_US\.UTF-8/en_US\.UTF-8/' /mnt/etc/locale.gen
|
||
|
sed -i 's/^#de_DE\.UTF-8/de_DE\.UTF-8/' /mnt/etc/locale.gen
|
||
|
arch-chroot /mnt locale-gen
|
||
|
arch-chroot /mnt systemd-firstboot \
|
||
|
--locale="en_US.UTF-8" \
|
||
|
--keymap="de-latin1" \
|
||
|
--timezone="Europe/Berlin" \
|
||
|
--hostname="${new_hostname}" \
|
||
|
--setup-machine-id
|
||
|
echo -e "127.0.0.1\tlocalhost" >> /mnt/etc/hosts
|
||
|
echo -e "127.0.1.1\t$new_hostname" >> /mnt/etc/hosts
|
||
|
echo -e "\n::1\tlocalhost" >> /mnt/etc/hosts
|
||
|
|
||
|
# Use systemd-resolved as dns backend for NetworkManager (auto-detected)
|
||
|
ln -sf /run/systemd/resolve/stub-resolv.conf /mnt/etc/resolv.conf
|
||
|
|
||
|
# Enable iwd as wifi backend for NetworkManager
|
||
|
cat > /mnt/etc/NetworkManager/conf.d/wifi-backend.conf <<EOF
|
||
|
[device]
|
||
|
wifi.backend=iwd
|
||
|
EOF
|
||
|
|
||
|
# Install dracut opt deps required to build unified kernel images
|
||
|
arch-chroot /mnt pacman -S --noconfirm --asdeps binutils elfutils
|
||
|
arch-chroot /mnt dracut -f --uefi --regenerate-all
|
||
|
# Install bootloader
|
||
|
arch-chroot /mnt bootctl install
|
||
|
|
||
|
# Enable resolved
|
||
|
systemctl --root /mnt enable systemd-resolved
|
||
|
# Enable NetworkManager
|
||
|
systemctl --root /mnt enable NetworkManager
|
||
|
# Enable homed
|
||
|
systemctl --root /mnt enable systemd-homed
|
||
|
|
||
|
# Set root password
|
||
|
echo "root:password" | chpasswd -R /mnt
|
||
|
|
||
|
echo "BOOTSTRAPPING FINISHED"
|