Problema
En entornos homelab con Proxmox, es frecuente combinar varios tipos de discos (NVMe, HDD, SSD) y usar ZFS como capa de datos primaria. El reto aparece cuando se necesita exponer esos datos a usuarios finales mediante SMB o NFS, y se delega la gestión de usuarios y permisos a una instancia de OpenMediaVault (OMV). La arquitectura típica —ZFS en el hipervisor, OMV en una VM o LXC, y discos de respaldo en RAID‑1— genera conflictos de permisos, latencia en escritura y complejidad en la planificación de backups. El síntoma más común es que los clientes Windows o Linux ven archivos con UID/GID inesperados o que los snapshots de ZFS no se sincronizan correctamente con los procesos de rsync programados.
Causa
-
Desalineación de UID/GID entre Proxmox y OMV
ZFS almacena propietarios como números UID/GID. Si la VM/contener de OMV tiene un rango de usuarios distinto al del host, los archivos aparecen con propietarios “nobody” o con IDs que no existen en el cliente. -
Exportación directa de datasets ZFS sin control de permisos
Compartir un dataset ZFS mediantezfs set sharenfs=onozfs set sharesmb=onignora la capa de control de acceso de OMV, provocando que los permisos de Samba/NFS se resuelvan únicamente a nivel de ZFS. -
Uso de LVM para VMs y datasets ZFS en paralelo
Cuando la unidad NVMe está particionada con LVM para VMs y, al mismo tiempo, se crea un pool ZFS sobre la misma unidad, el hipervisor necesita gestionar dos sistemas de bloques diferentes. Un error de alineación de bloques o de caché puede degradar el rendimiento y causar corrupción en snapshots. -
Backups basados en rsync sin snapshots consistentes
Ejecutar rsync directamente sobre un dataset activo puede copiar archivos en estado intermedio. Sin snapshots de ZFS, los backups pueden quedar inconsistentes, y los cambios de permisos entre ejecuciones pueden generar “Permission denied”. -
OMV en VM vs LXC
En una VM, OMV maneja su propio kernel y controladores, lo que añade una capa de virtualización extra. En LXC, el contenedor comparte el kernel del host, lo que facilita el ID mapping pero requiere configuraciones específicas (lxc.idmap) y permisos de montaje (privilegedvsunprivileged).
Solución
1. Consolidar ZFS como única capa de datos y exponerla a OMV mediante bind‑mounts
Crear datasets ZFS para cada tipo de dato (raw, backups, multimedia) y montar esos datasets dentro del contenedor/VM de OMV usando bind‑mounts. De esta forma OMV gestiona únicamente la capa de compartición (Samba/NFS) mientras que los permisos siguen siendo los del host.
# Crear pool ZFS en el NVMe (asumiendo /dev/nvme0n1)
zpool create -f -o ashift=12 tank /dev/nvme0n1
# Datasets
zfs create -o compression=lz4 tank/data
zfs create -o compression=lz4 tank/backups
# Montaje en el host (opcional, Proxmox lo hace automáticamente)
mkdir -p /tank/data /tank/backups
mount -t zfs tank/data /tank/data
mount -t zfs tank/backups /tank/backups
2. Deploy OMV como LXC con ID mapping
Usar un contenedor LXC no privilegiado permite mapear los UID/GID del host a un rango interno del contenedor (100000-165535). Configurar /etc/pve/lxc/ID.conf y el archivo de la plantilla LXC:
# En el host
cat >> /etc/subuid <<EOF
root:100000:65536
EOF
cat >> /etc/subgid <<EOF
root:100000:65536
EOF
# Crear contenedor
pct create 101 local:vztmpl/ubuntu-22.04-standard_22.04-1_amd64.tar.gz \
-cores 2 -memory 2048 -net0 name=eth0,bridge=vmbr0,ip=dhcp \
-features nesting=1,keyctl=1 -unprivileged 1
# Añadir bind‑mounts
pct set 101 -mp0 /tank/data,mp=/srv/omv/data
pct set 101 -mp1 /tank/backups,mp=/srv/omv/backups
Dentro del contenedor, instalar OMV siguiendo la guía oficial y configurar los “Shared Folders” apuntando a /srv/omv/data. OMV ahora usa los UID/GID del host (mapeados) y los permisos se conservan.
3. Configurar Samba y NFS en OMV con “force user/group”
Para evitar que los clientes vean UID/GID diferentes, habilitar la opción Force user y Force group en los shares de OMV. Seleccionar un usuario del host (por ejemplo proxmox) y asignarlo a todos los shares. Así, cualquier acceso SMB/NFS se traduce al mismo UID/GID en ZFS.
4. Automatizar backups con snapshots y rsync
Utilizar snapshots de ZFS como punto de consistencia y rsync para copiar a los discos HDD en RAID‑1. Un cron simple:
#!/bin/bash
# snapshot
SNAP=$(date +%Y-%m-%d_%H-%M)
zfs snapshot tank/data@${SNAP}
# rsync al pool de backup (montado en /mnt/backup)
rsync -aHAX --delete /tank/data/ /mnt/backup/${SNAP}/
# opcional: eliminar snapshots antiguos (>30d)
zfs destroy -r tank/data@$(date -d "-30 days" +%Y-%m-%d_%H-%M)
Programar con crontab -e:
0 2 * * * /root/zfs_backup.sh >> /var/log/zfs_backup.log 2>&1
5. Monitorear integridad y permisos
Instalar zfs-auto-snapshot o zrepl para crear snapshots horarios y diurnos. Además, habilitar zfs get all tank/data | grep aclmode y asegurarse de que aclmode=passthrough para que los ACL de ZFS no interfieran con los permisos de Samba.
Cuándo aplicar esta solución
- Entornos homelab o pequeñas empresas donde se combina NVMe rápido para datos activos y HDD para backups.
- Necesidad de compartir datos vía SMB/NFS a usuarios Windows/Linux sin que los permisos se “pierdan” en la capa de virtualización.
- Preferencia por ZFS como única capa de datos y deseo de evitar la duplicación de sistemas de archivos (por ejemplo, LVM + ZFS).
- Se busca una solución reproducible que funcione tanto con OMV en VM como en LXC, pero con menor sobrecarga de virtualización.
No es adecuada cuando:
- Se requiere alta disponibilidad con clústeres Proxmox y failover de VM/CT; en ese caso, la arquitectura de discos debe ser compartida (Ceph, ZFS over iSCSI, etc.).
- Los usuarios finales necesitan acceso directo a discos físicos sin pasar por Samba/NFS (por ejemplo, bases de datos que requieren latencia mínima).
Código
# Creación de pool y datasets
zpool create -f -o ashift=12 tank /dev/nvme0n1
zfs create -o compression=lz4 tank/data
zfs create -o compression=lz4 tank/backups
# Bind‑mounts en LXC
pct set 101 -mp0 /tank/data,mp=/srv/omv/data
pct set 101 -mp1 /tank/backups,mp=/srv/omv/backups
# Script de backup con snapshot y rsync
#!/bin/bash
SNAP=$(date +%Y-%m-%d_%H-%M)
zfs snapshot tank/data@${SNAP}
rsync -aHAX --delete /tank/data/ /mnt/backup/${SNAP}/
zfs destroy -r tank/data@$(date -d "-30 days" +%Y-%m-%d_%H-%M)
Verificación
-
Montaje y permisos
- En el host:
ls -l /tank/datadebe mostrar UID/GID que coinciden con los usuarios de OMV (proxmoxo el UID mapeado). - Desde una máquina cliente Windows: crear un archivo en el share SMB y comprobar que el propietario es el mismo UID/GID en el host (
stat /tank/data/archivo).
- En el host:
-
Snapshot y backup
- Ejecutar manualmente el script y validar que
/mnt/backup/<fecha>/contiene la misma estructura que/tank/data. - Verificar que
zfs list -t snapshot | grep tank/data@muestra el snapshot creado.
- Ejecutar manualmente el script y validar que
-
Rendimiento
- Medir IOPS/latencia con
fioen/tank/datay comparar con los valores esperados de NVMe. - Asegurarse de que la carga de Samba/NFS no degrada el rendimiento por más del 10 % en pruebas de transferencia de archivos grandes.
- Medir IOPS/latencia con
Notas adicionales
- ID mapping: si decides mantener OMV en una VM, habilita
idmapden el host y en la VM y usa el mismo dominio NFS (Domain = localdomain). - ACL vs POSIX: ZFS permite ACLs de nivel de archivo; si OMV usa Samba con ACL, configura
zfs set acltype=posixacl tank/datay habilitaaclmode=passthrough. - Espacio de snapshots: los snapshots consumen espacio incremental. Monitorea con
zfs list -o name,used,available,refer,compressratioy programa destrucción automática. - Expansión de almacenamiento: si añades un expansor PCIe x16, crea un nuevo pool (por ejemplo
tank2) y replica la misma estructura de datasets; luego usazfs send/receivepara migrar datos sin downtime. - Seguridad: restringe el acceso a la interfaz web de OMV a redes internas y usa certificados auto‑firmados para HTTPS.
Con esta arquitectura, ZFS sigue siendo la capa de datos confiable, OMV gestiona usuarios y protocolos de compartición, y los backups automáticos se ejecutan de forma consistente y verificable.