设备#

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)
  • 主板: ASUS TUF Gaming X570-PRO (Wi-Fi)
  • 鼠标: Logitech G305
  • 键盘: HyperX Alloy Origins Core,配 Razer Pink PBT 键帽
  • 耳机: Audio-Technica ATH-M50x 配 FiiO BTA10,以及 Sony Inzone H9

Raspberry Pi 4 Model B

Apple MacBook Air M1 2020

Samsung Galaxy S22 Ultra

基础安装#

Kubuntu 26.04 用 UEFI 模式安装:

  • Btrfs
  • Swap file
  • 启用 LUKS

布局:子卷 /@/@home/@swap,swap file 在 /swap/swapfile,磁盘用 LUKS 加密。

BIOS#

  • 加载优化默认值
  • 用 DOCP/XMP 把内存设到 3200 MHz
  • 启用 Above 4G Decoding
  • 启用 Resizable BAR
  • 启用 SVM Mode / AMD-V
  • 启用 Secure Boot
  • 禁用 CSM
  • 调风扇曲线,尽量安静

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 - 降低调度延迟。
  • pcie_aspm=off - 修 Intel AX200 WiFi 卡在 D3cold 的问题。
  • 不用 quiet,因为我想开机时看到更多信息。
  • cryptdevice=...root=... 每台机器都不一样。

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 - NVMe 上延迟更低。
  • allow-discards - 在 SSD 上启用 TRIM。

Btrfs mounts#

Kubuntu 已经创建好子卷和 swap file。/tmp 已经由 systemd 放在 tmpfs。我只改 mount options:

sudo nvim /etc/fstab

//home 上,如果有 autodefrag 就删掉,再加 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 - 少写点。
  • compress=zstd - 透明压缩。

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

磁盘 swap 留作 zram 满了之后的 fallback。

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 对 NVMe 来说通常已经是默认值。

XanMod 内核#

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。开机黑屏的官方修复(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 限制#

增加文件监视器实例,用于 IDE 和开发工具:

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

软件包#

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

用户权限#

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

注销重新登录。

ROCm#

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

注销重新登录。

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#

https://ubuntu.com/pro/dashboard 获取令牌。

sudo pro attach <你的令牌>
pro status

外部仓库#

extrepo#

extrepo 是 Debian 维护的外部仓库管理工具。不用从网上下载脚本然后用 root 跑,直接从审核过的列表里启用,GPG 密钥和仓库配置都已经配好了。用 extrepo search 搜索,用 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

包管理器和运行时#

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 用户环境#

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 安全加固#

针对供应链攻击的 hardening:阻止安装脚本,避开刚发布的包。

# npm: 不让第三方脚本执行
cat > ~/.npmrc << 'EOF'
ignore-scripts=true
EOF

# pnpm: 拒绝发布不到1天的包
pnpm config set minimumReleaseAge 1440 --location=global

# bun: 堵住脚本和刚发布的包
cat > ~/.bunfig.toml << 'EOF'
[install]
ignoreScripts=true
minimumReleaseAge=86400
EOF

这样 npm 不会执行依赖里的 preinstallpostinstall。pnpm 会等包发布满 1 天再接受(1440 分钟),bun 也一样,只是用 86400 秒来配。pnpm 11+ 本来就带这类攻击的防护。

脚本安装#

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

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

应用#

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

Setup Wizard 会把 SDK 下载到 ~/Android/Sdk

Zed#

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

Codex Desktop#

从 macOS 官方 DMG 做出来的非官方 Codex Desktop Linux build: https://github.com/ilysenko/codex-desktop-linux

用原生包安装(Kubuntu/Ubuntu 上是 .deb),顺手打开 Computer Use UI、Zed opener、remote/mobile:

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 会装依赖、下载 Codex.dmg、生成 codex-app/、打原生包并安装。依赖已经有了就用 make install-native

Computer Use 要能发输入,给用户加进 input 组之后要退出登录再进来。

kde-authorized 这条会让没有 app_id 的本机 app 跳过 KDE Remote Control 弹窗。省事,但范围比较大。

Trezor Suite#

Trezor Suite 下载成 AppImage,用 Gear Lever 管理。

Timeshift#

sudo timeshift-gtk

配置:

  • 类型:Btrfs
  • 位置:和系统同一个 Btrfs 磁盘
  • 调度:每日 + 启动时
  • 保留:3 个每日、3 个启动、2 个每周
  • /home: 不包含用户数据

Shell和终端#

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

服务和网络#

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

游戏#

Eden#

Eden(Nintendo Switch 模拟器)下载 AppImage,用 Gear Lever 管理。选 amd64 PGO 版本性能最好。

Sonic Unleashed Recompiled#

Unleashed Recompiled 下载 Flatpak 安装。需要 Sonic Unleashed Xbox 360 游戏文件(US 或 EU),title update,DLC 可选(强烈推荐,包含高质量光照)。

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#

  • 启用 Steam Play
  • 每个游戏设置启动选项:
gamemoderun %command%
  • 用 ProtonPlus 安装 Proton-CachyOS 或 Proton-GE

Half-Life / Portal / Counter-Strike#

-vulkan -novid -fullscreen

Sonic Adventure#

Adventure Mods 给 Linux 上的 Sonic Adventure DXSonic Adventure 2 配置 mod。自动检测 Steam 安装,安装 mod manager、mod、依赖、预设和基础配置。

GitHub Releases 下载 AppImage,用 Gear Lever 安装。

GTA IV#

从 Steam 安装 Grand Theft Auto IV: The Complete Edition

安装 FusionFix:下载 GTAIV.EFLC.FusionFix.zip,解压到游戏根目录(.exe 所在的位置)。

Steam 启动选项:

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

把公钥贴到 https://github.com/settings/ssh

Brave扩展#