ZFS es a la vez un sistema de archivos y un gestor de volúmenes: agrupa discos en un pool, verifica cada bloque con sumas de comprobación, repara datos corruptos a partir de la redundancia y crea snapshots instantáneos. En Linux se usa a través de OpenZFS. En este tutorial instalarás ZFS en Ubuntu 24.04, crearás un pool en espejo con dos discos, configurarás datasets con compresión y cuotas, y automatizarás snapshots, réplicas y la verificación periódica de los datos.
Requisitos previos
- Un servidor con Ubuntu 24.04 LTS, por ejemplo un servidor dedicado o un VPS de CubePath con volúmenes adicionales.
- Un usuario no root con privilegios
sudo. - Dos discos vacíos del mismo tamaño para el pool, distintos del disco del sistema. En los ejemplos aparecen como
/dev/vdby/dev/vdc. - Al menos 2 GB de RAM. ZFS usa la memoria libre como caché (ARC) y la libera cuando otros procesos la necesitan.
- Para el paso 7, un segundo servidor con ZFS al que tengas acceso por SSH con clave.
Paso 1: Instalar ZFS
Ubuntu incluye el módulo del kernel de ZFS en sus kernels oficiales, así que solo necesitas las herramientas de usuario:
sudo apt update
sudo apt install zfsutils-linux
Comprueba que el módulo está cargado y la versión instalada:
zfs version
zfs-2.2.2-0ubuntu9.1
zfs-kmod-2.2.2-0ubuntu9
En Debian 12 el módulo no viene incluido: instala zfs-dkms y zfsutils-linux desde el repositorio contrib, que compila el módulo para tu kernel. En Rocky Linux 9 se usa el repositorio de OpenZFS (zfs-release).
Paso 2: Identificar los discos
Localiza los discos vacíos:
lsblk -o NAME,SIZE,TYPE,MOUNTPOINTS
NAME SIZE TYPE MOUNTPOINTS
vda 40G disk
├─vda1 39G part /
...
vdb 100G disk
vdc 100G disk
Los nombres /dev/sdX o /dev/vdX pueden cambiar entre arranques. Para crear el pool es preferible usar los nombres estables de /dev/disk/by-id/:
ls -l /dev/disk/by-id/ | grep -E 'vdb|vdc'
lrwxrwxrwx 1 root root 9 Sep 25 10:00 virtio-disk-data1 -> ../../vdb
lrwxrwxrwx 1 root root 9 Sep 25 10:00 virtio-disk-data2 -> ../../vdc
En discos físicos verás nombres como ata-WDC_WD40EFRX-..._WD-XXXX o nvme-Samsung_SSD_.... Si tu VPS no muestra entradas en by-id, usa /dev/vdb y /dev/vdc; ZFS identifica los discos por sus etiquetas internas al importar el pool.
Paso 3: Crear un pool en espejo
Un espejo (mirror) guarda una copia completa de los datos en cada disco y tolera la pérdida de uno de ellos. Crea el pool tank:
sudo zpool create -o ashift=12 -O compression=lz4 -O atime=off -O xattr=sa \
-O mountpoint=/tank tank mirror \
/dev/disk/by-id/virtio-disk-data1 /dev/disk/by-id/virtio-disk-data2
-o ashift=12alinea las escrituras a sectores de 4 KiB, correcto para casi cualquier disco moderno. No se puede cambiar después.-O compression=lz4activa una compresión muy rápida que suele ahorrar espacio y E/S.-O atime=offevita escribir la hora de acceso en cada lectura.-O xattr=saguarda los atributos extendidos de forma más eficiente.
Las propiedades con -O se heredan en todos los datasets que crees dentro del pool. Comprueba el estado:
zpool status tank
pool: tank
state: ONLINE
config:
NAME STATE READ WRITE CKSUM
tank ONLINE 0 0 0
mirror-0 ONLINE 0 0 0
virtio-disk-data1 ONLINE 0 0 0
virtio-disk-data2 ONLINE 0 0 0
errors: No known data errors
Con cuatro o más discos puedes usar raidz1 (tolera un fallo), raidz2 (dos fallos) o varios espejos (mirror a b mirror c d). Para bases de datos y máquinas virtuales, los espejos ofrecen mejor rendimiento aleatorio.
Paso 4: Crear datasets
Los datasets son sistemas de archivos independientes dentro del pool, cada uno con sus propias propiedades, cuotas y snapshots. Crea uno para las copias de seguridad y otro para una base de datos:
sudo zfs create tank/backups
sudo zfs create -o recordsize=16K tank/mysql
recordsize=16K coincide con el tamaño de página de InnoDB y mejora el rendimiento de MySQL. El valor por defecto, 128K, es adecuado para archivos grandes.
Limita el espacio que puede ocupar tank/backups y cambia su compresión a zstd, más lenta pero con mayor ratio:
sudo zfs set quota=50G tank/backups
sudo zfs set compression=zstd tank/backups
Comprueba los datasets y sus propiedades:
zfs list -o name,used,avail,quota,compression,mountpoint
NAME USED AVAIL QUOTA COMPRESS MOUNTPOINT
tank 756K 96.4G none lz4 /tank
tank/backups 96K 50.0G 50G zstd /tank/backups
tank/mysql 96K 96.4G none lz4 /tank/mysql
Los datasets se montan automáticamente en el arranque. Copia algunos datos para comprobar la compresión:
sudo cp -r /usr/share/doc /tank/backups/
zfs get compressratio tank/backups
NAME PROPERTY VALUE SOURCE
tank/backups compressratio 3.12x -
Notaevita activar
dedup. La deduplicación necesita mucha RAM para sus tablas y rara vez compensa frente a la compresión.
Paso 5: Trabajar con snapshots
Un snapshot es una copia de solo lectura de un dataset en un momento dado. Se crea al instante y solo ocupa espacio a medida que los datos cambian. Crea uno:
sudo zfs snapshot tank/backups@antes-de-limpiar
Simula un error borrando datos:
sudo rm -rf /tank/backups/doc
Los snapshots son accesibles en el directorio oculto .zfs/snapshot, desde donde puedes recuperar archivos sueltos:
ls /tank/backups/.zfs/snapshot/antes-de-limpiar/
doc
Para devolver el dataset completo al estado del snapshot, usa rollback. Se pierden todos los cambios posteriores al snapshot:
sudo zfs rollback tank/backups@antes-de-limpiar
ls /tank/backups
doc
Lista los snapshots existentes:
zfs list -t snapshot
NAME USED AVAIL REFER MOUNTPOINT
tank/backups@antes-de-limpiar 0B - 45.2M -
Paso 6: Automatizar snapshots con Sanoid
Sanoid crea y elimina snapshots según una política de retención. Instálalo desde los repositorios de Ubuntu:
sudo apt install sanoid
Crea su archivo de configuración:
sudo mkdir -p /etc/sanoid
sudo nano /etc/sanoid/sanoid.conf
Esta configuración mantiene 36 snapshots horarios, 30 diarios y 3 mensuales de tank y de todos sus datasets hijos:
[tank]
use_template = production
recursive = yes
[template_production]
frequently = 0
hourly = 36
daily = 30
monthly = 3
yearly = 0
autosnap = yes
autoprune = yes
El paquete incluye un temporizador de systemd que ejecuta Sanoid cada 15 minutos. Asegúrate de que está activo:
sudo systemctl enable --now sanoid.timer
systemctl list-timers sanoid.timer
Fuerza una ejecución y comprueba que aparecen los snapshots:
sudo sanoid --cron --verbose
zfs list -t snapshot -o name | grep autosnap | head
tank@autosnap_2026-09-25_10:15:02_monthly
tank@autosnap_2026-09-25_10:15:02_daily
tank@autosnap_2026-09-25_10:15:02_hourly
tank/backups@autosnap_2026-09-25_10:15:02_monthly
...
Paso 7: Replicar un dataset a otro servidor
zfs send convierte un snapshot en un flujo de datos y zfs receive lo reconstruye en otro pool, conservando propiedades y snapshots. Es la forma nativa de hacer copias de seguridad fuera del servidor.
En el servidor de destino (backup.your_domain), que debe tener un pool llamado backup, crea el dataset contenedor:
sudo zfs create backup/replicas
En el servidor de origen, crea un snapshot y envíalo completo. La opción -u evita que el dataset recibido se monte en el destino:
sudo zfs snapshot tank/mysql@repl-1
sudo zfs send tank/mysql@repl-1 | ssh [email protected]_domain zfs receive -u backup/replicas/mysql
Los envíos siguientes solo transfieren los bloques que han cambiado entre dos snapshots (-i):
sudo zfs snapshot tank/mysql@repl-2
sudo zfs send -i tank/mysql@repl-1 tank/mysql@repl-2 | ssh [email protected]_domain zfs receive -u backup/replicas/mysql
Comprueba en el destino que los dos snapshots han llegado:
ssh [email protected]_domain zfs list -t snapshot -r backup/replicas/mysql
NAME USED AVAIL REFER MOUNTPOINT
backup/replicas/mysql@repl-1 56K - 104K -
backup/replicas/mysql@repl-2 0B - 104K -
Para automatizarlo, el paquete sanoid incluye syncoid, que calcula los snapshots incrementales por ti. Esta orden hace la misma réplica y se puede programar con cron o un temporizador de systemd:
sudo syncoid tank/mysql [email protected]_domain:backup/replicas/mysql
Paso 8: Verificar los discos con scrub
Un scrub lee todos los bloques del pool, verifica sus sumas de comprobación y repara los datos dañados usando la otra copia del espejo. Lánzalo manualmente:
sudo zpool scrub tank
zpool status tank | grep scan
scan: scrub repaired 0B in 00:00:12 with 0 errors on Fri Sep 25 10:30:14 2026
Ubuntu ya programa un scrub mensual de todos los pools. Comprueba la tarea que instala el paquete:
cat /etc/cron.d/zfsutils-linux
Si un disco falla, zpool status mostrará el pool como DEGRADED. Tras instalar el disco nuevo, sustitúyelo en el pool y ZFS reconstruirá la copia (resilver):
sudo zpool replace tank /dev/disk/by-id/virtio-disk-data2 /dev/disk/by-id/virtio-disk-data3
Paso 9: Limitar la memoria de la caché ARC (opcional)
Por defecto, ARC puede usar hasta la mitad de la RAM en Ubuntu 24.04. En un servidor que también ejecuta aplicaciones con mucha memoria, como una base de datos, conviene limitarla. Para fijar un máximo de 4 GiB (4 × 1024³ = 4294967296 bytes), aplícalo en caliente:
echo 4294967296 | sudo tee /sys/module/zfs/parameters/zfs_arc_max
Hazlo persistente creando /etc/modprobe.d/zfs.conf:
sudo nano /etc/modprobe.d/zfs.conf
options zfs zfs_arc_max=4294967296
Comprueba el tamaño máximo actual de ARC:
arc_summary -s arc | grep -i "max size"
Max size (high water): 16:1 4.0 GiB
Solución de problemas
zpool createfalla con/dev/vdb is in useocontains a filesystem: el disco tiene una tabla de particiones o datos anteriores. Si estás seguro de que puede borrarse, ejecutasudo wipefs -a /dev/vdby repite.- El pool no aparece tras reiniciar: impórtalo con
sudo zpool import tank. Si el problema se repite, comprueba quezfs-import-cache.serviceyzfs-mount.serviceestán habilitados. zfs receivefalla condestination has been modified: el dataset de destino ha cambiado desde el último snapshot recibido, normalmente porque estaba montado. Recibe siempre con-uo añade-Fal receive para descartar esos cambios en el destino.
Conclusión
Tienes un pool ZFS en espejo con datasets comprimidos, snapshots automáticos con Sanoid, réplicas incrementales a otro servidor y scrubs periódicos. Como siguientes pasos puedes programar syncoid con un temporizador de systemd para tener copias externas diarias, crear volúmenes de bloques (zfs create -V) para máquinas virtuales o activar el cifrado nativo en datasets nuevos con -o encryption=on.
