Skip to content

Instantly share code, notes, and snippets.

@dyeo
Last active August 17, 2025 03:11
Show Gist options
  • Select an option

  • Save dyeo/b44ee68b59f66386f7621cec159bf34d to your computer and use it in GitHub Desktop.

Select an option

Save dyeo/b44ee68b59f66386f7621cec159bf34d to your computer and use it in GitHub Desktop.
#!/usr/bin/env bash
# Arch gaming + studio bootstrap (dual-kernel, i3-gaps, NVIDIA, PipeWire, yay, fonts/theme)
# Usage: sudo ./bootstrap.sh <non-root-username>
set -euo pipefail
TARGET_USER="${1:-}"; [[ -n "$TARGET_USER" && "$TARGET_USER" != "root" ]] || { echo "Usage: sudo $0 <non-root-username>"; exit 1; }
USER_HOME="$(getent passwd "$TARGET_USER" | cut -d: -f6)"; [[ -d "$USER_HOME" ]] || { echo "User home not found"; exit 1; }
# ---------- helpers ----------
run_as_user() {
# run yay/makepkg without requiring a user bus
sudo -u "$TARGET_USER" env -i HOME="$USER_HOME" USER="$TARGET_USER" LOGNAME="$TARGET_USER" \
PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/bin" \
TERM=xterm-256color \
bash -lc "$*"
}
# ---------- multilib + keyring ----------
if ! grep -q "^\[multilib\]" /etc/pacman.conf; then
printf "\n[multilib]\nInclude = /etc/pacman.d/mirrorlist\n" >> /etc/pacman.conf
else
sed -i '/^\#\[multilib\]/,/^\#Include = \/etc\/pacman.d\/mirrorlist/ s/^#//' /etc/pacman.conf || true
fi
pacman -Syyu --noconfirm
pacman -Sy --noconfirm archlinux-keyring
# ---------- core packages ----------
pacman -S --noconfirm --needed \
base-devel git sed grep which curl wget \
grub efibootmgr os-prober \
xorg-server xorg-xinit i3-gaps i3status dmenu alacritty \
nvidia-dkms nvidia-utils vulkan-icd-loader \
lib32-nvidia-utils lib32-vulkan-icd-loader \
pipewire pipewire-alsa pipewire-pulse pipewire-jack wireplumber \
realtime-privileges rtkit \
steam lutris wine-staging winetricks gamemode \
seatd dbus \
picom polybar ttf-dejavu ttf-liberation noto-fonts earlyoom
# ---------- services (no user-bus calls) ----------
systemctl enable seatd
systemctl enable --now earlyoom
# make gamemoded available for all users; user can start on login
systemctl --global enable gamemoded.service || true
# ---------- GRUB (UEFI assumed with EFI at /boot) ----------
if [[ -d /boot/EFI || -d /boot/efi || -d /efi ]]; then
grub-install --target=x86_64-efi --efi-directory=/boot --bootloader-id=GRUB || true
fi
if grep -q '^GRUB_CMDLINE_LINUX_DEFAULT=' /etc/default/grub; then
sed -i 's/^GRUB_CMDLINE_LINUX_DEFAULT=.*/GRUB_CMDLINE_LINUX_DEFAULT="quiet nvidia-drm.modeset=1"/' /etc/default/grub
else
echo 'GRUB_CMDLINE_LINUX_DEFAULT="quiet nvidia-drm.modeset=1"' >> /etc/default/grub
fi
grub-mkconfig -o /boot/grub/grub.cfg
# ---------- user X session: startx → i3 ----------
install -d -o "$TARGET_USER" -g "$TARGET_USER" "${USER_HOME}/.config/i3"
if [[ ! -f "${USER_HOME}/.xinitrc" ]]; then
cat > "${USER_HOME}/.xinitrc" <<'EOF'
#!/bin/sh
exec i3
EOF
chown "$TARGET_USER:$TARGET_USER" "${USER_HOME}/.xinitrc"; chmod +x "${USER_HOME}/.xinitrc"
fi
if [[ ! -f "${USER_HOME}/.bash_profile" ]]; then
cat > "${USER_HOME}/.bash_profile" <<'EOF'
# auto-start X on TTY1
if [[ -z "$DISPLAY" && "${XDG_VTNR}" = "1" ]]; then
exec startx
fi
EOF
chown "$TARGET_USER:$TARGET_USER" "${USER_HOME}/.bash_profile"
fi
# ---------- PipeWire low-latency + realtime ----------
usermod -aG realtime "$TARGET_USER"
mkdir -p /etc/pipewire
if [[ -f /usr/share/pipewire/pipewire.conf ]]; then
sed -r '/^#?default\.clock\.(quantum|min-quantum|max-quantum)/d' /usr/share/pipewire/pipewire.conf \
> /etc/pipewire/pipewire.conf
{
echo
echo "default.clock.quantum = 64"
echo "default.clock.min-quantum = 32"
echo "default.clock.max-quantum = 128"
} >> /etc/pipewire/pipewire.conf
fi
# ---------- yay (AUR helper) ----------
if ! command -v yay >/dev/null 2>&1; then
pacman -S --noconfirm --needed git base-devel
cd /opt
run_as_user "git clone https://aur.archlinux.org/yay.git"
chown -R "$TARGET_USER:$TARGET_USER" /opt/yay
cd /opt/yay
run_as_user "cd /opt/yay && makepkg -si --noconfirm"
fi
# ---------- resilient xanmod + xanmod-rt ----------
# noninteractive yay flags
YAYFLAGS="--noconfirm --needed --noredownload --norebuild --answerdiff N --answerclean N --mflags --skipinteg"
# 1) try normal
run_as_user "yay -Syu --pgpfetch || true"
if ! run_as_user "yay -S $YAYFLAGS linux-xanmod linux-xanmod-headers linux-xanmod-rt linux-xanmod-rt-headers"; then
# 2) alternate keyservers
install -d -m 700 -o "$TARGET_USER" -g "$TARGET_USER" "$USER_HOME/.gnupg"
cat > "$USER_HOME/.gnupg/dirmngr.conf" <<'EOF'
keyserver hkps://keys.openpgp.org
keyserver hkps://keyserver.ubuntu.com
keyserver hkp://keyserver.ubuntu.com:80
honor-http-proxy
EOF
chown "$TARGET_USER:$TARGET_USER" "$USER_HOME/.gnupg/dirmngr.conf"
run_as_user "gpgconf --kill dirmngr || true"
if ! run_as_user "yay -S $YAYFLAGS linux-xanmod linux-xanmod-headers linux-xanmod-rt linux-xanmod-rt-headers"; then
# 3) last resort: skip PGP just for these packages
run_as_user "yay -S --noconfirm --needed --mflags '--skippgpcheck' linux-xanmod linux-xanmod-headers linux-xanmod-rt linux-xanmod-rt-headers"
fi
fi
grub-mkconfig -o /boot/grub/grub.cfg
# ---------- optional: fonts + Alacritty theme (never fail) ----------
set +e
run_as_user "yay -S --noconfirm --needed ttf-iosevka-term-curly ttf-nerd-fonts-symbols ttf-nerd-fonts-symbols-mono" || true
fc-cache -fv || true
grep -q '^font ' "${USER_HOME}/.config/i3/config" 2>/dev/null || \
echo 'font pango:Iosevka Term Curly 11' >> "${USER_HOME}/.config/i3/config" 2>/dev/null
mkdir -p "${USER_HOME}/.config/alacritty"
cat > "${USER_HOME}/.config/alacritty/alacritty.yml" <<'YAML'
font:
normal: { family: "Iosevka Term Curly", style: Regular }
bold: { family: "Iosevka Term Curly", style: Bold }
italic: { family: "Iosevka Term Curly", style: Italic }
size: 11.0
colors:
primary: { background: '0x0a0a0f', foreground: '0xffd9f2' }
cursor: { text: '0x0a0a0f', cursor: '0xff9ad6' }
selection: { text: '0xffd9f2', background: '0x3a243d' }
normal: { black:'0x15121a', red:'0xff6b9f', green:'0x6ee6b7', yellow:'0xffc3e1', blue:'0xb7a1ff', magenta:'0xff9ad6', cyan:'0x9fe8ff', white:'0xffe9f6' }
bright: { black:'0x2a2533', red:'0xff84b0', green:'0x8cf0c9', yellow:'0xffd1e9', blue:'0xc8b7ff', magenta:'0xffb0e0', cyan:'0xb8f1ff', white:'0xffffff' }
YAML
chown -R "$TARGET_USER:$TARGET_USER" "${USER_HOME}/.config/alacritty" "${USER_HOME}/.config/i3" || true
set -e
echo
echo "Done. Reboot. Pick linux-xanmod (gaming) or linux-xanmod-rt (audio) in GRUB."
echo "Login on tty1 → startx → i3-gaps."
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment