Move to Ubuntu 26.04 LTS: backup, setup and restore scripts
Replaces the Bazzite/BlueBuild image with plain Ubuntu. apt covers the system and dev tools, Flathub the desktop apps, and three scripts do the rest: backup.sh archives this machine's home to server-marvin and reads it back to verify it; setup.sh builds a fresh 26.04 install (NVIDIA 595-open, Docker with GPU access, Steam/Lutris, 27 Flatpaks, VS Code, Claude desktop, the Data drive and marvin mounts); restore.sh unpacks the backup without the Fedora/KDE parts that would fight Ubuntu. The app list comes from a scan of the running machine. The 15 Flatpaks left behind sit commented at the bottom of flatpaks.txt, and their data still rides along in the backup. No Node or .NET on the host by choice — LudosData and landingPage build in Docker. Drops the BlueBuild recipe, the cosign key and the old dev-setup script. The Bazzite setup stays in this history. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Executable
+111
@@ -0,0 +1,111 @@
|
||||
#!/usr/bin/env bash
|
||||
# Run on the Bazzite box BEFORE wiping it. Archives your home folder to server-marvin as
|
||||
# tar.zst files, then reads every archive back to prove it's intact.
|
||||
#
|
||||
# scripts/backup.sh # -> /var/mnt/server-marvin-personal/desktop-backup-<date>
|
||||
# scripts/backup.sh /some/other/dir # any directory NOT on the disk you're about to wipe
|
||||
#
|
||||
# Re-running skips archives that already finished (FORCE=1 redoes them).
|
||||
# Close Steam, Firefox, Discord and Claude first — files that change mid-read get a warning.
|
||||
set -euo pipefail
|
||||
|
||||
SHARE=/var/mnt/server-marvin-personal
|
||||
DEST="${1:-$SHARE/desktop-backup-$(date +%F)}"
|
||||
|
||||
step() { printf '\n\033[1;34m== %s ==\033[0m\n' "$*"; }
|
||||
warn() { printf '\033[1;33mwarning:\033[0m %s\n' "$*" >&2; }
|
||||
die() { printf '\033[1;31merror:\033[0m %s\n' "$*" >&2; exit 1; }
|
||||
|
||||
# -- Make sure the backup lands somewhere that survives the reinstall ------------------
|
||||
if [[ $DEST == "$SHARE"/* ]]; then
|
||||
ls "$SHARE" >/dev/null 2>&1 || true # poke the automount
|
||||
mountpoint -q "$SHARE" || die "$SHARE isn't mounted — is server-marvin up?"
|
||||
fi
|
||||
mkdir -p "$DEST"
|
||||
disk_of() { findmnt -n -o SOURCE -T "$1" | sed 's/\[.*//'; }
|
||||
[[ $(disk_of "$DEST") != "$(disk_of "$HOME")" ]] \
|
||||
|| die "$DEST is on the same disk as your home — that's the disk Ubuntu will wipe"
|
||||
echo "Backing up $HOME -> $DEST"
|
||||
df -h "$DEST" | tail -1
|
||||
|
||||
# -- Archive helper ---------------------------------------------------------------------
|
||||
archive() { # archive <name> <tar args + members...>
|
||||
local name=$1 out="$DEST/$1.tar.zst"; shift
|
||||
step "$name"
|
||||
if [[ -s $out && -z ${FORCE:-} ]]; then echo "already done, skipping"; return; fi
|
||||
local rc=0
|
||||
tar --create --file="$out.partial" --use-compress-program='zstd -T0 -3' \
|
||||
--directory="$HOME" \
|
||||
--checkpoint=100000 --checkpoint-action='ttyout= %{%H:%M:%S}t %T%*\r' \
|
||||
"$@" || rc=$?
|
||||
echo
|
||||
# GNU tar exits 1 when a file changed while it was being read (an app was still open).
|
||||
# Everything else still made it in, so keep the archive; anything above 1 is fatal.
|
||||
(( rc <= 1 )) || die "tar failed on $name (exit $rc)"
|
||||
(( rc == 0 )) || warn "$name: some files changed while being read — close apps and FORCE=1 to redo if it matters"
|
||||
mv "$out.partial" "$out"
|
||||
ls -lh "$out" | awk '{print " " $5}'
|
||||
}
|
||||
|
||||
# Big, self-contained folders get their own archive so they can be restored (or skipped)
|
||||
# separately. Everything else goes in home.tar.zst.
|
||||
archive home \
|
||||
--anchored \
|
||||
--exclude=./.cache \
|
||||
--exclude=./.local/share/Trash \
|
||||
--exclude=./.local/share/Steam \
|
||||
--exclude=./.steam \
|
||||
--exclude=./.local/share/containers \
|
||||
--exclude=./.local/share/flatpak \
|
||||
--exclude=./.local/share/baloo \
|
||||
--exclude='./.var/app/*/cache' \
|
||||
--exclude='./.claude.json.tmp.*' \
|
||||
--exclude=./.xlcore \
|
||||
--exclude=./ComfyUI \
|
||||
--no-anchored \
|
||||
--exclude=node_modules \
|
||||
--exclude=__pycache__ \
|
||||
.
|
||||
|
||||
# FFXIV game install (~124 GB) — Square's patch servers make a redownload take hours.
|
||||
[[ -d $HOME/.xlcore ]] && archive xlcore ./.xlcore
|
||||
|
||||
# ComfyUI minus its venv (rebuilt on Ubuntu); this is ~110 GB of models.
|
||||
[[ -d $HOME/ComfyUI ]] && archive comfyui \
|
||||
--anchored --exclude=./ComfyUI/venv --exclude=./ComfyUI/.venv \
|
||||
--no-anchored --exclude=__pycache__ \
|
||||
./ComfyUI
|
||||
|
||||
# Steam: only saves and settings. Games get redownloaded; the ones on the Data drive stay put.
|
||||
archive steam-saves \
|
||||
./.local/share/Steam/userdata \
|
||||
./.local/share/Steam/steamapps/compatdata
|
||||
|
||||
# -- Reference info for the rebuild -------------------------------------------------------
|
||||
step "manifest"
|
||||
m="$DEST/manifest"; mkdir -p "$m"
|
||||
flatpak list --app --columns=application,origin,installation > "$m/flatpaks.txt" 2>/dev/null || true
|
||||
code --list-extensions > "$m/vscode-extensions.txt" 2>/dev/null || true
|
||||
brew leaves > "$m/brew-leaves.txt" 2>/dev/null || true
|
||||
rpm-ostree status > "$m/rpm-ostree-status.txt" 2>/dev/null || true
|
||||
cp /etc/fstab "$m/fstab"
|
||||
cp -r "$HOME/.local/share/flatpak/overrides" "$m/flatpak-overrides-user" 2>/dev/null || true
|
||||
cp -r /var/lib/flatpak/overrides "$m/flatpak-overrides-system" 2>/dev/null || true
|
||||
lsblk -f > "$m/disks.txt"
|
||||
ls "$HOME/.local/share/Steam/steamapps/common" > "$m/steam-games-home.txt" 2>/dev/null || true
|
||||
ls /run/media/"$USER"/Data/SteamLibrary/steamapps/common > "$m/steam-games-data-drive.txt" 2>/dev/null || true
|
||||
ls "$m"
|
||||
|
||||
# -- Prove every archive reads back cleanly ----------------------------------------------
|
||||
if [[ -z ${SKIP_VERIFY:-} ]]; then
|
||||
for f in "$DEST"/*.tar.zst; do
|
||||
step "verify $(basename "$f")"
|
||||
tar --use-compress-program=zstd --list --file="$f" > /dev/null || die "$f is corrupt — rerun with FORCE=1"
|
||||
echo "ok"
|
||||
done
|
||||
fi
|
||||
|
||||
step "done"
|
||||
du -sh "$DEST"/*.tar.zst
|
||||
echo "Backup is in: $DEST"
|
||||
echo "Safe to wipe the 990 PRO once you've eyeballed that list."
|
||||
@@ -1,35 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
# One-shot developer toolchain setup for the main-desktop image.
|
||||
# Run as your user after first boot (safe to re-run). See DEVELOPMENT.md for the why.
|
||||
set -euo pipefail
|
||||
|
||||
echo "== Homebrew tools =="
|
||||
brew install mise gh cosign
|
||||
|
||||
echo "== Toolchains (mise) =="
|
||||
mise use -g node@22 python@3.12 go@latest rust@latest java@temurin-21 dotnet@10
|
||||
mise install node@18 node@20 python@3.11 java@temurin-17 java@temurin-25
|
||||
|
||||
echo "== RTL-SDR udev rules (FRScanner) =="
|
||||
if [ ! -f /etc/udev/rules.d/20-rtlsdr.rules ]; then
|
||||
sudo tee /etc/udev/rules.d/20-rtlsdr.rules >/dev/null <<'EOF'
|
||||
# Generic RTL2832U (rtl-sdr) dongles — allow non-root access
|
||||
SUBSYSTEM=="usb", ATTRS{idVendor}=="0bda", ATTRS{idProduct}=="2838", MODE="0666", TAG+="uaccess"
|
||||
SUBSYSTEM=="usb", ATTRS{idVendor}=="0bda", ATTRS{idProduct}=="2832", MODE="0666", TAG+="uaccess"
|
||||
EOF
|
||||
sudo udevadm control --reload-rules
|
||||
fi
|
||||
|
||||
echo "== Native-build distrobox =="
|
||||
if ! distrobox list 2>/dev/null | grep -q '^.*| *dev '; then
|
||||
distrobox create --yes dev --image registry.fedoraproject.org/fedora:44
|
||||
distrobox enter dev -- sudo dnf install -y gcc gcc-c++ make cmake pkgconf python3-devel \
|
||||
gtk4-devel zbar libsndfile mediainfo-libs rtl-sdr rtl-sdr-devel mkvtoolnix \
|
||||
python3-tkinter python3-dbus flashrom
|
||||
fi
|
||||
|
||||
echo "== Done =="
|
||||
echo "Remaining manual bits (see DEVELOPMENT.md):"
|
||||
echo " - copy ~/godot/ (pinned 4.2/4.3 binaries) and ~/.local/share/godot/ from old machine"
|
||||
echo " - bring per-project .env files (API keys)"
|
||||
echo " - ujust dx-group (docker group), then re-login"
|
||||
Executable
+90
@@ -0,0 +1,90 @@
|
||||
#!/usr/bin/env bash
|
||||
# Run on Ubuntu AFTER setup.sh and a reboot. Unpacks the Bazzite backup into your home,
|
||||
# minus the Fedora/KDE-specific bits that would fight a fresh Ubuntu desktop.
|
||||
#
|
||||
# scripts/restore.sh # newest desktop-backup-* on server-marvin
|
||||
# scripts/restore.sh /path/to/backup # a specific backup folder
|
||||
# ONLY="home steam-saves" scripts/restore.sh # just some archives
|
||||
#
|
||||
# Everything is still in the archives, so anything skipped here can be pulled out later:
|
||||
# tar -I zstd -xf home.tar.zst -C ~ ./.config/some-app
|
||||
set -euo pipefail
|
||||
|
||||
SHARE=/mnt/server-marvin-personal
|
||||
|
||||
step() { printf '\n\033[1;34m== %s ==\033[0m\n' "$*"; }
|
||||
die() { printf '\033[1;31merror:\033[0m %s\n' "$*" >&2; exit 1; }
|
||||
|
||||
[[ $EUID -ne 0 ]] || die "run as your user, not with sudo"
|
||||
ls "$SHARE" >/dev/null 2>&1 || true # poke the automount
|
||||
SRC="${1:-$(ls -d "$SHARE"/desktop-backup-* 2>/dev/null | sort | tail -1)}"
|
||||
[[ -n $SRC && -d $SRC ]] || die "no backup found — pass the folder, or check $SHARE is mounted"
|
||||
ONLY=${ONLY:-home steam-saves xlcore comfyui}
|
||||
echo "Restoring from $SRC: $ONLY"
|
||||
|
||||
pgrep -x steam >/dev/null && die "quit Steam first"
|
||||
|
||||
# Flatpak apps need a GL extension matching the NVIDIA driver, and flatpak can only see the
|
||||
# driver version once it's loaded — i.e. now, after the reboot. Without this they render in software.
|
||||
step "Flatpak NVIDIA runtime"
|
||||
sudo flatpak update -y --noninteractive
|
||||
|
||||
# Old configs (Heroic, Lutris, XIVLauncher, Proton prefixes, ...) hold absolute
|
||||
# /var/home/ckoch/... paths. One symlink makes all of them resolve on Ubuntu.
|
||||
[[ -e /var/home ]] || sudo ln -s /home /var/home
|
||||
|
||||
# Left out of home.tar.zst on purpose:
|
||||
skip=(
|
||||
--anchored
|
||||
# Fedora's shell dotfiles; Ubuntu's are better and setup.sh already added what's needed
|
||||
--exclude=./.bashrc --exclude=./.bash_profile --exclude=./.bash_logout --exclude=./.profile
|
||||
--exclude=./.bashrc.d --exclude=./.zshrc --exclude=./.zprofile
|
||||
# .NET tool shims built against Homebrew's SDK (setup.sh reinstalled dotnet-ef)
|
||||
--exclude=./.dotnet
|
||||
# pip --user installs for Fedora's Python, and launchers for the old distroboxes
|
||||
--exclude=./.local/bin --exclude='./.local/lib/python*'
|
||||
--exclude='./.local/share/applications/claude*'
|
||||
--exclude='./.local/share/applications/war1gus*'
|
||||
--exclude=./.local/share/applications/code.desktop
|
||||
# desktop state that would clobber Ubuntu's: GNOME's settings db, keyring, default apps,
|
||||
# and KDE-generated GTK themes that would recolor GNOME apps
|
||||
--exclude=./.config/dconf --exclude=./.local/share/keyrings --exclude=./.config/mimeapps.list
|
||||
--exclude=./.config/gtk-3.0 --exclude=./.config/gtk-4.0
|
||||
--exclude=./.config/gtkrc --exclude=./.config/gtkrc-2.0 --exclude=./.gtkrc-2.0
|
||||
# Bazzite leftovers
|
||||
--exclude=./.config/bazzite --exclude=./.config/autostart/sb-key-notify.desktop
|
||||
# old SMB password file (setup.sh stored the credentials in /etc/samba)
|
||||
--exclude=./.smbcredentials
|
||||
)
|
||||
|
||||
for name in $ONLY; do
|
||||
f="$SRC/$name.tar.zst"
|
||||
step "$name"
|
||||
[[ -f $f ]] || { echo "not in backup, skipping"; continue; }
|
||||
args=()
|
||||
[[ $name == home ]] && args=("${skip[@]}")
|
||||
tar --extract --file="$f" --use-compress-program=zstd --directory="$HOME" \
|
||||
--checkpoint=100000 --checkpoint-action='ttyout= %{%H:%M:%S}t %T%*\r' \
|
||||
"${args[@]}"
|
||||
echo "ok"
|
||||
done
|
||||
|
||||
# Claude Code keys memory/history by folder path; /var/home/ckoch is now /home/ckoch.
|
||||
if [[ -d ~/.claude/projects ]]; then
|
||||
for d in ~/.claude/projects/-var-home-*; do
|
||||
[[ -d $d ]] || continue
|
||||
new=~/.claude/projects/${d##*/-var}
|
||||
[[ -e $new ]] || mv "$d" "$new"
|
||||
done
|
||||
[[ -f ~/.claude.json ]] && sed -i 's#"/var/home/#"/home/#g' ~/.claude.json
|
||||
fi
|
||||
|
||||
step "Done — a few things to finish by hand"
|
||||
cat <<EOF
|
||||
- Steam: open it, sign in, then Settings > Storage > Add drive > /mnt/data/SteamLibrary
|
||||
(games on the Data drive come back without downloading; home-drive games redownload).
|
||||
- ComfyUI: rebuild its venv —
|
||||
cd ~/ComfyUI && python3 -m venv venv && venv/bin/pip install -r requirements.txt
|
||||
- Old pip --user tools (rembg etc.) weren't restored: pipx install "rembg[cli]" if you want it.
|
||||
- Log out and back in so every app picks up the restored settings.
|
||||
EOF
|
||||
Executable
+226
@@ -0,0 +1,226 @@
|
||||
#!/usr/bin/env bash
|
||||
# Fresh Ubuntu 26.04 LTS -> my desktop, in one pass. Run as your user; it sudos as needed.
|
||||
# Safe to re-run: each step checks before it changes anything. Reboot when it finishes,
|
||||
# then run scripts/restore.sh.
|
||||
set -euo pipefail
|
||||
|
||||
REPO="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
|
||||
# Second NVMe (970 EVO Plus, label "Data"): SteamLibrary + emulator files. Never formatted.
|
||||
DATA_UUID=29db4bd3-b743-417d-aa39-4da4acc9df3f
|
||||
DATA_MNT=/mnt/data
|
||||
# server-marvin SMB share — the backup lives here. \040 is fstab's escaped space.
|
||||
MARVIN_SHARE='//192.168.1.193/Personal\040Files\040-\040ckoch'
|
||||
MARVIN_MNT=/mnt/server-marvin-personal
|
||||
MARVIN_CREDS=/etc/samba/credentials-marvin
|
||||
|
||||
step() { printf '\n\033[1;34m== %s ==\033[0m\n' "$*"; }
|
||||
warn() { printf '\033[1;33mwarning:\033[0m %s\n' "$*" >&2; }
|
||||
die() { printf '\033[1;31merror:\033[0m %s\n' "$*" >&2; exit 1; }
|
||||
apt_install() { sudo DEBIAN_FRONTEND=noninteractive apt-get install -y "$@"; }
|
||||
|
||||
[[ $EUID -ne 0 ]] || die "run as your user, not with sudo"
|
||||
. /etc/os-release
|
||||
[[ $ID == ubuntu ]] || die "expected Ubuntu, found $ID"
|
||||
[[ $VERSION_ID == 26.04 ]] || warn "written for 26.04; this is $VERSION_ID — carrying on"
|
||||
CODENAME=${UBUNTU_CODENAME:-$VERSION_CODENAME}
|
||||
|
||||
# Ask for the password once and keep sudo alive for the whole run (Flatpaks take a while).
|
||||
sudo -v
|
||||
while true; do sudo -n true; sleep 50; kill -0 "$$" 2>/dev/null || exit; done 2>/dev/null &
|
||||
keepalive=$!
|
||||
trap 'kill "$keepalive" 2>/dev/null' EXIT
|
||||
|
||||
# ---------------------------------------------------------------------------------------
|
||||
step "Apt repositories"
|
||||
sudo apt-get update
|
||||
apt_install curl gpg ca-certificates software-properties-common
|
||||
for c in universe multiverse restricted; do sudo add-apt-repository -y -n "$c"; done
|
||||
sudo dpkg --add-architecture i386 # Steam + 32-bit game libraries
|
||||
sudo install -d -m 0755 /etc/apt/keyrings
|
||||
|
||||
# Docker CE — Docker's own repo, not the snap or Ubuntu's docker.io
|
||||
if [[ ! -f /etc/apt/sources.list.d/docker.sources ]]; then
|
||||
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
|
||||
sudo chmod a+r /etc/apt/keyrings/docker.asc
|
||||
sudo tee /etc/apt/sources.list.d/docker.sources >/dev/null <<EOF
|
||||
Types: deb
|
||||
URIs: https://download.docker.com/linux/ubuntu
|
||||
Suites: $CODENAME
|
||||
Components: stable
|
||||
Signed-By: /etc/apt/keyrings/docker.asc
|
||||
EOF
|
||||
fi
|
||||
|
||||
# NVIDIA Container Toolkit — GPU access inside Docker/Podman
|
||||
if [[ ! -f /etc/apt/sources.list.d/nvidia-container-toolkit.list ]]; then
|
||||
curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey \
|
||||
| sudo gpg --dearmor --yes -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg
|
||||
curl -fsSL https://nvidia.github.io/libnvidia-container/stable/deb/nvidia-container-toolkit.list \
|
||||
| sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' \
|
||||
| sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list >/dev/null
|
||||
fi
|
||||
|
||||
# VS Code — Microsoft's repo (was rpm-ostree-layered on Bazzite)
|
||||
if [[ ! -f /etc/apt/sources.list.d/vscode.sources ]]; then
|
||||
curl -fsSL https://packages.microsoft.com/keys/microsoft.asc \
|
||||
| sudo gpg --dearmor --yes -o /usr/share/keyrings/microsoft.gpg
|
||||
sudo tee /etc/apt/sources.list.d/vscode.sources >/dev/null <<EOF
|
||||
Types: deb
|
||||
URIs: https://packages.microsoft.com/repos/code
|
||||
Suites: stable
|
||||
Components: main
|
||||
Architectures: amd64
|
||||
Signed-By: /usr/share/keyrings/microsoft.gpg
|
||||
EOF
|
||||
fi
|
||||
|
||||
# GitHub CLI
|
||||
if [[ ! -f /etc/apt/sources.list.d/github-cli.list ]]; then
|
||||
sudo curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg \
|
||||
-o /etc/apt/keyrings/githubcli-archive-keyring.gpg
|
||||
sudo chmod go+r /etc/apt/keyrings/githubcli-archive-keyring.gpg
|
||||
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" \
|
||||
| sudo tee /etc/apt/sources.list.d/github-cli.list >/dev/null
|
||||
fi
|
||||
|
||||
# Claude desktop — Anthropic's repo (ran inside an Ubuntu distrobox on Bazzite)
|
||||
if [[ ! -f /etc/apt/sources.list.d/claude-desktop.list ]]; then
|
||||
key=/usr/share/keyrings/claude-desktop-archive-keyring.asc
|
||||
sudo curl -fsSLo "$key" https://downloads.claude.ai/claude-desktop/key.asc
|
||||
if ! gpg --show-keys --with-colons "$key" 2>/dev/null \
|
||||
| grep -q '^fpr:::::::::31DDDE24DDFAB679F42D7BD2BAA929FF1A7ECACE:'; then
|
||||
sudo rm -f "$key"; die "Claude desktop signing key has the wrong fingerprint — not adding the repo"
|
||||
fi
|
||||
echo "deb [arch=amd64,arm64 signed-by=$key] https://downloads.claude.ai/claude-desktop/apt/stable stable main" \
|
||||
| sudo tee /etc/apt/sources.list.d/claude-desktop.list >/dev/null
|
||||
fi
|
||||
|
||||
sudo apt-get update
|
||||
sudo DEBIAN_FRONTEND=noninteractive apt-get full-upgrade -y
|
||||
|
||||
# ---------------------------------------------------------------------------------------
|
||||
step "Packages"
|
||||
# steam-installer refuses to install non-interactively until its license is accepted.
|
||||
echo 'steam-installer steam/question select I AGREE' | sudo debconf-set-selections
|
||||
echo 'steam-installer steam/license note ' | sudo debconf-set-selections
|
||||
|
||||
apt_install \
|
||||
build-essential cmake pkg-config git git-lfs wget jq zstd unzip p7zip-full rsync htop \
|
||||
python3-venv python3-pip pipx ffmpeg cifs-utils flatpak \
|
||||
steam-installer steam-devices gamemode mangohud lutris vulkan-tools \
|
||||
docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin \
|
||||
nvidia-container-toolkit \
|
||||
code claude-desktop
|
||||
|
||||
# ---------------------------------------------------------------------------------------
|
||||
step "NVIDIA driver (open kernel modules — the only kind the RTX 5090 supports)"
|
||||
apt_install ubuntu-drivers-common
|
||||
installed_driver() {
|
||||
{ dpkg-query -W -f='${Status} ${Package}\n' 'nvidia-driver-*' 2>/dev/null || true; } \
|
||||
| awk '/^install ok installed / {print $4}' | sort -V | tail -1
|
||||
}
|
||||
if [[ $(installed_driver) != *-open ]]; then
|
||||
ubuntu-drivers devices 2>/dev/null | grep -E 'model|driver' || true
|
||||
# Picks Ubuntu's recommended branch plus its prebuilt, signed kernel modules (no DKMS).
|
||||
sudo ubuntu-drivers install
|
||||
fi
|
||||
driver=$(installed_driver)
|
||||
[[ $driver == nvidia-driver-*-open ]] \
|
||||
|| die "got '${driver:-no driver}', but the 5090 needs an -open driver — check 'ubuntu-drivers devices'"
|
||||
branch=${driver#nvidia-driver-}; branch=${branch%-open}
|
||||
apt_install "libnvidia-gl-$branch:i386" # 32-bit GL/Vulkan for Steam and Proton
|
||||
echo "using $driver"
|
||||
|
||||
# ---------------------------------------------------------------------------------------
|
||||
step "Docker, GPU containers, Claude's Cowork VM"
|
||||
sudo usermod -aG docker "$USER" # docker without sudo (after reboot)
|
||||
getent group kvm >/dev/null && sudo usermod -aG kvm "$USER" # Cowork needs /dev/kvm + vhost-vsock
|
||||
echo vhost_vsock | sudo tee /etc/modules-load.d/vhost_vsock.conf >/dev/null
|
||||
if ! grep -q nvidia /etc/docker/daemon.json 2>/dev/null; then
|
||||
sudo nvidia-ctk runtime configure --runtime=docker # enables `docker run --gpus all`
|
||||
sudo systemctl restart docker
|
||||
fi
|
||||
|
||||
# ---------------------------------------------------------------------------------------
|
||||
step "Flatpak apps"
|
||||
sudo flatpak remote-add --if-not-exists flathub https://dl.flathub.org/repo/flathub.flatpakrepo
|
||||
mapfile -t apps < <(sed -e 's/#.*//' -e 's/[[:space:]]//g' -e '/^$/d' "$REPO/flatpaks.txt")
|
||||
sudo flatpak install -y --noninteractive --system flathub "${apps[@]}"
|
||||
# Firefox's read-only peek at landingPage, as set by hand on Bazzite
|
||||
flatpak override --user org.mozilla.firefox --filesystem="$HOME/Documents/git/landingPage:ro"
|
||||
|
||||
# Firefox/Thunderbird come from Flathub instead, so restoring ~/.var/app brings the old
|
||||
# profiles back untouched. Drop Ubuntu's snaps and the debs that pull them back in.
|
||||
for s in firefox thunderbird; do
|
||||
if snap list "$s" >/dev/null 2>&1; then sudo snap remove --purge "$s"; fi
|
||||
if dpkg -s "$s" >/dev/null 2>&1; then sudo apt-get remove -y "$s"; fi
|
||||
done
|
||||
xdg-settings set default-web-browser org.mozilla.firefox.desktop 2>/dev/null || true
|
||||
|
||||
# Keep Flatpaks updated daily, like Bazzite did. Starts next boot.
|
||||
sudo tee /etc/systemd/system/flatpak-update.service >/dev/null <<'EOF'
|
||||
[Unit]
|
||||
Description=Update system Flatpaks
|
||||
Wants=network-online.target
|
||||
After=network-online.target
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
ExecStart=/usr/bin/flatpak update --system --noninteractive --assumeyes
|
||||
EOF
|
||||
sudo tee /etc/systemd/system/flatpak-update.timer >/dev/null <<'EOF'
|
||||
[Unit]
|
||||
Description=Update system Flatpaks daily
|
||||
|
||||
[Timer]
|
||||
OnBootSec=10min
|
||||
OnUnitActiveSec=1d
|
||||
Persistent=true
|
||||
|
||||
[Install]
|
||||
WantedBy=timers.target
|
||||
EOF
|
||||
sudo systemctl daemon-reload
|
||||
sudo systemctl enable flatpak-update.timer
|
||||
|
||||
# ---------------------------------------------------------------------------------------
|
||||
step "Claude Code CLI"
|
||||
# No Node or .NET on the host by choice — LudosData and landingPage build in Docker.
|
||||
# If you want them back: sudo apt install mise dotnet-sdk-10.0 (mise needs ppa:jdxcode/mise).
|
||||
command -v claude >/dev/null || [[ -x ~/.local/bin/claude ]] || curl -fsSL https://claude.ai/install.sh | bash
|
||||
|
||||
# ---------------------------------------------------------------------------------------
|
||||
step "Data drive + server-marvin share"
|
||||
sudo mkdir -p "$DATA_MNT" "$MARVIN_MNT"
|
||||
if ! grep -q "$DATA_UUID" /etc/fstab; then
|
||||
echo "UUID=$DATA_UUID $DATA_MNT ext4 defaults,nofail,x-gvfs-show,x-gvfs-name=Data 0 2" \
|
||||
| sudo tee -a /etc/fstab >/dev/null
|
||||
fi
|
||||
sudo blkid -U "$DATA_UUID" >/dev/null || warn "Data drive ($DATA_UUID) not found — fstab entry is nofail, so boot is fine"
|
||||
|
||||
if [[ ! -f $MARVIN_CREDS ]]; then
|
||||
read -rp "server-marvin SMB username: " smb_user
|
||||
read -rsp "server-marvin SMB password: " smb_pass; echo
|
||||
sudo install -d -m 0755 /etc/samba
|
||||
printf 'username=%s\npassword=%s\n' "$smb_user" "$smb_pass" \
|
||||
| sudo install -m 600 /dev/stdin "$MARVIN_CREDS"
|
||||
unset smb_pass
|
||||
fi
|
||||
if ! grep -q "$MARVIN_MNT" /etc/fstab; then
|
||||
echo "$MARVIN_SHARE $MARVIN_MNT cifs credentials=$MARVIN_CREDS,uid=$(id -u),gid=$(id -g),iocharset=utf8,vers=3.0,x-systemd.automount,_netdev,nofail 0 0" \
|
||||
| sudo tee -a /etc/fstab >/dev/null
|
||||
fi
|
||||
sudo systemctl daemon-reload
|
||||
sudo mount -a || warn "a mount failed — check 'sudo mount -a' (is server-marvin up? right password?)"
|
||||
|
||||
# ---------------------------------------------------------------------------------------
|
||||
step "Small carry-overs from Bazzite"
|
||||
# Xbox controllers over Bluetooth (Bazzite set this as a kernel argument)
|
||||
echo 'options bluetooth disable_ertm=1' | sudo tee /etc/modprobe.d/bluetooth-xbox.conf >/dev/null
|
||||
|
||||
step "Done"
|
||||
cat <<EOF
|
||||
Reboot now (NVIDIA driver + docker/kvm groups take effect), then:
|
||||
scripts/restore.sh
|
||||
EOF
|
||||
Reference in New Issue
Block a user