Dispositivos#

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
  • Teclado: HyperX Alloy Origins Core con keycaps Razer Pink PBT
  • Auriculares: Audio-Technica ATH-M50x con FiiO BTA10 y Sony Inzone H9

Instalación base#

Kubuntu 26.04 instalado en modo UEFI. Los dos NVMe usan LUKS2.

Disco del sistema:

  • Partición EFI de 1 GiB
  • /boot ext4 de 4 GiB
  • LUKS2 -> LVM
  • / Btrfs de 96 GiB con los subvolúmenes /@ y /@swap
  • /home XFS de 370 GiB sobre un pool VDO físico de 357 GiB con compresión y deduplicación
  • Swap file de 4 GiB en /swap/swapfile

Disco de datos:

  • LUKS2 -> LVM VDO -> /data XFS de 470 GiB
  • Pool VDO físico de 453 GiB con compresión y deduplicación
  • Desbloqueo automático con una clave guardada en el disco cifrado del sistema; passphrase de recuperación separada

BIOS#

  • Cargar valores predeterminados optimizados
  • Configurar RAM a 3200 MHz con DOCP/XMP
  • Habilitar Above 4G Decoding
  • Habilitar Resizable BAR
  • Habilitar SVM Mode / AMD-V
  • Deshabilitar Secure Boot
  • Deshabilitar CSM
  • Configurar los coolers para que hagan el menor ruido posible

Linux#

GRUB#

sudo tee /etc/default/grub.d/99-preempt.cfg > /dev/null << 'EOF'
GRUB_CMDLINE_LINUX_DEFAULT="$GRUB_CMDLINE_LINUX_DEFAULT preempt=full"
EOF

sudo update-grub

LUKS performance#

Las opciones persistentes están en /etc/crypttab:

system_crypt UUID=<system-luks-uuid> none luks,discard,no-read-workqueue,no-write-workqueue
data_crypt UUID=<data-luks-uuid> /etc/cryptsetup-keys.d/data_crypt.key luks,discard,no-read-workqueue,no-write-workqueue,nofail

Para verificar los mappings activos:

sudo cryptsetup status system_crypt
sudo cryptsetup status data_crypt
  • no-read-workqueue / no-write-workqueue saltean las workqueues internas de dm-crypt en los NVMe.
  • discard pasa los descartes a través de LUKS. Ayuda al SSD y a VDO a recuperar bloques borrados, pero expone patrones de asignación.
  • La clave del disco de datos está protegida en reposo por el LUKS del disco del sistema.

Filesystems y VDO#

Entradas relevantes de /etc/fstab:

UUID=<root-btrfs-uuid> /      btrfs subvol=/@,defaults,noatime,compress=zstd:3,discard=async 0 0
UUID=<home-xfs-uuid>   /home  xfs   defaults,noatime 0 2
UUID=<root-btrfs-uuid> /swap  btrfs subvol=/@swap,defaults,noatime 0 0
/swap/swapfile         none   swap  defaults 0 0
UUID=<data-xfs-uuid>   /data  xfs   defaults,noatime,nofail,x-systemd.device-timeout=30s 0 2

Los dos filesystems XFS tienen compresión y deduplicación VDO por debajo. Cada pool VDO usa inicialmente el 95% del espacio libre de su volume group. Los extents restantes permiten que LVM extienda el pool si aumenta mucho el uso físico.

# /etc/lvm/lvm.conf
activation {
  vdo_pool_autoextend_threshold=70
  vdo_pool_autoextend_percent=5
}

La extensión automática requiere que dmeventd monitoree cada pool VDO. Verificar que seg_monitor muestre monitored en la salida de lvs.

sudo lvs -a -o name,vg_name,lv_size,segtype,data_percent,seg_monitor,vdo_compression,vdo_deduplication
sudo vdostats --human-readable

sysctl#

sudo tee /etc/sysctl.d/99-zram.conf > /dev/null << 'EOF'
vm.swappiness = 150
EOF

sudo tee /etc/sysctl.d/99-inotify.conf > /dev/null << 'EOF'
fs.inotify.max_user_instances = 8192
fs.inotify.max_user_watches = 524288
fs.inotify.max_queued_events = 16384
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

Swap file Btrfs#

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

El swap en disco queda como fallback cuando zram se llena.

OOM#

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

CPU#

powerprofilesctl set performance

WiFi Intel AX200#

sudo mkdir -p /etc/modprobe.d && \
  sudo tee /etc/modprobe.d/iwlwifi-fix.conf > /dev/null << 'EOF'
options iwlmvm power_scheme=1
EOF

NetworkManager#

sudo tee /etc/NetworkManager/conf.d/99-mac-address-policy.conf > /dev/null << 'EOF'
[connection]
wifi.cloned-mac-address=stable
EOF

sudo systemctl restart NetworkManager

Paquetes#

apt#

apt_packages=(
  # Build and development
  autoconf automake bear build-essential clang cmake
  libfuse-dev libfuse3-dev libtool meson ninja-build pkg-config
  python-is-python3 python3-dev python3-full python3-venv valgrind

  # Shell and CLI
  ble.sh direnv jo thefuck universal-ctags xmlstarlet

  # Networking and security
  aria2 axel hashcat httpie
  nethogs nload nmap redis-tools speedtest-cli ssh sshpass
  torbrowser-launcher tshark whois wireshark

  # Audio, video, and images
  audacity ffmpegthumbnailer gifsicle handbrake mpv optipng pamixer
  pdfgrep playerctl pngquant tidy vlc

  # Containers and virtualization
  buildah cockpit cockpit-podman criu distrobox libvirt-daemon-system podman
  podman-docker podman-toolbox qemu-system-x86 virt-manager

  # Hardware and desktop
  adb brightnessctl ddcui ddcutil fastboot filelight flatpak gamemode ghostty
  kde-config-flatpak openrgb
  plasma-discover-backend-flatpak ydotool

  # Languages and spell checking
  aspell-es fcitx5-mozc hunspell-es hyphen-en-us hyphen-es
  mythes-en-us mythes-es

  # System utilities and maintenance
  antiword bleachbit btop cabextract clamav diffoscope duf expect firejail
  hw-probe hyperfine inotify-tools iotop-c ncdu needrestart nvtop procs
  timeshift trash-cli tree unrar

  # Fun
  cmatrix fortune-mod sl toilet
)

sudo apt install "${apt_packages[@]}"
if command -v fdfind >/dev/null; then
  mkdir -p "$HOME/.local/bin" && \
    ln -sfn "$(command -v fdfind)" "$HOME/.local/bin/fd"
fi

Permisos de usuario#

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

ROCm#

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

Cerrar sesión y volver a entrar.

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#

sudo pro attach
pro status

Repos externos#

extrepo#

extrepo gestiona repositorios externos. Buscá con extrepo search, habilitá con extrepo enable.

sudo apt install extrepo && \
  sudo extrepo enable brave_release librewolf steam tailscale vscode && \
  sudo apt update && \
  sudo apt install brave-browser code librewolf steam tailscale && \
  sudo tailscale up

Gestores y runtimes#

Homebrew#

/bin/bash -c "$(curl --proto '=https' --tlsv1.2 -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" && \
  eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)" && \
  brew install atuin bat cowsay croc editorconfig eza fd fnm gh glab go hugo just \
    lazygit magic-wormhole moreutils neovim pandoc pipx pre-commit ripgrep-all \
    shellcheck shfmt starship tealdeer tmux topgrade ugrep uv yq yt-dlp zoxide

Topgrade config#

mkdir -p "$HOME/.config" && \
  cat > "$HOME/.config/topgrade.toml" << 'EOF'
[misc]
assume_yes = true
cleanup = true
ask_retry = false
notify_end = "on_failure"
EOF

pnpm global#

eval "$(fnm env --use-on-cd --shell bash)" && \
  fnm install --lts --use && \
  fnm default "$(fnm current)" && \
  (command -v corepack >/dev/null || npm install --global corepack@latest) && \
  corepack enable pnpm && \
  corepack install --global pnpm@latest && \
  mkdir -p "$HOME/.local/share/pnpm" && \
  pnpm config set global-bin-dir "$HOME/.local/share/pnpm" --location=global

Seguridad npm / pnpm#

Hardening contra supply chain attacks: bloquear scripts de instalación y evitar paquetes recién publicados.

npm: no ejecutar scripts de terceros

npm config set ignore-scripts true --location=user

Bun: bloquear scripts y paquetes recién publicados

cat > "$HOME/.bunfig.toml" << 'EOF'
[install]
ignoreScripts = true
minimumReleaseAge = 86400
EOF

Con esto, npm no ejecuta preinstall ni postinstall de dependencias. Bun bloquea scripts y paquetes publicados hace menos de 1 día (86400 segundos). pnpm 11+ ya aplica una política integrada de 1 día en modo no estricto, así que no hace falta una configuración global extra.

Scripts#

Bun#

curl --proto '=https' --tlsv1.2 -fsSL https://bun.sh/install | bash

Rust / Cargo#

curl --proto '=https' --tlsv1.2 -fsSL 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.isoimagewriter 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

El Setup Wizard descarga el SDK en ~/Android/Sdk.

Zed#

curl --proto '=https' --tlsv1.2 -fsSL https://zed.dev/install.sh | sh

Codex#

curl --proto '=https' --tlsv1.2 -fsSL https://chatgpt.com/codex/install.sh | sh

Codex Desktop#

curl -fsSL -o /tmp/chatgpt.deb \
  https://persistent.oaistatic.com/codex-app-prod/linux/deb/latest/chatgpt_amd64.deb && \
  sudo apt install /tmp/chatgpt.deb && \
  rm -- /tmp/chatgpt.deb

Trezor Suite#

Descargar Trezor Suite como AppImage y manejarlo con Gear Lever.

Timeshift#

sudo timeshift-gtk

Config:

  • Tipo: Btrfs
  • Ubicación: root Btrfs del disco del sistema
  • Schedule: diario + semanal + boot
  • Mantener: 3 diarios, 3 boot, 2 semanales
  • /home y /data: no se incluyen; los dos son filesystems XFS separados

Shell y terminal#

Ghostty#

mkdir -p "$HOME/.config/ghostty" && \
  tee "$HOME/.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 0
  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"
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
  eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)"
fi

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

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

# solana
path_prepend "$HOME/.local/share/solana/install/active_release/bin"

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

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

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

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

bashrc#

~/.bashrc:

# ble.sh - load first, attach last
[[ $- == *i* && -r /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 0 ;;
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)"

if [ -x /usr/bin/dircolors ]; then
  if [ -r "$HOME/.dircolors" ]; then
    eval "$(dircolors -b "$HOME/.dircolors")"
  else
    eval "$(dircolors -b)"
  fi

  alias grep='grep --color=auto'
  alias egrep='grep -E --color=auto'
  alias fgrep='grep -F --color=auto'
fi

# aliases
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 [ -r "$HOME/.bash_aliases" ]; then
  . "$HOME/.bash_aliases"
fi

if ! shopt -oq posix; then
  if [ -r /usr/share/bash-completion/bash_completion ]; then
    . /usr/share/bash-completion/bash_completion
  elif [ -r /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
if command -v thefuck >/dev/null; then
  fuck() {
    unset -f fuck
    eval "$(thefuck --alias)"
    fuck "$@"
  }
fi

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

# zoxide
command -v zoxide >/dev/null && eval "$(zoxide init 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

# grok completion
command -v grok >/dev/null && [[ -r "$HOME/.grok/completions/bash/grok.bash" ]] && source "$HOME/.grok/completions/bash/grok.bash"

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

Servicios y red#

Podman socket#

systemctl --user enable --now podman.socket

SSH#

sudo systemctl enable --now ssh

UFW#

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

Gaming#

Eden#

Descargá Eden (emulador de Nintendo Switch) como AppImage y manejalo con Gear Lever. Usá el build amd64 PGO para mejor performance.

Sonic Unleashed Recompiled#

Descargá el Flatpak de Unleashed Recompiled e instalalo. Necesitás los archivos del Sonic Unleashed de Xbox 360 (US o EU), el title update, y opcionalmente el DLC (recomendado, incluye iluminación de alta calidad).

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#

  • Habilitar Steam Play
  • Opciones de lanzamiento por juego:
gamemoderun %command%
  • Instalar Proton-CachyOS o Proton-GE con ProtonPlus

Half-Life / Portal / Counter-Strike#

-vulkan -novid -fullscreen

Sonic Adventure#

Usar Adventure Mods para configurar mods de Sonic Adventure DX y Sonic Adventure 2 en Linux.

Instalar el Flatpak:

flatpak install https://flatpak.4st.li/io.github.astrovm.AdventureMods.flatpakref

Abrir Adventure Mods y seguir el asistente de configuración.

GTA IV#

Instalar Grand Theft Auto IV: The Complete Edition desde Steam.

Instalar FusionFix: descargar GTAIV.EFLC.FusionFix.zip y extraerlo en la carpeta raíz del juego, donde está el .exe.

Opciones de lanzamiento en 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 bat && \
  git config --global fetch.prune true && \
  git config --global rerere.enabled true

Exigí una referencia explícita al hacer push:

git config --global push.default nothing

Usá un hook global de pre-push para impedir pushes directos a main y master:

mkdir -p "$HOME/.config/git/hooks"
git config --global core.hooksPath "$HOME/.config/git/hooks"
cat > "$HOME/.config/git/hooks/pre-push" <<'EOF'
#!/bin/sh

while read local_ref local_oid remote_ref remote_oid; do
    case "$remote_ref" in
        refs/heads/main|refs/heads/master)
            echo "Blocked: direct pushes to ${remote_ref#refs/heads/} are not allowed." >&2
            echo "Create a branch and open a pull request instead." >&2
            exit 1
            ;;
    esac
done

exit 0
EOF
chmod +x "$HOME/.config/git/hooks/pre-push"
ssh-keygen -t ed25519 -C "[email protected]" && \
  eval "$(ssh-agent -s)" && \
  ssh-add "$HOME/.ssh/id_ed25519" && \
  cat "$HOME/.ssh/id_ed25519.pub"

Pegar la clave pública en https://github.com/settings/ssh.

Extensiones de Brave#