Devices#

PC Master Race

  • OS: Kubuntu 26.04 LTS
  • CPU: AMD Ryzen 5 3600
  • GPU: AMD Radeon RX 6800 16 GB
  • RAM: 32 GB (4×8 GB GeIL Super Luce DDR4 3200 MHz)
  • NVMe: 1 TB (2×512 GB Adata XPG Spectrix S40G)
  • Motherboard: ASUS TUF Gaming X570-PRO (Wi-Fi)
  • Mouse: Logitech G305
  • Keyboard: HyperX Alloy Origins Core with Razer Pink PBT keycaps
  • Headphones: Audio-Technica ATH-M50x with FiiO BTA10 and Sony Inzone H9

Raspberry Pi 4 Model B

Apple MacBook Air M1 2020

Samsung Galaxy S22 Ultra

Base installation#

Kubuntu 26.04 installed in UEFI mode with:

  • Btrfs
  • Swap file
  • LUKS enabled

Layout: subvols /@, /@home, and /@swap, swap file at /swap/swapfile, disk encrypted with LUKS.

BIOS#

  • Load optimized defaults
  • Set RAM to 3200 MHz with DOCP/XMP
  • Enable Above 4G Decoding
  • Enable Resizable BAR
  • Enable SVM Mode / AMD-V
  • Enable Secure Boot
  • Disable CSM
  • Tune fan curves for silence

Linux#

GRUB#

sudo nvim /etc/default/grub

Add preempt=full pcie_aspm=off to GRUB_CMDLINE_LINUX_DEFAULT, without deleting what’s already there.

Example with LUKS:

GRUB_CMDLINE_LINUX_DEFAULT="cryptdevice=UUID=blablabla:luks-blablabla root=/dev/mapper/luks-blablabla splash preempt=full pcie_aspm=off"
sudo update-grub
  • preempt=full - lower scheduling latency.
  • pcie_aspm=off - workaround for Intel AX200 WiFi stuck in D3cold.
  • I don’t use quiet because I prefer seeing more info at boot.
  • cryptdevice=... and root=... depend on your installation.

LUKS performance#

sudo dmsetup table

sudo cryptsetup --perf-no_read_workqueue --perf-no_write_workqueue --allow-discards --persistent refresh luks-blablabla
  • no_read_workqueue / no_write_workqueue - lower latency on NVMe.
  • allow-discards - enables TRIM on SSD.

Btrfs mounts#

Kubuntu already creates the subvols and swap file. /tmp already comes as tmpfs through systemd. I only change mount options:

sudo nvim /etc/fstab

On / and /home, remove autodefrag if present and add compress=zstd:

/dev/mapper/luks-blablabla /     btrfs subvol=/@,defaults,noatime,compress=zstd 0 0
/dev/mapper/luks-blablabla /home btrfs subvol=/@home,defaults,noatime,compress=zstd 0 0
  • noatime - fewer writes.
  • compress=zstd - transparent compression.

sysctl#

sudo tee /etc/sysctl.d/99-performance.conf > /dev/null << 'EOF'
kernel.nmi_watchdog = 0
kernel.watchdog = 0
net.ipv4.tcp_fastopen = 3
vm.dirty_ratio = 10
vm.dirty_background_ratio = 5
EOF && \
sudo tee /etc/sysctl.d/99-vm-zram.conf > /dev/null << 'EOF'
vm.swappiness = 150
vm.vfs_cache_pressure = 50
vm.page-cluster = 0
vm.watermark_scale_factor = 100
vm.compaction_proactiveness = 50
EOF && \
sudo sysctl --system

zram#

sudo apt install systemd-zram-generator && \
sudo tee /etc/systemd/zram-generator.conf > /dev/null << 'EOF'
[zram0]
zram-size = ram / 2
compression-algorithm = zstd
swap-priority = 100
EOF && \
sudo systemctl daemon-reload && sudo systemctl start dev-zram0.swap

Btrfs swap file#

sudo swapoff /swap/swapfile && \
  sudo rm -f /swap/swapfile && \
  sudo btrfs filesystem mkswapfile --size 4G /swap/swapfile && \
  sudo swapon /swap/swapfile

Disk swap stays as a fallback when zram fills up.

OOM#

sudo apt install systemd-oomd && \
  sudo systemctl enable --now systemd-oomd.service

CPU#

powerprofilesctl set performance
  • amd-pstate active + governor performance + EPP performance
  • transparent_hugepage=madvise is already default.
  • NVMe scheduler none is already the normal default for NVMe.

Intel AX200 WiFi#

sudo tee /etc/modprobe.d/iwlwifi-fix.conf > /dev/null << 'EOF'
options iwlwifi power_save=0
options iwlmvm power_scheme=1
EOF
sudo tee /etc/NetworkManager/conf.d/99-disable-wifi-powersave.conf > /dev/null << 'EOF'
[connection]
wifi.powersave=2
EOF && sudo systemctl restart NetworkManager

KWin AMDGPU#

KDE only. Only if you get a black screen during boot.

sudo mkdir -p /etc/systemd/system/sddm.service.d && \
sudo tee /etc/systemd/system/sddm.service.d/restart-limits.conf > /dev/null << 'EOF'
[Unit]
StartLimitIntervalSec=30
StartLimitBurst=5

[Service]
ExecStartPre=/usr/bin/sleep 3
Restart=on-failure
RestartSec=2
EOF && \
sudo systemctl daemon-reload

NetworkManager#

sudo systemctl disable --now NetworkManager-wait-online.service
sudo tee /etc/NetworkManager/conf.d/99-mac-address-policy.conf > /dev/null << 'EOF'
[device]
wifi.scan-rand-mac-address=yes

[connection]
wifi.cloned-mac-address=stable
ethernet.cloned-mac-address=preserve
EOF && sudo systemctl restart NetworkManager

Bluetooth restart#

sudo rfkill unblock all
sudo systemctl restart bluetooth
sudo modprobe -r btusb
sudo modprobe btusb

Packages#

apt#

sudo apt install \
  7zip adb atuin audacity bleachbit ble.sh build-essential buildah clang \
  bat ca-certificates criu curl ddcui ddcutil easyeffects \
  fastboot ffmpeg flatpak fzf gamemode gammastep gh ghostty git \
  gnupg golang-go gwenview handbrake hashcat hugo isoimagewriter kcalc \
  kde-config-flatpak lazygit libvirt-daemon-system \
  mpv neovim nmap okular openrgb \
  plasma-discover-backend-flatpak pipx podman podman-docker python3 \
  python3-dev python3-full python3-venv \
  qemu-system-x86 ssh sshpass ripgrep starship thefuck timeshift tmux \
  torbrowser-launcher tree ufw unrar unzip virt-manager vlc wget \
  wireshark yt-dlp zoxide

User permissions#

sudo usermod -aG kvm,libvirt,wireshark "$USER"

Log out and back in.

ROCm#

sudo apt install rocm rocm-podman-support && \
  sudo usermod -aG render,video "$USER"

Log out and back in.

APT security auto-updates#

sudo apt install unattended-upgrades && \
sudo tee /etc/apt/apt.conf.d/20auto-upgrades > /dev/null << 'EOF'
APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Download-Upgradeable-Packages "1";
APT::Periodic::AutocleanInterval "7";
APT::Periodic::Unattended-Upgrade "1";
EOF

Ubuntu Pro#

Get your token at https://ubuntu.com/pro/dashboard.

sudo pro attach <YOUR_TOKEN>
pro status

External repos#

Brave#

sudo curl -fsSLo /usr/share/keyrings/brave-browser-archive-keyring.gpg \
  https://brave-browser-apt-release.s3.brave.com/brave-browser-archive-keyring.gpg && \
sudo curl -fsSLo /etc/apt/sources.list.d/brave-browser-release.sources \
  https://brave-browser-apt-release.s3.brave.com/brave-browser.sources && \
sudo apt update && sudo apt install brave-browser

Firefox#

sudo apt remove firefox
snap list firefox >/dev/null 2>&1 && sudo snap remove firefox
snap list thunderbird >/dev/null 2>&1 && sudo snap remove thunderbird

sudo install -d -m 0755 /etc/apt/keyrings && \
wget https://packages.mozilla.org/apt/repo-signing-key.gpg -O- \
  | sudo tee /etc/apt/keyrings/packages.mozilla.org.asc > /dev/null && \
cat <<EOF | sudo tee /etc/apt/sources.list.d/mozilla.sources
Types: deb
URIs: https://packages.mozilla.org/apt
Suites: mozilla
Components: main
Signed-By: /etc/apt/keyrings/packages.mozilla.org.asc
EOF && \
cat <<EOF | sudo tee /etc/apt/preferences.d/mozilla
Package: *
Pin: origin packages.mozilla.org
Pin-Priority: 1000
EOF && \
sudo apt update && sudo apt install firefox

Tailscale#

sudo mkdir -p --mode=0755 /usr/share/keyrings && \
curl -fsSL https://pkgs.tailscale.com/stable/ubuntu/resolute.noarmor.gpg \
  | sudo tee /usr/share/keyrings/tailscale-archive-keyring.gpg > /dev/null && \
curl -fsSL https://pkgs.tailscale.com/stable/ubuntu/resolute.tailscale-keyring.list \
  | sudo tee /etc/apt/sources.list.d/tailscale.list && \
sudo apt update && sudo apt install tailscale && sudo tailscale up

Antigravity#

sudo mkdir -p /etc/apt/keyrings && \
curl -fsSL https://us-central1-apt.pkg.dev/doc/repo-signing-key.gpg | \
  sudo gpg --dearmor --yes -o /etc/apt/keyrings/antigravity-repo-key.gpg && \
echo "deb [signed-by=/etc/apt/keyrings/antigravity-repo-key.gpg] https://us-central1-apt.pkg.dev/projects/antigravity-auto-updater-dev/ antigravity-debian main" | \
  sudo tee /etc/apt/sources.list.d/antigravity.list > /dev/null && \
sudo apt update && sudo apt install antigravity

Package managers and runtimes#

Homebrew#

/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" && \
eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)" && \
brew install fnm topgrade uv

Topgrade auto-update#

mkdir -p ~/.config

cat > ~/.config/topgrade.toml << 'EOF'
[misc]
assume_yes = true
cleanup = true
no_retry = true
notify_end = "on_failure"
disable = ["system", "snap"]
EOF

mkdir -p ~/.config/systemd/user

cat > ~/.config/systemd/user/topgrade.service << 'EOF'
[Unit]
Description=Update user-level packages with Topgrade

[Service]
Type=oneshot
Environment=PATH=%h/.local/bin:%h/.bun/bin:%h/.cargo/bin:/home/linuxbrew/.linuxbrew/bin:/home/linuxbrew/.linuxbrew/sbin:/usr/local/bin:/usr/bin:/bin
ExecStart=/home/linuxbrew/.linuxbrew/bin/topgrade
EOF

cat > ~/.config/systemd/user/topgrade.timer << 'EOF'
[Unit]
Description=Run Topgrade automatically

[Timer]
OnCalendar=daily
Persistent=true
RandomizedDelaySec=1h

[Install]
WantedBy=timers.target
EOF

systemctl --user daemon-reload && systemctl --user enable --now topgrade.timer

npm global#

eval "$(fnm env --use-on-cd --shell bash)" && \
fnm install --lts --use && \
fnm default "$(fnm current)" && \
npm install -g @google/gemini-cli @openai/codex opencode-ai

Script installs#

# Bun
curl -fsSL https://bun.sh/install | bash

# Rust / Cargo
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

Apps#

Nerd Fonts#

brew install --cask font-hack-nerd-font font-ubuntu-mono-nerd-font && fc-cache -fv

Flatpak#

flatpak remote-add --if-not-exists flathub \
  https://flathub.org/repo/flathub.flatpakrepo

flatpak install flathub \
  com.github.tchx84.Flatseal \
  com.github.PintaProject.Pinta \
  com.obsproject.Studio \
  com.obsproject.Studio.Plugin.OBSVkCapture//stable \
  com.spotify.Client \
  com.stremio.Stremio \
  com.usebottles.bottles \
  com.vysp3r.ProtonPlus \
  dev.vencord.Vesktop \
  io.github.flattool.Warehouse \
  io.github.hedge_dev.hedgemodmanager \
  io.podman_desktop.PodmanDesktop \
  it.mijorus.gearlever \
  net.lutris.Lutris \
  net.retrodeck.retrodeck \
  org.freedesktop.Platform.VulkanLayer.OBSVkCapture//25.08 \
  org.gimp.GIMP \
  org.kde.kdenlive \
  org.kde.krita \
  org.kde.yakuake \
  org.libreoffice.LibreOffice \
  org.localsend.localsend_app \
  org.qbittorrent.qBittorrent \
  org.signal.Signal \
  org.telegram.desktop

Steam#

wget -O /tmp/steam.deb https://cdn.fastly.steamstatic.com/client/installer/steam.deb && \
sudo apt install /tmp/steam.deb && rm /tmp/steam.deb

Google Chrome#

wget "https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb" -O /tmp/chrome.deb && \
sudo apt install /tmp/chrome.deb && rm /tmp/chrome.deb

Android Studio#

url=$(curl -s "https://developer.android.com/studio" | grep -o 'https://[^"]*linux[^"]*\.tar\.gz' | head -1) && \
wget -O /tmp/android-studio.tar.gz "$url" && \
tar -xzf /tmp/android-studio.tar.gz -C /tmp && \
sudo rm -rf /opt/android-studio && \
sudo mv /tmp/android-studio /opt/android-studio && \
mkdir -p ~/.local/bin && \
ln -sf /opt/android-studio/bin/studio ~/.local/bin/studio && \
rm /tmp/android-studio.tar.gz

First run:

~/.local/bin/studio

After ~/.local/bin is in PATH:

studio

Inside Android Studio:

Tools > Create Desktop Entry

The Setup Wizard downloads the SDK to ~/Android/Sdk.

Visual Studio Code#

wget -O /tmp/code.deb "https://code.visualstudio.com/sha/download?build=stable&os=linux-deb-x64" && \
sudo apt install /tmp/code.deb && rm /tmp/code.deb

Zed#

curl -f https://zed.dev/install.sh | sh

Trezor Suite#

Download Trezor Suite as an AppImage and manage it with Gear Lever.

Timeshift#

sudo timeshift-gtk

Config:

  • Type: Btrfs
  • Location: same Btrfs system disk
  • Schedule: daily + boot
  • Keep: 3 daily, 3 boot, 2 weekly
  • /home: do not include user data

Shell & terminal#

Ghostty#

mkdir -p ~/.config/ghostty && \
  tee ~/.config/ghostty/config.ghostty > /dev/null << 'EOF'
background-opacity = "0.9"
font-family = "UbuntuMono Nerd Font"
font-size = "14"
theme = "Dark Pastel"
window-height = "32"
window-width = "100"
EOF

bashrc#

Edit ~/.bashrc:

nvim ~/.bashrc

At the very top:

# ble.sh - load first, attach last
[[ $- == *i* && -f /usr/share/blesh/ble.sh ]] && source -- /usr/share/blesh/ble.sh --attach=none

Override defaults:

HISTCONTROL=ignoreboth:erasedups
HISTSIZE=100000
HISTFILESIZE=100000
shopt -s globstar

Add aliases:

alias cat='batcat --paging=never'
alias egrep='grep -E --color=auto'
alias fgrep='grep -F --color=auto'

Delete the PS1 block (chroot, color prompt, xterm title) since starship handles it.

Normal config:

# path helper
path_prepend() {
  [[ -d "$1" ]] || return
  case ":$PATH:" in
    *":$1:"*) ;;
    *) export PATH="$1:$PATH" ;;
  esac
}

# local bin
path_prepend "$HOME/.local/bin"

# android sdk
export ANDROID_HOME="$HOME/Android/Sdk"
export ANDROID_SDK_ROOT="$ANDROID_HOME"
path_prepend "$ANDROID_HOME/cmdline-tools/latest/bin"
path_prepend "$ANDROID_HOME/emulator"
path_prepend "$ANDROID_HOME/platform-tools"

# bun
export BUN_INSTALL="$HOME/.bun"
path_prepend "$BUN_INSTALL/bin"

# homebrew
if [[ -x /home/linuxbrew/.linuxbrew/bin/brew ]]; then
  export HOMEBREW_PREFIX="/home/linuxbrew/.linuxbrew"
  export HOMEBREW_CELLAR="$HOMEBREW_PREFIX/Cellar"
  export HOMEBREW_REPOSITORY="$HOMEBREW_PREFIX/Homebrew"
  path_prepend "$HOMEBREW_PREFIX/bin"
  path_prepend "$HOMEBREW_PREFIX/sbin"
  [[ -z "${MANPATH-}" ]] || export MANPATH=":${MANPATH#:}"
  export INFOPATH="$HOMEBREW_PREFIX/share/info:${INFOPATH:-}"
fi

# fnm
command -v fnm >/dev/null && eval "$(fnm env --use-on-cd --shell bash)"

# rust/cargo
[[ -f "$HOME/.cargo/env" ]] && . "$HOME/.cargo/env"

# starship
command -v starship >/dev/null && eval "$(starship init bash)"

# thefuck - lazy load
fuck() { unset -f fuck; eval "$(thefuck --alias)"; fuck "$@"; }

# fzf
command -v fzf >/dev/null && eval "$(fzf --bash)"

# zoxide
command -v zoxide >/dev/null && eval "$(zoxide init --cmd cd bash)"

# atuin
if command -v atuin >/dev/null; then
  if [[ ${BLE_VERSION-} ]]; then
    eval "$(atuin init bash --disable-up-arrow)"
    ble-bind -x 'C-r' '__atuin_history'
  else
    eval "$(atuin init bash)"
  fi
fi

At the very end:

# ble.sh attach
[[ ! ${BLE_VERSION-} ]] || ble-attach

Services and networking#

Podman socket#

systemctl --user enable --now podman.socket

OpenCode server#

mkdir -p ~/.local/bin ~/.config/systemd/user

cat > ~/.local/bin/opencode-serve << 'EOF'
#!/usr/bin/env bash
set -euo pipefail

export PATH="$HOME/.local/bin:$HOME/.bun/bin:$HOME/.cargo/bin:/home/linuxbrew/.linuxbrew/bin:/home/linuxbrew/.linuxbrew/sbin:/usr/local/bin:/usr/bin:/bin"

[[ -x /home/linuxbrew/.linuxbrew/bin/brew ]] && eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)"
command -v fnm >/dev/null && eval "$(fnm env --use-on-cd --shell bash)"

exec opencode serve --mdns
EOF

chmod +x ~/.local/bin/opencode-serve

cat > ~/.config/systemd/user/opencode-serve.service << 'EOF'
[Unit]
Description=OpenCode serve

[Service]
Type=simple
Environment=PATH=%h/.local/bin:%h/.bun/bin:%h/.cargo/bin:/home/linuxbrew/.linuxbrew/bin:/home/linuxbrew/.linuxbrew/sbin:/usr/local/bin:/usr/bin:/bin
ExecStart=%h/.local/bin/opencode-serve
Restart=always
RestartSec=3

[Install]
WantedBy=default.target
EOF

systemctl --user daemon-reload && systemctl --user enable --now opencode-serve.service

SSH#

sudo systemctl enable --now ssh

UFW#

sudo ufw default deny incoming && \
  sudo ufw default allow outgoing && \
  sudo ufw allow OpenSSH && \
  sudo ufw allow kdeconnect && \
  sudo ufw enable

Gaming#

Eden#

Download Eden (Nintendo Switch emulator) as an AppImage and manage it with Gear Lever. Use the amd64 PGO build for best performance.

Sonic Unleashed Recompiled#

Download the Flatpak from Unleashed Recompiled and install it. You need the Sonic Unleashed Xbox 360 game files (US or EU), title update, and optionally the DLC (recommended, includes high quality lighting).

wget -O /tmp/UnleashedRecomp-Flatpak.zip \
  https://github.com/hedge-dev/UnleashedRecomp/releases/latest/download/UnleashedRecomp-Flatpak.zip && \
  unzip -o /tmp/UnleashedRecomp-Flatpak.zip -d /tmp/UnleashedRecomp && \
  flatpak install /tmp/UnleashedRecomp/*.flatpak && \
  rm -rf /tmp/UnleashedRecomp /tmp/UnleashedRecomp-Flatpak.zip

Steam#

  • Enable Steam Play
  • Launch options per game:
gamemoderun %command%
  • Install Proton-CachyOS or Proton-GE with ProtonPlus

Half-Life / Portal / Counter-Strike#

-vulkan -novid -fullscreen

Sonic Adventure#

Use Adventure Mods to configure mods for Sonic Adventure DX and Sonic Adventure 2 on Linux. Detects Steam installations, installs mod managers, mods, dependencies, presets and base configuration.

Download the AppImage from GitHub Releases and install it with Gear Lever.

GTA IV#

Install Grand Theft Auto IV: The Complete Edition from Steam.

Install FusionFix: download GTAIV.EFLC.FusionFix.zip and extract it to the game’s root folder, where the .exe is.

Steam launch options:

WINEDLLOVERRIDES="dinput8=n,b" %command%

Git#

git config --global user.name "astrovm"
git config --global user.email "[email protected]"
git config --global init.defaultBranch main
git config --global pull.rebase true
git config --global rebase.autoStash true
git config --global core.autocrlf input
git config --global core.pager batcat
git config --global fetch.prune true
git config --global rerere.enabled true

ssh-keygen -t ed25519 -C "[email protected]"
eval "$(ssh-agent -s)" && \
ssh-add ~/.ssh/id_ed25519 && \
cat ~/.ssh/id_ed25519.pub

Paste the public key into https://github.com/settings/ssh.

Brave extensions#