From 154deb02cf7ebd8fcc8bf44239a622ba32389949 Mon Sep 17 00:00:00 2001 From: Conor Budworth Date: Sun, 9 Nov 2025 04:30:02 +0100 Subject: [PATCH] Update install_arch_solphyr.sh --- install_arch_solphyr.sh | 138 +++++++++------------------------------- 1 file changed, 30 insertions(+), 108 deletions(-) diff --git a/install_arch_solphyr.sh b/install_arch_solphyr.sh index cde192f..19ab567 100644 --- a/install_arch_solphyr.sh +++ b/install_arch_solphyr.sh @@ -1,12 +1,11 @@ #!/usr/bin/env bash set -euo pipefail -# ──────────────────────────────────────────────────────────────── -# Solphyr Arch Linux Auto-Installer -# Full LUKS2 encryption • systemd-boot • yay • WireGuard • Hardening -# ──────────────────────────────────────────────────────────────── +# ─────────────────────────────────────────────── +# Solphyr Arch Linux Auto-Installer (base only) +# LUKS2 • systemd-boot • yay • reproducible .env +# ─────────────────────────────────────────────── -# 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} $*"; } @@ -15,80 +14,45 @@ 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 -# ── Safe prompting helpers ───────────────────────────────────── -# --- Safe prompting helpers --- +# ── Prompt helpers ───────────────────────────── prompt_var() { - local var_name="$1" - local prompt_text="$2" - local default_val - default_val="$(eval "echo \${$var_name:-}")" - - if [[ "$NO_PROMPT" == "1" ]]; then - info "Using $var_name=$default_val" - return 0 - fi - - local input - # disable errexit for the read itself - set +e - read -e -p "$prompt_text [${default_val}]: " input - local rc=$? - set -e + local var_name="$1" prompt_text="$2" + local default_val; default_val="$(eval "echo \${$var_name:-}")" + if [[ "$NO_PROMPT" == "1" ]]; then info "Using $var_name=$default_val"; return 0; fi + local input; set +e + read -e -p "$prompt_text [${default_val}]: " input; local rc=$?; set -e [[ $rc -ne 0 ]] && die "Input cancelled" - if [[ -n "$input" ]]; then - eval "$var_name=\"\$input\"" - fi - return 0 + [[ -n "$input" ]] && eval "$var_name=\"\$input\"" } - prompt_secret() { - local var_name="$1" - local prompt_text="$2" - local default_val - default_val="$(eval "echo \${$var_name:-}")" + local var_name="$1" prompt_text="$2" + local default_val; default_val="$(eval "echo \${$var_name:-}")" if [[ -z "$default_val" ]]; then - set +e - read -s -p "$prompt_text: " input - local rc=$? - set -e - echo + set +e; read -s -p "$prompt_text: " input; local rc=$?; set -e; echo [[ $rc -ne 0 ]] && die "Input cancelled" eval "$var_name=\"\$input\"" - else - info "Using $var_name from .env" - fi - return 0 + else info "Using $var_name from .env"; fi } +save_env(){ local n=$1 v; v="$(eval "echo \${$n}")"; sed -i "/^${n}=/d" .env; echo "${n}=\"${v}\"" >> .env; } -save_env() { - local var_name="$1" - local var_value - var_value="$(eval "echo \${$var_name}")" - sed -i "/^${var_name}=/d" .env - echo "${var_name}=\"${var_value}\"" >> .env - return 0 -} - - -# ── Gather configuration ──────────────────────────────────────── +# ── Gather config ────────────────────────────── 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 ───────────────────────────────────────────────── +# ── Network ──────────────────────────────────── 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 connection failed" + iwctl station wlan0 connect "$WIFI_SSID" --passphrase "$WIFI_PASS" || die "Wi-Fi failed" else info "Network detected"; fi -# ── Disk selection ───────────────────────────────────────────── +# ── Disk ─────────────────────────────────────── 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" @@ -97,25 +61,23 @@ fi; save_env DISK EFI="${DISK}p1"; ROOT="${DISK}p2" read -p "${e}${b}⚠️ Erase $DISK? ENTER to confirm${r}" -# ── Partition + encryption ───────────────────────────────────── 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" - + --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 system ────────────────────────────────────── +# ── Base system ──────────────────────────────── 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 -# ── System configuration inside chroot ───────────────────────── +# ── Configure system ─────────────────────────── arch-chroot /mnt /bin/bash </etc/hosts 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 -# Fix insecure permissions from FAT32 chmod 600 /boot/loader/random-seed 2>/dev/null || true chmod 700 /boot/loader 2>/dev/null || true chmod 700 /boot/EFI/systemd 2>/dev/null || true chown -R root:root /boot /boot/EFI || true - UUID=\$(blkid -s UUID -o value ${ROOT}) cat </boot/loader/loader.conf default arch.conf @@ -154,13 +112,10 @@ linux /vmlinuz-linux initrd /initramfs-linux.img options cryptdevice=UUID=\${UUID}:cryptroot root=/dev/mapper/cryptroot rw EOF - -# Create user but skip passwords (set later outside heredoc) useradd -m -G wheel -s /bin/bash $USERNAME sed -i 's/^# %wheel ALL=(ALL:ALL) ALL/%wheel ALL=(ALL:ALL) ALL/' /etc/sudoers systemctl enable NetworkManager - -# yay (AUR helper) +# yay installation if [[ "${INSTALL_YAY,,}" == "yes" ]]; then pacman -S --noconfirm base-devel git go echo "%wheel ALL=(ALL:ALL) NOPASSWD: ALL" > /etc/sudoers.d/00-yay-temp @@ -175,58 +130,25 @@ if [[ "${INSTALL_YAY,,}" == "yes" ]]; then ' rm -f /etc/sudoers.d/00-yay-temp fi - -# 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 -# ── Interactive password setup (outside heredoc) ─────────────── +# ── Passwords (interactive) ──────────────────── info "Set root password" until arch-chroot /mnt passwd; do echo "Try again."; done - -info "Set password for user ${USERNAME}" +info "Set password for ${USERNAME}" until arch-chroot /mnt passwd "${USERNAME}"; do echo "Try again."; done -# ── WireGuard (optional) ──────────────────────────────────────── -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 - -# ── Finish ───────────────────────────────────────────────────── umount -R /mnt cryptsetup close cryptroot info "Installation complete" cat <