From 95a37adce77e0a567abe3d21e782115e956b4f2f Mon Sep 17 00:00:00 2001 From: Conor Budworth Date: Sun, 9 Nov 2025 03:18:30 +0100 Subject: [PATCH] Add install_arch_solphyr.sh --- install_arch_solphyr.sh | 152 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 152 insertions(+) create mode 100644 install_arch_solphyr.sh diff --git a/install_arch_solphyr.sh b/install_arch_solphyr.sh new file mode 100644 index 0000000..8cc984e --- /dev/null +++ b/install_arch_solphyr.sh @@ -0,0 +1,152 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Colour helpers +b=$(tput bold); r=$(tput sgr0); g=$(tput setaf 2); y=$(tput setaf 3); c=$(tput setaf 6); e=$(tput setaf 1) +info(){ echo "${c}==>${r} $*"; } +warn(){ echo "${y}!${r} $*"; } +die(){ echo "${e}x${r} $*" >&2; exit 1; } + +NO_PROMPT=0 +[[ "${1:-}" =~ (--no-prompt|--auto) ]] && NO_PROMPT=1 + +# --- Load or create .env --- +[[ ! -f .env ]] && { warn ".env missing, creating from template"; cp .env.template .env 2>/dev/null || touch .env; } +source .env || true + +prompt_var(){ local n=$1 t=$2 d="${!n:-}"; [[ $NO_PROMPT == 1 ]] && { info "Using $n=$d"; return; } +read -e -p "$t [$d]: " i; [[ -n $i ]] && eval "$n=\"\$i\""; } +prompt_secret(){ local n=$1 t=$2 d="${!n:-}"; if [[ -z $d ]]; then read -s -p "$t: " i; echo; eval "$n=\"\$i\""; else info "Using $n from .env"; fi; } +save_env(){ local n=$1 v="${!n}"; sed -i "/^$n=/d" .env; echo "$n=\"$v\"" >> .env; } + +# --- Gather configuration --- +prompt_var HOSTNAME "Hostname"; prompt_var USERNAME "Username"; prompt_var KEYMAP "Keymap" +prompt_var TIMEZONE "Timezone"; prompt_var LOCALE "Locale" +save_env HOSTNAME; save_env USERNAME; save_env KEYMAP; save_env TIMEZONE; save_env LOCALE + +# --- Networking --- +timedatectl set-ntp true +if [[ -z "$(ip link | grep -E 'state UP')" ]]; then + warn "No active network found" + prompt_var WIFI_SSID "Wi-Fi SSID"; prompt_secret WIFI_PASS "Wi-Fi password" + iwctl station wlan0 scan || true + iwctl station wlan0 connect "$WIFI_SSID" --passphrase "$WIFI_PASS" || die "Wi-Fi connect failed" +else info "Network detected"; fi + +# --- Disk selection --- +if [[ -z "${DISK:-}" ]]; then + info "Available disks:"; lsblk -dno NAME,SIZE,MODEL | grep -v loop | nl -w2 -s'. ' + [[ $NO_PROMPT == 1 ]] && die "No DISK specified in .env" + read -p "Select disk number: " n; DISK="/dev/$(lsblk -dno NAME | grep -v loop | sed -n "${n}p")" +fi; save_env DISK +EFI="${DISK}p1"; ROOT="${DISK}p2" +read -p "${e}${b}⚠️ Erase $DISK? ENTER to confirm${r}" + +# --- Partition + encrypt --- +sgdisk --zap-all "$DISK" +sgdisk -n1:0:+1G -t1:ef00 -c1:"EFI System" "$DISK" +sgdisk -n2:0:0 -t2:8300 -c2:"Linux LUKS" "$DISK"; partprobe "$DISK" +prompt_secret LUKS_PASSWORD "LUKS password"; save_env LUKS_PASSWORD +echo -n "$LUKS_PASSWORD" | cryptsetup luksFormat --batch-mode --type luks2 --cipher aes-xts-plain64 --key-size 512 --hash sha512 "$ROOT" - +echo -n "$LUKS_PASSWORD" | cryptsetup open "$ROOT" cryptroot - +mkfs.fat -F32 "$EFI"; mkfs.ext4 /dev/mapper/cryptroot +mount /dev/mapper/cryptroot /mnt; mkdir /mnt/boot; mount "$EFI" /mnt/boot + +# --- Mirrors + base --- +pacman -Sy --noconfirm reflector +reflector --country "United Kingdom" --latest 20 --sort rate --save /etc/pacman.d/mirrorlist +pacstrap -K /mnt base linux linux-firmware vim networkmanager sudo base-devel git + +genfstab -U /mnt >> /mnt/etc/fstab + +# --- Chroot configuration --- +arch-chroot /mnt /bin/bash < /etc/locale.conf +echo "$HOSTNAME" > /etc/hostname +cat </etc/hosts +127.0.0.1 localhost +::1 localhost +127.0.1.1 $HOSTNAME.localdomain $HOSTNAME +EOF +echo "KEYMAP=$KEYMAP" > /etc/vconsole.conf + +sed -i 's/\(filesystems\)/encrypt \1/' /etc/mkinitcpio.conf +mkinitcpio -P + +bootctl install +UUID=\$(blkid -s UUID -o value ${ROOT}) +cat </boot/loader/loader.conf +default arch.conf +timeout 3 +console-mode max +editor no +EOF +cat </boot/loader/entries/arch.conf +title Arch Linux +linux /vmlinuz-linux +initrd /initramfs-linux.img +options cryptdevice=UUID=\${UUID}:cryptroot root=/dev/mapper/cryptroot rw +EOF + +echo "Set root password:"; passwd +useradd -m -G wheel -s /bin/bash $USERNAME +echo "Set password for $USERNAME:"; passwd $USERNAME +sed -i 's/^# %wheel ALL=(ALL:ALL) ALL/%wheel ALL=(ALL:ALL) ALL/' /etc/sudoers +systemctl enable NetworkManager + +# --- Optional yay --- +if [[ "${INSTALL_YAY,,}" == "yes" ]]; then + pacman -Sy --noconfirm base-devel git + su - $USERNAME -c "cd /tmp && git clone https://aur.archlinux.org/yay.git && cd yay && makepkg -si --noconfirm && rm -rf /tmp/yay" +fi + +# --- Optional hardening --- +if [[ "${ENABLE_HARDENING,,}" == "yes" ]]; then + pacman -Sy --noconfirm ufw apparmor fail2ban archlinux-keyring + systemctl enable ufw; systemctl start ufw + ufw default deny incoming; ufw default allow outgoing; ufw enable + systemctl enable apparmor; systemctl enable fail2ban + cat </etc/sysctl.d/99-hardening.conf +net.ipv4.conf.all.accept_redirects = 0 +net.ipv6.conf.all.accept_redirects = 0 +net.ipv4.conf.all.send_redirects = 0 +net.ipv4.conf.all.accept_source_route = 0 +net.ipv6.conf.all.accept_source_route = 0 +net.ipv4.tcp_syncookies = 1 +net.ipv4.icmp_echo_ignore_broadcasts = 1 +net.ipv4.icmp_ignore_bogus_error_responses = 1 +kernel.randomize_va_space = 2 +EOF + sysctl --system + echo 'Defaults timestamp_timeout=5' > /etc/sudoers.d/hardening +fi +CHROOT + +# --- Optional WireGuard setup --- +if [[ "${ENABLE_WIREGUARD,,}" == "yes" && -f "${WIREGUARD_CONF_PATH}" ]]; then + info "Installing WireGuard..." + install -Dm600 "$WIREGUARD_CONF_PATH" "/mnt/etc/wireguard/wg0.conf" + arch-chroot /mnt pacman -Sy --noconfirm wireguard-tools + arch-chroot /mnt systemctl enable wg-quick@wg0.service +else + warn "WireGuard skipped (no config or disabled)." +fi + +umount -R /mnt; cryptsetup close cryptroot +info "Installation complete" + +cat <