Arch Linux automated install script
2022-11-06
Manual install becomes boring after a while. Especially when creating multiple virtual machines.
Featuring:
- luks encrypted volume
- UEFI systemd-boot
- passwordless sudo for main user
- ansible ready (my tool of choice when it comes to post install config)
- shellcheck approved
There are four things that demands caution:
- This script is destructive, and I mean it - it will wipe your device clean (DISK variable), so you better verify it line by line before actually using it.
- Passwords in plaintext = bad security practice. Goto 3.
- Primary purpose is bootstraping virtual machines. Running it on physical machines/production is definitely possible, but I don't encourage it.
- Don't ask me to restore your backups, which you forgot to make before running this script. I'm not responsible for misusing the power of convenience and time saving this script provides.
#!/usr/bin/env bash
set -e
export DISK="/dev/sda"
export DEV_EFI="$DISK"1
export DEV_CRYPT="$DISK"2
export HOSTNAME="arch-vm"
export LOCALE_LANG="en_US.UTF-8"
export LOCALE_TIME="pl_PL.UTF-8"
export TIMEZONE="Europe/Warsaw"
export USERNAME="archimedes"
export GREEN="\033[0;32m"
export LUKS_PASSWORD="test"
export USER_PASSWORD="test"
export ROOT_PASSWORD="test"
main(){
if [ "$1" == "chroot" ]; then
chroot
fi
read -r -p "Arch Install Script, proceed? (y/n)" choice
case "$choice" in
y | Y) base ;;
n | N) exit ;;
*) exit ;;
esac
}
base() {
echo -e "${GREEN}>>> Preliminary setup"
tput sgr0
timedatectl set-ntp true
loadkeys pl
echo -e "${GREEN}>>> Creating Partitions"
tput sgr0
parted -s "$DISK" mklabel gpt
parted -s "$DISK" mkpart primary fat32 1MiB 512MiB
parted -s "$DISK" set 1 esp on
parted -s "$DISK" mkpart primary ext4 512MiB 100%
echo -e "${GREEN}>>> Partition created"
echo -e "${GREEN}>>> Setup luks on lvm"
tput sgr0
echo -n "$LUKS_PASSWORD" | cryptsetup luksFormat "$DEV_CRYPT" -
echo -n "$LUKS_PASSWORD" | cryptsetup luksOpen "$DEV_CRYPT" lvm -
pvcreate -f /dev/mapper/lvm
vgcreate arch /dev/mapper/lvm
lvcreate -l +100%FREE arch -n root
mkfs.ext4 /dev/mapper/arch-root
mount /dev/mapper/arch-root /mnt
mkdir /mnt/boot
mkfs.fat -F32 "$DEV_EFI"
mount "$DEV_EFI" /mnt/boot
echo -e "${GREEN}>>> Pacstrap"
tput sgr0
pacstrap -K /mnt base linux linux-firmware lvm2 man-db man-pages texinfo ansible git networkmanager zsh sudo
echo -e "${GREEN}>>> Fstab"
tput sgr0
genfstab -U /mnt >> /mnt/etc/fstab
echo -e "${GREEN}>>> Copy bootstrap into mount and exec arch-chroot"
tput sgr0
cp "${0##*/}" /mnt
echo -e "${GREEN}>>> Chroot"
tput sgr0
arch-chroot /mnt /"${0##*/}" chroot
umount -R /mnt
reboot
}
chroot() {
echo -e "${GREEN}>>> Timezone n hostname setup"
tput sgr0
ln -sf /usr/share/zoneinfo/"$TIMEZONE" /etc/localtime
hwclock --systohc
echo "$LOCALE_LANG" UTF-8 >>/etc/locale.gen
echo "$LOCALE_TIME" UTF-8 >>/etc/locale.gen
locale-gen
echo LANG="$LOCALE_LANG" >/etc/locale.conf
echo LC_TIME="$LOCALE_TIME" >>/etc/locale.conf
echo "$HOSTNAME" >/etc/hostname
echo -e "${GREEN}>>> mkinitcpio hooks"
tput sgr0
sed -i 's/^HOOKS=.*/HOOKS=(base udev autodetect modconf block keyboard encrypt lvm2 filesystems keyboard fsck)/' /etc/mkinitcpio.conf
mkinitcpio -p linux
echo -e "${GREEN}>>> systemd-boot"
tput sgr0
bootctl install
# no microcode, consider adding it when non-VM environment
DEVCRYPT_UUID="$(blkid -o value -s UUID "$DEV_CRYPT")"
{
echo title Arch Linux
echo linux /vmlinuz-linux
echo initrd /initramfs-linux.img
echo options cryptdevice=UUID="$DEVCRYPT_UUID":lvm root=/dev/mapper/arch-root rw
} >>/boot/loader/entries/arch.conf
# services
systemctl enable NetworkManager.service
systemctl enable NetworkManager-wait-online.service
# user
useradd -u 1000 -m -G wheel -s /usr/bin/zsh "$USERNAME"
echo -e "${GREEN}>>> Sudo config"
echo '%wheel ALL=(ALL) NOPASSWD: ALL' | EDITOR='tee -a' visudo
echo -e "${GREEN}>>> $USERNAME password"
tput sgr0
echo "$USERNAME:$USER_PASSWORD" | chpasswd
echo -e "${GREEN}>>> Root password"
tput sgr0
echo "root:$ROOT_PASSWORD" | chpasswd
echo -e "${GREEN}>>> Leaving chroot n rebooting"
tput sgr0
exit
}
main "$@"; exit