Debian 13 en portátil: instalación resiliente con LUKS, btrfs y Timeshift
Cuando reinstalé mi portátil quería algo más que una instalación típica. Quería que si un día el sistema dejaba de arrancar pudiera recuperarlo en minutos. Que si metía la pata con una actualización hubiera vuelta atrás. Que si el portátil caía en manos equivocadas los datos estuvieran protegidos. Esta guía es exactamente eso: una instalación de Debian 13 pensada para la resiliencia real, no para el tutorial de turno.
La base es simple pero potente: LUKS2 para cifrar todo el disco, btrfs con subvolúmenes bien separados para que Timeshift pueda hacer snapshots de verdad, y grub-btrfs para que esos snapshots aparezcan directamente en el menú de arranque. Si el sistema revienta, entras al GRUB, seleccionas el snapshot del día anterior y listo.
Nota: Esta guía está probada en un ThinkPad X270 con NVMe de 2 TB. Los comandos son los mismos para cualquier portátil con UEFI. Solo cambia el nombre del dispositivo — en NVMe será /dev/nvme0n1, en SATA será /dev/sda.
🗂️ El esquema de particiones
Antes de empezar, hay que tener claro qué vamos a crear y por qué:
/dev/nvme0n1
├── nvme0n1p1 512 MB FAT32 /boot/efi (EFI — sin cifrar, lo necesita el firmware)
├── nvme0n1p2 1 GB ext4 /boot (GRUB — sin cifrar, más fiable así)
└── nvme0n1p3 ~resto LUKS2 → btrfs
├── @ → /
├── @home → /home
├── @snapshots → /.snapshots
├── @var_log → /var/log
├── @swap → /swap
├── @docker → /var/lib/docker
└── @vms → /var/lib/libvirt/images
El truco está en separar /boot de la partición cifrada. Muchos tutoriales meten GRUB dentro de LUKS y luego tienen problemas. Con /boot sin cifrar el proceso es más fiable y el arranque más rápido.
Los subvolúmenes de btrfs son la clave de la resiliencia: Timeshift hace snapshots del sistema (@) sin tocar Docker (@docker) ni las imágenes de VMs (@vms), que pueden pesar decenas de GB y no tienen sentido incluir en un snapshot del sistema.
💾 Fase 1 — Preparar el USB y la BIOS
Descargar y grabar el USB
Desde cualquier Linux descargamos la ISO de Debian 13 netinst y la grabamos:
wget https://cdimage.debian.org/debian-cd/current/amd64/iso-cd/debian-13.0.0-amd64-netinst.iso
# Verificar que la descarga está íntegra
wget https://cdimage.debian.org/debian-cd/current/amd64/iso-cd/SHA256SUMS
sha256sum -c SHA256SUMS --ignore-missing
# Grabar en el USB — sustituir /dev/sdX por tu USB
sudo dd if=debian-13.0.0-amd64-netinst.iso of=/dev/sdX bs=4M status=progress conv=fsyncNota: conv=fsync asegura que el contenido llega al USB antes de salir. Sin ello puedes arrancar con una imagen incompleta y no entender por qué falla.
Configurar la BIOS
En el X270 se entra pulsando F1 al arrancar. En otros portátiles suele ser Del, F2 o Esc — depende del fabricante.
Ajustes imprescindibles:
| Opción | Valor | Por qué |
|---|---|---|
| Secure Boot | Disabled | Debian no lo soporta por defecto |
| Boot Mode | UEFI Only | Para que use la partición EFI que vamos a crear |
| VT-x / Intel Virtualization | Enabled | Para KVM si luego quieres VMs |
Guardar y al reiniciar pulsar F12 (o el equivalente de tu portátil) para arrancar desde el USB.
🛠️ Fase 2 — Instalador Debian
Arrancamos con Graphical Install y seguimos hasta el paso de particionado. Los primeros pasos son los de siempre:
- Idioma:
Español/ Ubicación:España/ Teclado:Español - Hostname: el que quieras / Dominio: el tuyo o vacío
- Contraseña root: fuerte
- Usuario: el tuyo
Particionado manual
En el paso de particionado elegir Manual y crear la tabla GPT:
Seleccionar el disco → Nueva tabla de particiones → GPT
Partición 1 — EFI (512 MB):
- Tipo:
Partición del sistema EFI - Formato:
FAT32 - Punto de montaje:
/boot/efi
Partición 2 — /boot sin cifrar (1 GB):
- Tipo:
Partición primaria - Formato:
ext4 - Punto de montaje:
/boot
Partición 3 — LUKS con el resto:
- Tipo:
Volumen físico para cifrado - Ir a
Configurar volúmenes cifrados→ seleccionar la partición 3 - Método: LUKS2
- Contraseña: la que se pedirá en cada arranque — que sea buena
- El instalador crea
nvme0n1p3_crypt→ usarlo comobtrfs/ Punto de montaje:/
Continuamos con:
- Sistema base:
linux-image-amd64 - Entorno escritorio: ninguno (lo instalamos después con más control)
- SSH server: sí
- GRUB: instalar en el disco principal (
/dev/nvme0n1)
Reiniciamos. El sistema ya arranca pidiendo la contraseña LUKS.
🌿 Fase 3 — Subvolúmenes btrfs
Hacer justo tras el primer arranque, antes de instalar nada más.
El instalador crea un solo volumen btrfs. Lo restructuramos en subvolúmenes para que Timeshift funcione correctamente y los snapshots tengan sentido.
su -
# Montar la raíz del volumen btrfs (sin subvolumen)
mkdir /mnt/btrfs-root
mount -o subvolid=0 /dev/mapper/nvme0n1p3_crypt /mnt/btrfs-root
# Crear los subvolúmenes
cd /mnt/btrfs-root
btrfs subvolume create @
btrfs subvolume create @home
btrfs subvolume create @snapshots
btrfs subvolume create @var_log
btrfs subvolume create @swap
btrfs subvolume create @docker
btrfs subvolume create @vms
# Copiar el contenido existente a los subvolúmenes correctos
rsync -aAX --exclude=/home --exclude=/var/log \
/mnt/btrfs-root/ /mnt/btrfs-root/@/
rsync -aAX /mnt/btrfs-root/home/ /mnt/btrfs-root/@home/
rsync -aAX /mnt/btrfs-root/var/log/ /mnt/btrfs-root/@var_log/
# Eliminar los directorios originales (ya están en los subvolúmenes)
rm -rf /mnt/btrfs-root/home
rm -rf /mnt/btrfs-root/var/logActualizar /etc/fstab
Necesitamos los UUIDs de las tres particiones:
blkid /dev/nvme0n1p1 # UUID de EFI
blkid /dev/nvme0n1p2 # UUID de /boot
blkid /dev/mapper/nvme0n1p3_crypt # UUID del volumen btrfs (dentro de LUKS)Editamos el fstab del nuevo sistema:
nano /mnt/btrfs-root/@/etc/fstab# EFI
UUID=<uuid-efi> /boot/efi vfat umask=0077 0 1
# /boot sin cifrar
UUID=<uuid-boot> /boot ext4 defaults 0 2
# Subvolúmenes btrfs
UUID=<uuid-crypt> / btrfs noatime,compress=zstd:1,space_cache=v2,subvol=@ 0 0
UUID=<uuid-crypt> /home btrfs noatime,compress=zstd:1,space_cache=v2,subvol=@home 0 0
UUID=<uuid-crypt> /.snapshots btrfs noatime,compress=zstd:1,space_cache=v2,subvol=@snapshots 0 0
UUID=<uuid-crypt> /var/log btrfs noatime,compress=zstd:1,space_cache=v2,subvol=@var_log 0 0
UUID=<uuid-crypt> /swap btrfs noatime,space_cache=v2,subvol=@swap 0 0
UUID=<uuid-crypt> /var/lib/docker btrfs noatime,space_cache=v2,subvol=@docker 0 0
UUID=<uuid-crypt> /var/lib/libvirt/images btrfs nodatacow,space_cache=v2,subvol=@vms 0 0
Nota: nodatacow en @vms es obligatorio si vas a usarlo para VMs. Sin él los discos .qcow2 tienen un rendimiento muy degradado por el Copy-on-Write de btrfs.
Actualizar /etc/crypttab
nano /mnt/btrfs-root/@/etc/crypttab# <nombre> <dispositivo> <keyfile> <opciones>
nvme0n1p3_crypt UUID=<uuid-nvme0n1p3> none luks,discard
discard activa TRIM a través de LUKS — mejora el rendimiento y la vida del SSD. El tradeoff es que revela qué bloques están en uso, algo irrelevante en un portátil personal.
Regenerar initramfs y GRUB
# Montar todo para el chroot
mount -o subvol=@ /dev/mapper/nvme0n1p3_crypt /mnt
mount -o subvol=@home /dev/mapper/nvme0n1p3_crypt /mnt/home
mount -o subvol=@var_log /dev/mapper/nvme0n1p3_crypt /mnt/var/log
mount /dev/nvme0n1p2 /mnt/boot
mount /dev/nvme0n1p1 /mnt/boot/efi
mount --bind /dev /mnt/dev
mount --bind /proc /mnt/proc
mount --bind /sys /mnt/sys
mount --bind /run /mnt/run
chroot /mnt
update-initramfs -u -k all
update-grub
exit
umount -R /mnt
reboot💤 Fase 4 — Swapfile y hibernación
Con btrfs el swapfile tiene sus particularidades. No se puede crear como en ext4 — hay que desactivarle el CoW antes de escribir en él, si no el sistema te avisa de error al intentar activarlo.
su -
# Crear el swapfile sin Copy-on-Write (obligatorio en btrfs)
touch /swap/swapfile
chattr +C /swap/swapfile
dd if=/dev/zero of=/swap/swapfile bs=1M count=65536 # 64 GB
chmod 600 /swap/swapfile
mkswap /swap/swapfile
swapon /swap/swapfile
echo '/swap/swapfile none swap sw 0 0' >> /etc/fstab
swapon --show && free -hConfigurar la hibernación
Para que la hibernación funcione con btrfs el GRUB necesita dos datos: el UUID del volumen y el offset físico del swapfile dentro de btrfs. Este offset es diferente al offset de fichero normal — hay que calcularlo con la herramienta de btrfs.
# Offset físico del swapfile — anotar este número
btrfs inspect-internal map-swapfile -r /swap/swapfile
# UUID del volumen LUKS abierto
blkid /dev/mapper/nvme0n1p3_crypt | grep -o 'UUID="[^"]*"'
nano /etc/default/grubAñadir o modificar esta línea con tus valores:
GRUB_CMDLINE_LINUX="resume=UUID=<uuid-crypt> resume_offset=<offset>"
update-grub
update-initramfs -u -k all
# Probar que funciona — el equipo se apaga por completo
systemctl hibernateAl encender, GRUB recupera la sesión donde la dejaste.
⚡ Fase 5 — Post-instalación: KDE, TLP y Timeshift
Paquetes base y KDE
su -
apt update && apt upgrade -y
# Base del sistema
apt install -y git curl wget rsync htop vim build-essential btrfs-progs acpid
# WiFi + Bluetooth (mayoría de portátiles Intel)
apt install -y firmware-iwlwifi bluetooth bluez
# Gestión de energía
apt install -y tlp tlp-rdw thermald powertop
systemctl enable tlp
# KDE Plasma
apt install -y task-kde-desktop kde-standard \
plasma-workspace-wayland plasma-pa powerdevil bluedevil \
xserver-xorg-input-libinput
# Audio PipeWire (estándar en Debian 13)
apt install -y pipewire pipewire-pulse wireplumber
# Plymouth — prompt LUKS con logo en el arranque
apt install -y plymouth plymouth-themes
plymouth-set-default-theme -R bgrt
systemctl enable sddm
rebootTLP — protección de batería
TLP es imprescindible en cualquier portátil que pase tiempo enchufado. Sin umbrales de carga la batería pasa el día al 100% y se degrada mucho antes de lo necesario.
nano /etc/tlp.confDescomentar y ajustar estos valores:
# Carga: empieza al bajar del 75%, para al llegar al 80%
START_CHARGE_THRESH_BAT0=75
STOP_CHARGE_THRESH_BAT0=80
# Si el portátil tiene segunda batería (ThinkPad X270, X250, etc.)
START_CHARGE_THRESH_BAT1=75
STOP_CHARGE_THRESH_BAT1=80
# CPU en batería: ahorro de energía
CPU_SCALING_GOVERNOR_ON_BAT=powersave
CPU_ENERGY_PERF_POLICY_ON_BAT=power
tlp start
tlp-stat -b # verificar que los umbrales están aplicados en hardwareNota: Los umbrales de batería solo funcionan en hardware compatible. En ThinkPad con kernel reciente funciona sin problema vía thinkpad_acpi. En otros portátiles puede no estar soportado — tlp-stat -b te lo indica claramente.
Timeshift + grub-btrfs — la combinación que lo cambia todo
Timeshift en modo btrfs hace snapshots instantáneos sin copiar datos, aprovechando el CoW del sistema de ficheros. grub-btrfs añade esos snapshots al menú de GRUB automáticamente — sin tocar nada a mano.
apt install -y timeshift inotify-tools
# grub-btrfs desde GitHub — el de los repos de Debian suele estar desactualizado
apt install -y gawk # necesario — mawk no es compatible con este script
git clone https://github.com/Antynea/grub-btrfs.git /tmp/grub-btrfs
cd /tmp/grub-btrfs && make install
systemctl enable --now grub-btrfsdAbrir Timeshift desde el menú de KDE y configurar:
- Tipo de snapshot: BTRFS (no RSYNC)
- Dispositivo: seleccionar
/dev/mapper/nvme0n1p3_crypt - Retención de snapshots recomendada:
| Tipo | Retener | Cuándo |
|---|---|---|
| Arranque | 3 | En cada arranque |
| Diario | 5 | Una vez al día |
| Semanal | 3 | Una vez a la semana |
| Mensual | 2 | Una vez al mes |
- Incluir
/home/tuusuariosi quieres snapshot de home - Excluir:
/var/lib/docker,/var/lib/libvirt/images,/swap - Crear el primer snapshot manual → botón Crear → “instalación base”
Desde ese momento, antes de cada arranque Timeshift crea un snapshot y grub-btrfsd actualiza el menú de GRUB. Si el sistema deja de arrancar, en el propio GRUB tienes la opción de entrar a cualquier snapshot anterior.
Tapa → hibernar
nano /etc/systemd/logind.confHandleLidSwitch=hibernate # en batería → hibernar
HandleLidSwitchExternalPower=suspend # enchufado → suspender (más rápido)
HandleLidSwitchDocked=ignore # con monitor externo → no hacer nada
systemctl restart systemd-logind✅ Qué tienes cuando terminas
- Disco cifrado con LUKS2 — sin la contraseña los datos son inaccesibles
- btrfs con subvolúmenes independientes — Docker y VMs no ensucian los snapshots del sistema
- Snapshots automáticos — en cada arranque, diario, semanal y mensual; en modo btrfs son instantáneos
- Restauración desde GRUB — si el sistema no arranca, seleccionas el snapshot anterior directamente en el menú de arranque, sin USB de rescate
- TLP con umbrales de carga — la batería no se pasa el día al 100% degradándose
- Hibernación funcional — cierras la tapa, al día siguiente abres y sigues donde lo dejaste
En el siguiente artículo: personalización del terminal con zsh, oh-my-zsh, powerlevel10k y tmux.