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#

for p in preempt=full pcie_aspm=off; do
  grep -q "$p" /etc/default/grub || sudo sed -i "s/GRUB_CMDLINE_LINUX_DEFAULT=\([\"']\)\(.*\)\1/GRUB_CMDLINE_LINUX_DEFAULT=\1\2 $p\1/" /etc/default/grub
done && 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
  • NVMe scheduler none is already the normal default for NVMe.

XanMod kernel#

sudo install -d -m 0755 /etc/apt/keyrings
wget -qO - https://dl.xanmod.org/archive.key | sudo gpg --dearmor -vo /etc/apt/keyrings/xanmod-archive-keyring.gpg
echo "deb [signed-by=/etc/apt/keyrings/xanmod-archive-keyring.gpg] http://deb.xanmod.org $(lsb_release -sc) main" | sudo tee /etc/apt/sources.list.d/xanmod-release.list
sudo apt update && sudo apt install linux-xanmod-x64v3

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

SDDM AMDGPU#

KDE only. Official fix for black screen on boot (regression in 26.04, LP: #2063143).

sudo mkdir -p /etc/systemd/system/sddm.service.d && \
  sudo tee /etc/systemd/system/sddm.service.d/udev-settle.conf > /dev/null << 'EOF'
[Unit]
After=systemd-udev-settle.service
Wants=systemd-udev-settle.service
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

inotify limits#

Increase file watcher instances for IDEs and development tools:

echo "fs.inotify.max_user_instances = 1024" | sudo tee /etc/sysctl.d/90-inotify.conf
sudo sysctl --system

Packages#

apt#

sudo apt install \
  7zip adb antiword aria2 aspell-es atuin audacity autoconf automake axel bat \
  bear ble.sh bleachbit brightnessctl btop build-essential buildah \
  ca-certificates cabextract clamav clang cmake cmatrix cockpit cockpit-podman cowsay \
  criu curl ddcui ddcutil diffoscope direnv distrobox dnsutils duf \
  editorconfig expect eza fastboot fd-find ffmpeg ffmpegthumbnailer filelight \
  firejail flatpak fortune-mod fzf gamemode gdb gh ghostty gifsicle \
  git glab gnupg golang-go gwenview handbrake hashcat httpie hugo \
  hunspell-en-us hunspell-es hw-probe hyperfine hyphen-en-us hyphen-es \
  inotify-tools iotop-c isoimagewriter jo jq just kcalc kde-config-flatpak \
  lazygit libfuse-dev libfuse3-dev libtool libvirt-daemon-system lolcat \
  magic-wormhole meson moreutils mpv mythes-en-us mythes-es ncdu needrestart \
  neovim nethogs ninja-build nload nmap nvtop okular openrgb optipng pamixer \
  pandoc pdfgrep pipx pkg-config plasma-discover-backend-flatpak playerctl \
  pngquant podman podman-docker podman-toolbox poppler-utils pre-commit procs \
  python-is-python3 python3 python3-dev python3-full python3-venv \
  qemu-system-x86 redis-server redis-tools ripgrep-all shellcheck shfmt sl \
  speedtest-cli ssh sshpass starship tealdeer thefuck tidy timeshift tmux \
  toilet torbrowser-launcher trash-cli tree tshark ufw ugrep universal-ctags \
  unrar unzip valgrind virt-manager vlc wget whois wireshark xmlstarlet ydotool yt-dlp \
  zoxide
ln -s "$(command -v fdfind)" ~/.local/bin/fd

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#

extrepo#

extrepo is Debian’s curated external repo manager. Instead of curling random install scripts and running them as root, you enable repos from a vetted catalog that already has the GPG keys and repo definitions. Search with extrepo search, enable with extrepo enable.

sudo apt install extrepo
sudo extrepo enable brave_release google_chrome librewolf steam tailscale vscode
sudo apt update
sudo apt install brave-browser code google-chrome-stable librewolf steam tailscale
sudo tailscale up

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 anomalyco/tap/opencode codex croc fnm gemini-cli topgrade uv yq

systemd user environment#

mkdir -p ~/.config/environment.d

cat > ~/.config/environment.d/10-user-path.conf << 'EOF'
ANDROID_HOME=$HOME/Android/Sdk
ANDROID_SDK_ROOT=$ANDROID_HOME
BUN_INSTALL=$HOME/.bun
HOMEBREW_CELLAR=/home/linuxbrew/.linuxbrew/Cellar
HOMEBREW_PREFIX=/home/linuxbrew/.linuxbrew
HOMEBREW_REPOSITORY=/home/linuxbrew/.linuxbrew/Homebrew
INFOPATH=/home/linuxbrew/.linuxbrew/share/info:${INFOPATH:-}
PATH=$HOME/.cargo/bin:$HOME/.local/share/pnpm:/home/linuxbrew/.linuxbrew/sbin:/home/linuxbrew/.linuxbrew/bin:$HOME/.bun/bin:$HOME/Android/Sdk/platform-tools:$HOME/Android/Sdk/emulator:$HOME/Android/Sdk/cmdline-tools/latest/bin:$HOME/.local/bin:$HOME/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
PNPM_HOME=$HOME/.local/share/pnpm
EOF

systemctl --user daemon-reload

Topgrade auto-update#

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

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

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

[Service]
Type=oneshot
ExecStart=/home/linuxbrew/.linuxbrew/bin/topgrade --disable system snap restarts clam_av_db
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

pnpm global#

eval "$(fnm env --use-on-cd --shell bash)" && \
  fnm install --lts --use && \
  fnm default "$(fnm current)" && \
  corepack install --global pnpm@latest && \
  mkdir -p ~/.local/share/pnpm && \
  pnpm config set global-bin-dir ~/.local/share/pnpm --location=global

npm / pnpm security#

Hardening against supply chain attacks: block install scripts and avoid newly published packages.

# npm: don't run third-party scripts
cat > ~/.npmrc << 'EOF'
ignore-scripts=true
EOF

# pnpm: reject packages published less than 1 day ago
pnpm config set minimumReleaseAge 1440 --location=global

# bun: block scripts and newly published packages
cat > ~/.bunfig.toml << 'EOF'
[install]
ignoreScripts=true
minimumReleaseAge=86400
EOF

With this, npm won’t run dependency preinstall or postinstall scripts. pnpm waits 1 day before accepting new packages (1440 minutes), and bun does the same with 86400 seconds. pnpm 11+ already ships with defenses for this class of attacks.

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.wwmm.easyeffects \
  com.github.PintaProject.Pinta com.github.tchx84.Flatseal \
  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

Android Studio#

sudo snap install android-studio --classic

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

Zed#

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

Codex Desktop#

Unofficial Linux build of Codex Desktop from the official macOS DMG: https://github.com/ilysenko/codex-desktop-linux.

Install it with the native package (.deb on Kubuntu/Ubuntu), with Computer Use UI, Zed opener, and remote/mobile enabled:

sudo apt install ydotool xdg-desktop-portal-kde
sudo usermod -a -G input "$USER"
systemctl --user enable --now ydotool.service
flatpak permission-set kde-authorized remote-desktop "" yes

git clone https://github.com/ilysenko/codex-desktop-linux.git ~/Documents/codex-desktop-linux
cd ~/Documents/codex-desktop-linux

cat > linux-features/features.json << 'EOF'
{
  "enabled": [
    "open-target-discovery",
    "zed-opener",
    "remote-control-ui",
    "remote-mobile-control"
  ]
}
EOF

mkdir -p ~/.config/codex-desktop
echo '{"codex-linux-computer-use-ui-enabled": true}' > ~/.config/codex-desktop/settings.json

make bootstrap-native

make bootstrap-native installs dependencies, downloads Codex.dmg, generates codex-app/, builds the native package, and installs it. If the dependencies already exist, use make install-native.

For Computer Use input control to work, log out and back in after adding your user to the input group.

The kde-authorized permission avoids KDE’s Remote Control popup for host apps without an app_id. Handy, but broad.

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

profile#

~/.profile:

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

# local bin
path_prepend "$HOME/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

# pnpm
export PNPM_HOME="$HOME/.local/share/pnpm"
path_prepend "$PNPM_HOME"

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

# if running bash
if [ -n "$BASH_VERSION" ]; then
    # include .bashrc if it exists
    if [ -f "$HOME/.bashrc" ]; then
	. "$HOME/.bashrc"
    fi
fi

bashrc#

~/.bashrc:

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

# If not running interactively, don't do anything
case $- in
    *i*) ;;
      *) return;;
esac

HISTCONTROL=ignoreboth:erasedups
shopt -s histappend
HISTSIZE=100000
HISTFILESIZE=100000
shopt -s checkwinsize
shopt -s globstar
[ -x /usr/bin/lesspipe ] && eval "$(SHELL=/bin/sh lesspipe)"

# PS1 is handled by starship (see below)

if [ -x /usr/bin/dircolors ]; then
    test -r ~/.dircolors && eval "$(dircolors -b ~/.dircolors)" || eval "$(dircolors -b)"
    alias grep='grep --color=auto'
    alias egrep='grep -E --color=auto'
    alias fgrep='grep -F --color=auto'
fi

# aliases
alias ls='eza'
alias ll='eza -l'
alias la='eza -la'
alias cat='batcat --paging=never'
alias alert='notify-send --urgency=low -i "$([ $? = 0 ] && echo terminal || echo error)" "$(history|tail -n1|sed -e '\''s/^\s*[0-9]\+\s*//;s/[;&|]\s*alert$//'\'')"'

if [ -f ~/.bash_aliases ]; then
    . ~/.bash_aliases
fi

if ! shopt -oq posix; then
  if [ -f /usr/share/bash-completion/bash_completion ]; then
    . /usr/share/bash-completion/bash_completion
  elif [ -f /etc/bash_completion ]; then
    . /etc/bash_completion
  fi
fi

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

# 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

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

Services and networking#

Podman socket#

systemctl --user enable --now podman.socket

OpenCode server#

mkdir -p ~/.config/systemd/user

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

[Service]
Type=simple
ExecStart=/home/linuxbrew/.linuxbrew/bin/opencode serve --mdns
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#