Skip to content

Instantly share code, notes, and snippets.

@altercation
Last active October 4, 2021 15:38
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save altercation/8d5bd3685f564e6e3c0c4c06f4730484 to your computer and use it in GitHub Desktop.
Save altercation/8d5bd3685f564e6e3c0c4c06f4730484 to your computer and use it in GitHub Desktop.
arch-dual drive config
#!/bin/sh
#----------------------------------------------------------------------
# Arch Linux Installation Script
#
# This installs, with no intervention (other than initial edit to change
# RAID array drive values), Arch Linux on an encrypted btrfs raid1 array.
#----------------------------------------------------------------------
set -eu
#----------------------------------------------------------------------
# DRIVE & SCRIPT VALUES
#----------------------------------------------------------------------
DRIVE1=/dev/nvme0n1
DRIVE2=/dev/sdb
echo -e "confirm device assignments in script first\nDRIVE 1 = $DRIVE1\nDRIVE 2 = $DRIVE2\n\nlsblk:\n"; lsblk; exit
# script values
HOST=nostromo
USER=es
USERSHELL=zsh
MOUNT=/mnt
MOUNTOPTS=defaults,x-mount.mkdir
BTRFSOPTS=$MOUNTOPTS,ssd,noatime
#----------------------------------------------------------------------
# preflight cleanup (close mapped encrypted devices, unmount, shutdown swap)
#----------------------------------------------------------------------
[ -n "${SWAP:=$(swapon --noheadings --show=NAME)}" ] && swapoff $SWAP
umount /key || :
umount /mnt/boot || :
umount -R /mnt || :
for MAPPED in $(ls /dev/mapper); do [ "$MAPPED" != "control" ] && cryptsetup close /dev/mapper/$MAPPED || : ; done
#----------------------------------------------------------------------
# optional: secure wipe of drive (takes a while)
#----------------------------------------------------------------------
# sgdisk --zap-all /dev/device
# cryptsetup open --type plain /dev/device container --key-file /dev/random
# dd if=/dev/zero of=/dev/mapper/container status=progress
# cryptsetup close container
#----------------------------------------------------------------------
# Create Partitions
#----------------------------------------------------------------------
# NOTE: EFI partition should be at least 550MiB according to
# http://www.rodsbooks.com/efi-bootloaders/principles.html
for DRIVE in $DRIVE1 $DRIVE2
do
sgdisk --zap-all $DRIVE
done
sgdisk --clear \
--new=1:0:+2GiB --typecode=1:ef00 --change-name=1:EFI \
--new=2:0:+64GiB --typecode=2:8200 --change-name=2:cryptswap \
--new=3:0:0 --typecode=3:8200 --change-name=3:cryptsystem1 \
$DRIVE1
sgdisk --clear \
--new=1:0:0 --typecode=1:8200 --change-name=1:cryptsystem2 \
$DRIVE2
#----------------------------------------------------------------------
#
#----------------------------------------------------------------------
# get passphrase
while ! ${MATCH:-false}
do
echo -en "Enter Passphrase : "
read -rs PASS
echo -en "\nConfirm Passphrase : "
read -rs CONF
[ "$PASS" = "$CONF" ] \
&& { MATCH=true; echo -e "\n\nPassphrases matched.\n"; } \
|| echo -e "\n\nPassphrases didn't match--try again.\n"
done
# encrypt cryptsystem* partitions with passphrases
for PART in cryptsystem1 cryptsystem2
do
echo $PASS | cryptsetup luksFormat --align-payload=8192 -s 256 -c aes-xts-plain64 /dev/disk/by-partlabel/$PART
echo $PASS | cryptsetup open /dev/disk/by-partlabel/$PART ${PART#crypt}
done
#----------------------------------------------------------------------
# Format & Mount Partitions
#----------------------------------------------------------------------
mkfs.fat -F32 -n EFI /dev/disk/by-partlabel/EFI
# make btrfs raid
mkfs.btrfs --force --data raid1 --metadata raid1 --label system /dev/mapper/system1 /dev/mapper/system2
# mount btrfs top-level subvolume for further subvolume creation
mount -t btrfs -o $BTRFSOPTS LABEL=system $MOUNT
btrfs subvolume create $MOUNT/root
btrfs subvolume create $MOUNT/home
btrfs subvolume create $MOUNT/snapshots
umount -R $MOUNT
# remount subvolumes
mount -t btrfs -o $BTRFSOPTS,subvol=root LABEL=system $MOUNT
mount -t btrfs -o $BTRFSOPTS,subvol=home LABEL=system $MOUNT/home
mount -t btrfs -o $BTRFSOPTS,subvol=snapshots LABEL=system $MOUNT/.snapshots
# mount EFI
mount -o $MOUNTOPTS LABEL=EFI $MOUNT/boot
# make and activate swap
cryptsetup open --type plain --key-file /dev/urandom /dev/disk/by-partlabel/cryptswap swap
mkswap -L swap /dev/mapper/swap
swapon -L swap
#----------------------------------------------------------------------
# Install Base System
#----------------------------------------------------------------------
# install base system
pacstrap $MOUNT base base-devel btrfs-progs iw zsh vim terminus-font efibootmgr
# generate fstab
genfstab -L -p $MOUNT >> $MOUNT/etc/fstab
# remove the subvolume ID element of the fstab statements to
# allow mounting by subvolume name only (to facilitate rollbacks)
sed -i 's/,subvolid=[[:digit:]]*//g' $MOUNT/etc/fstab
# enter swap into crypttab
echo 'swap /dev/disk/by-partlabel/cryptswap /dev/urandom swap,cipher=aes-cbc-essiv:sha256,size=256' >> $MOUNT/etc/crypttab
# make sure we have a crypttab.initramfs as well
echo 'swap /dev/disk/by-partlabel/cryptswap /dev/urandom swap,cipher=aes-cbc-essiv:sha256,size=256' > $MOUNT/etc/crypttab.initramfs
# remove LABEL identifier for swap in fstab as it may/will not have a label from crypttab
# (TODO: could *maybe* solve this with luks.name= but I'm then using UUID)
sed -i 's+LABEL=swap+/dev/mapper/swap+' $MOUNT/etc/fstab
#----------------------------------------------------------------------
# Prepare chroot script
#----------------------------------------------------------------------
cat > $MOUNT/setup.sh <<EOFSETUP
#!/bin/sh
set -eu
HOST=$HOST
USER=$USER
USERSHELL=$USERSHELL
# get partition UUIDs (have to do this before entering chroot since lsblk won't report there)
CRYPTSWAP_UUID=$(lsblk --nodeps --noheadings -oUUID /dev/disk/by-partlabel/cryptswap)
CRYPTSYSTEM1_UUID=$(lsblk --nodeps --noheadings -oUUID /dev/disk/by-partlabel/cryptsystem1)
CRYPTSYSTEM2_UUID=$(lsblk --nodeps --noheadings -oUUID /dev/disk/by-partlabel/cryptsystem2)
EOFSETUP
cat >> $MOUNT/setup.sh <<'EOFSETUP'
setfont ter-u18n
echo "FONT=ter-u18n" > /etc/vconsole.conf
echo "en_US.UTF-8 UTF-8" >> /etc/locale.gen
locale-gen
echo "LANG=en_US.UTF-8" > /etc/locale.conf
export LANG=en_US.UTF-8
mv /etc/localtime /etc/localtime.orig
ln -s /usr/share/zoneinfo/America/Los_Angeles /etc/localtime
hwclock --systohc --utc
#timedatectl set-ntp true
echo $HOST > /etc/hostname
#edit /etc/hosts the same way... see beginners guide
mv /etc/hosts /etc/hosts.orig
cat > /etc/hosts <<EOF
#
# /etc/hosts: static lookup table for host names
#
#<ip-address> <hostname.domain.org> <hostname>
127.0.0.1 localhost.localdomain localhost
::1 localhost.localdomain localhost
127.0.0.1 $HOST.localdomain $HOST
::1 $HOST.localdomain $HOST
# End of file
EOF
# add user, set passwords
useradd -m -G wheel -s $(which $USERSHELL) $USER
while ! ${MATCH:-false}
do
echo -en "Enter Initial Root/User Passphrase : "
read -rs PASS
echo -en "\nConfirm Passphrase : "
read -rs CONF
[ "$PASS" = "$CONF" ] \
&& { MATCH=true; echo -e "\n\nPassphrases matched.\n"; } \
|| echo -e "\n\nPassphrases didn't match--try again.\n"
done
for ACCOUNT in root $USER; do
echo "$ACCOUNT:$PASS" | chpasswd
done
# enable sudo for wheel
tmpfile=$(mktemp)
echo "%wheel ALL=(ALL) NOPASSWD: ALL" > $tmpfile
visudo -cf $tmpfile \
&& mv $tmpfile /etc/sudoers.d/wheel \
|| { echo "ERROR updating sudoers; no change made"; exit 1; }
# reconfigure and regenerate initrams
mv /etc/mkinitcpio.conf /etc/mkinitcpio.orig
cat > /etc/mkinitcpio.conf << EOF
#MODULES="nvidia nvidia_modeset nvidia_uvm nvidia_drm"
BINARIES=""
FILES=""
HOOKS="base systemd sd-vconsole modconf keyboard block filesystems btrfs sd-encrypt fsck"
EOF
mkinitcpio -p linux
# remove exiting boot entry
EXISTINGENTRY=$(efibootmgr | grep "Linux Boot Manager" | cut -d " " -f 1 | sed "s/[^[:digit:]]*//g" | head -n1)
[ -n "$EXISTINGENTRY" ] && efibootmgr -b$EXISTINGENTRY -B
# install bootloader ( || : to swallow error code... this seems to return one even on success?)
bootctl --path=/boot install || :
# configure loader defaults
cat > /boot/loader/loader.conf <<EOF
default arch
timeout 5
editor 0
EOF
# configure initial entry
# TODO: try PARTLABEL in lieu of UUID
cat > /boot/loader/entries/arch.conf <<EOF
title Arch Linux
linux /vmlinuz-linux
initrd /initramfs-linux.img
options \
rd.luks.name=$CRYPTSYSTEM1_UUID=system1 \
rd.luks.name=$CRYPTSYSTEM2_UUID=system2 \
root=LABEL=system rootflags=subvol=/root,rw,x-systemd.device-timeout=0
# nvidia-drm.modeset=1 intel_iommu=on
EOF
cat > /boot/loader/entries/arch_fallback.conf <<EOF
title Arch Linux Fallback
linux /vmlinuz-linux
initrd /initramfs-linux-fallback.img
options \
rd.luks.name=$CRYPTSYSTEM1_UUID=system1 \
rd.luks.name=$CRYPTSYSTEM2_UUID=system2 \
root=LABEL=system rootflags=subvol=/root,rw,x-systemd.device-timeout=0
# nvidia-drm.modeset=1 intel_iommu=on
EOF
echo "use efibootmgr to ensure correct entry for systemd-boot is present, active, and in bootorder"
# add new efi boot entry
NEWENTRY=$(efibootmgr | grep "Linux Boot Manager" | cut -d " " -f 1 | sed "s/[^[:digit:]]*//g" | tail -n1)
BOOTORDER=$(efibootmgr | grep BootOrder | cut -d " " -f 2)
efibootmgr -o$NEWENTRY,$BOOTORDER
EOFSETUP
#----------------------------------------------------------------------
# Execute chroot script
#----------------------------------------------------------------------
chmod +x $MOUNT/setup.sh
arch-chroot $MOUNT sh -c '/setup.sh'
#----------------------------------------------------------------------
# Post reboot installation
#----------------------------------------------------------------------
cat > $MOUNT/install.sh <<EOFINSTALL
#!/bin/sh
set -eu
#----------------------------------------------------------------------
# Cleanup
#----------------------------------------------------------------------
rm /setup.sh
#----------------------------------------------------------------------
# Needs a bus, so post reboot
#----------------------------------------------------------------------
timedatectl set-ntp true
#----------------------------------------------------------------------
# general
#----------------------------------------------------------------------
pacman -S git
#----------------------------------------------------------------------
# Xorg
#----------------------------------------------------------------------
pacman -S nvidia nvidia-utils xorg-server xorg-server-utils xorg-apps
pacman -S nvidia-settings xorg-server-devel opencl-nvidia
# based on optional dependencies for nvidia-utils
# nvidia-settings
# xorg-server-devel: nvidia-xconfig
# opencl-nvidia
# INSTALL VIDEO ACCELERATION:
# https://wiki.archlinux.org/index.php/Hardware_video_acceleration
# (env variable VDPAU_DRIVER is current in my .xinitrc and should be sufficient in conjunction with nvidia-utils
# Consider "gnome-themes-standard" as optional fallback icon thing for libxcursor
# misc xorg utils
pacman -S xdotool wmctrl
# window manager / desktop environment
pacman -S xmonad xmonad-contrib xmobar rxvt-unicode compton dunst feh udiskie polkit-gnome \
xorg-xinit xorg-xfontsel xdg-utils networkmanager xscreensaver thunar dex xclip
# what about aur xinit-xsession?
# unclutter from aur
AUR unclutter-xfixes-git
# gtk theme
pacman -S gtk3 arc-solid-gtk-theme numix-gtk-theme lxappearance
AUR flatplat-theme-git oomox #oomox for numix changing
AUR xcursor-thedot
systemctl enable NetworkManager
systemctl start NetworkManager
# audio
pacman -S alsa-utils
# !!! Unmute master via alsamixer
pacman -S pulseaudio pulseaudio-alsa
OTHER AUR PACKAGES TO INSTALL:
# xsettingsd-git
# xcape or xcape-git
# xkb-switch, used to poll current keyboard config for xmobar
# xss-lock-git
# networkmanager_dmenu
# (I also create a symlink from /usr/bin/dmenu to /usr/bin/rofi
# rofi-fuzzy-git (I'm using a patched package I built with better fuzzy matching)
# google-chrome-beta
# IMPORTANT: copy over fonts
# acpi
pacman -S acpid
systemctl enable acpid
systemctl start acpid
mv /etc/acpi/handler.sh /etc/acpi/handler.sh.orig
#!!copy over handler.sh to /etc/acpi, make sure it's executable
#----------------------------------------------------------------------
# Misc utilities
#----------------------------------------------------------------------
# reflector
pacman -S reflector
cp /etc/pacman.d/mirrorlist /etc/pacman.d/mirrorlist.bak
reflector --country 'United States' --age 12 --protocol https --sort rate --save /etc/pacman.d/mirrorlist
#TODO: add as service
pacman -S mlocate
updatedb
#network utils
ldns #drill, etc.
bind-tools #dig, etc.
gptfdisk #sgdisk
youtube-dl
ffmpeg
dosfstools #mkfs.fat, etc.
# for xmonad: in chrome://apps, select desired chrome apps, right click on them and "add shortcuts".
# I find it easiest to do this to the $HOME/Desktop (or xdg equiv) folder and then rename them and move them
# to ~/.local/share/applications/ (though maybe I could keep them on the "Desktop"?)
# --------------------------------
# CUPS
pacman -S cups cups-pdf
# edit /etc/cups/cups-pdf.conf to change destination of PDFs which is by default /var/spool/cups-pdf/$USER
systemctl enable org.cups.cupsd
systemctl start org.cups.cupsd
# for gtk3 printing as of gtk3.22
pacman -S gtk3-print-backends
#ADD USER TO lp and sys GROUP
usermod -aG lp es
usermod -aG sys es
# install avahi, enable hostname resolution
pacman -S avahi nss-mdns
pacman -S pygtk python2-dbus # for avahi-discover
sed -i 's/resolve/mdns_minimal \[NOTFOUND=return\] resolve/' /etc/nsswitch.conf
systemctl enable avahi-daemon
systemctl start avahi-daemon
systemctl restart org.cups.cupsd
systemctl enable cups-browsed
systemctl start cups-browsed
# Avahi: Be sure to open UDP port 5353 if you're using a firewall.
# https://wiki.archlinux.org/index.php/Avahi#Hostname_resolution
# install samba?
# SAMBA NOTE: according to https://wiki.archlinux.org/index.php/Avahi#Samba
# With the Avahi daemon running on both the server and client, the file manager on the client should automatically find the server.
#drivers (kitchen sink approach)
pacman -S foomatic-db-engine foomatic-db foomatic-db-ppds foomatic-db-nonfree-ppds foomatic-db-gutenprint-ppds gutenprint ghostscript gsfonts
# see the https://wiki.archlinux.org/index.php/CUPS page for examples of the very useful
# lp* commands for adding queues, printing, etc. It's my preferred method.
# at this point, running 'lpinfo -v' should return list of local and network printers
# hplip should have extra drivers
pacman -S hplip
driverless:ipp://NPI0E6B0A.local:631/ipp/print Hewlett-Packard HP Color LaserJet MFP M277dw, driverless, cups-filters 1.13.4
ipp://NPI0E6B0A.local:631/ipp/print
# following worked to setup my local HP printer, which was also available via driverless printing
lpadmin -p hpcolor -E -v ipp://NPI0E6B0A.local:631/ipp/print -m lsb/usr/HP/hp-color_laserjet_pro_mfp_m277-ps.ppd.gz
# I can then set it as defaul
lpoptions -d hpcolor
# and print (for example) an image to it like this:
cat my.jpg | lpr
# In my experience the following hp-setup commands aren't useful
# hplip provides drivers for HP DeskJet, OfficeJet, Photosmart, Business Inkjet, and some LaserJet printers, and also provides an easy to use setup tool.
# To run the setup tool with the GUI qt frontend:
hp-setup -u
# To run the setup tool with the command line frontend:
hp-setup -i
# To set up directly the configuration of a network connected HP printer:
hp-setup -i <ip address>
# To run systray spool manager:
hp-systray
# To generate a URI for a given ip address:
hp-makeuri <ip address>
# scanning...
# sane, hp-scan, python-pillow
# install other hplip optional packages
libusb python-gobject python-pillow python-pyqt5 python-reportlab rpcbind sane wget xsane xsane-gimp
AUR: hplip-plugin # probably not necessary... i've had this setup working before without this
# scanning
# I am not sure if I previously had run hp-setup or not, but I found that this time round I couldn't
# scan without first running hp-setup and adding a printer again, but then it works
hp-scan --mode=color
# STEAM
enable multilib in pacman.conf
install lib32-nvidia-utils
install steam
# ----------------------------------
# production apps
pacman -S libreoffice-fresh
pacman -S gimp inkscapesed 's/resolve/mdns_minimal \[NOTFOUND=return\] resolve/' /etc/nsswitch.conf
# ----------------------------------
# SNAPPER - as per rec on https://wiki.archlinux.org/index.php/Snapper
# this should be moved to the configuration stage, not provisioning
chmod 0750 /.snapshots
umount /.snapshots
rmdir /.snapshots
snapper -c root create-config /
mount /.snapshots
snapper -c home create-config /home
# enable backup of boot partition (ESP) on kernel update (evidently works well with snap-pac)
vim /usr/share/libalpm/hooks/50_bootbackup.hook
[Trigger]
Operation = Upgrade
Operation = Install
Operation = Remove
Type = Package
Target = linux
[Action]
Depends = rsync
Description = Backing up /boot...
When = PreTransaction
Exec = /usr/bin/rsync -avzq --delete /boot /.bootbackup
# install snap-pac to automatically use snapper
pacman -S snap-pac
# install a btrfs sync tool TBD
TBD
# enable snapshots on boot
systemctl enable snapper-boot.timer
# filesystem mounting of iOS devices
pacman -S gvfs-afc
EOFINSTALL
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment