
🌐 También en: English · Deutsch · Français
📦 Lo que iba a ser un rápido «voy a montar un NAS este fin de semana» se convirtió en una semana de madrigueras de conejo, yak shaving y una cantidad poco razonable de commits de git. Pero bueno: el homelab ha salido ganando y ahora todo está automatizado y documentado. Como siempre, el código completo de Ansible está aquí:
👉 github.com/aptupgrademe/www_k3s
Antes de llegar al NAS y a OpenZFS —el verdadero plato fuerte—, déjame soltar rápidamente las misiones secundarias que fueron surgiendo por el camino. Si tienes prisa, salta directamente a la sección de ZFS. No te juzgaré.
🐿️ Misiones secundarias: todo lo que no era el NAS
Ya sabes cómo va esto. Empiezas a configurar un NAS y tres días después estás arreglando reglas de alerta de Grafana y escribiendo una guía de operaciones en francés. Esto es lo que pasó:
🔒 Correcciones de seguridad (edición «espera, ¿¡eso estaba abierto!?»)
- rpcbind escuchaba en el puerto 111, públicamente. NFS no se usa en ningún sitio. Arreglado. 😬
- rkhunter enviaba cada mañana correos de «infected!», porque SourceForge había pasado a redirecciones HTTPS y
curlno las seguía. Añadidocurl -L. También automaticérkhunter --propupddespués dednf-automatic, para que las actualizaciones de seguridad nocturnas no parezcan rootkits. - Las reglas de alerta de Grafana tenían los umbrales metidos a fuego en el PromQL, lo que provocaba errores de «condition must not be empty» cuando las métricas estaban por debajo del umbral. Umbrales trasladados al evaluador. Ahora funciona de verdad.
- Bastionado de systemd desplegado con drop-ins: la puntuación de exposición de
sshdpasó de 9,6 → 7,8, y la denode_exporteryprometheus, de 9,2 → 4,4 cada uno. - Servicios innecesarios eliminados:
rpcbind,gssproxy,sssd; ninguno hacía falta y todos estaban en marcha.
⚡ Rendimiento
- Autoptimize instalado en WordPress: el número de etiquetas JS/CSS bajó de 40 a 6. El tamaño de la página, un ~18 % menos.
- robots.txt devolvía un 404. Yoast SEO lo genera dinámicamente con PHP, pero nginx lo trataba como un archivo estático. Una directiva
try_filesdespués: arreglado. tcp_max_syn_backlogsubido de 512 a 4096 para que cuadre consomaxconn.- Transparent Huge Pages cambiado de
alwaysamadvise: el valor por defecto provoca picos de latencia en los pods de K3s, en MariaDB y en Redis.
🎨 Diseño y SEO
- La cabecera del blog recibió un rediseño: el logo de Superman ahora está a la derecha (en espejo, para que mire hacia dentro en lugar de salir volando de la página), el título del sitio a la izquierda y un fondo oscuro a juego con las barras de navegación. Pequeños detalles, gran diferencia.
- 165 imágenes no tenían texto alternativo. Arreglado con un script de WP-CLI que deduce las descripciones automáticamente a partir de los nombres de archivo. Eso llevó más tiempo que montar el NAS.
- robots.txt ahora muestra correctamente a los buscadores el sitemap generado por Yoast.
- Añadido «Home» como primera entrada del menú de navegación. Resulta que no era evidente cómo volver a la portada. Ups.
📚 Documentación
Porque, por lo visto, disfruto escribiendo documentación más de lo que es sano: las guías de operaciones ya están disponibles en alemán, inglés y francés para WordPress, Nextcloud y el nuevo NAS. Sí, en francés. La carpeta docs/ del repositorio contiene los seis archivos HTML.
🗄️ El plato fuerte: un NAS con OpenZFS en Debian 13
Vale. Lo que de verdad me había propuesto hacer.
¿Por qué ZFS? Un poco de historia
ZFS lo desarrolló originalmente Sun Microsystems y se lanzó por primera vez con Solaris 10 en 2005. El nombre significaba «Zettabyte File System»: lo de la modestia no iba con Sun. Se diseñó desde cero para resolver problemas que los sistemas de archivos UNIX tradicionales llevaban décadas tapando: la corrupción silenciosa, los estados inconsistentes tras un fallo y el horror general de un fsck en volúmenes grandes.
Cuando Oracle compró Sun en 2010, el desarrollo de código abierto de ZFS se bifurcó en OpenZFS, hoy el proyecto comunitario con mantenimiento activo que funciona en Linux, FreeBSD, macOS y otros. Es el que usamos.
Algo que di por hecho durante mucho tiempo: ZFS es cosa de FreeBSD. Pues resulta que no del todo. OpenZFS viene en los repositorios de Debian 13 y se instala sin problemas. Es la primera vez que lo uso, así que todavía no tengo cifras reales. Mi intuición es que el rendimiento bruto podría ser algo menor que el de una configuración ext4/mdadm afinada, pero a cambio las sumas de comprobación, la detección de corrupción silenciosa y los snapshots hacen que los datos estén bastante más seguros. Ya veremos cómo aguanta. 🧪
✅ Lo que hace genial a ZFS
- Sumas de comprobación de extremo a extremo: cada bloque recibe una suma de comprobación al escribirse, que se verifica al leerse. La corrupción silenciosa («bit rot») se detecta y, en un pool redundante, se repara automáticamente.
- Copy-on-Write (CoW): los datos nunca se sobrescriben en el sitio. Eso hace que los snapshots salgan prácticamente gratis y elimina el problema del «write hole» de RAID 5.
- Snapshots: copias de un dataset en un momento dado, creadas al instante y almacenadas de forma eficiente. Vuelta atrás en segundos.
- RAID integrado (RAIDZ): sin controladora RAID aparte ni corrupción silenciosa de metadatos. RAIDZ1/2/3 son nativos de ZFS.
- Compresión: transparente y por dataset.
zstdahorra un 30–50 % de espacio en documentos y copias de seguridad con un coste de CPU insignificante. - Caché ARC: ZFS gestiona su propia caché de lectura adaptativa en RAM. Más RAM = lecturas más rápidas.
- Almacenamiento agrupado: todos los datasets comparten dinámicamente el espacio del pool. Se acabó lo de trocear particiones fijas.
⚠️ Las contrapartidas
- Devora RAM: el ARC es glotón. Un NAS de verdad quiere 16–32 GB.
- Ampliar un RAIDZ no es fácil: no puedes añadir sin más un disco a un vdev RAIDZ existente. ZFS 2.2+ introdujo la expansión, pero sigue sin ser instantánea.
- RAM ECC muy recomendable: ZFS confía en la RAM. Si la RAM corrompe un bit en silencio antes de escribirlo, ZFS calcula una suma de comprobación válida sobre el dato corrupto. La ECC lo evita.
- Curva de aprendizaje: pools, vdevs, datasets, propiedades. Un modelo mental distinto al de los sistemas de archivos tradicionales. Merece la pena, pero se te va un fin de semana.
🏗️ La configuración real
Antes, esos mismos tres SSD ejecutaban un RAID5 por software clásico de Linux (md) con ext4 encima. Funcionaba, pero no ofrecía ninguna de las garantías de integridad, snapshots ni compresión de ZFS. Hora de actualizar.
El hardware es un HP MicroServer Gen10 Plus V2: Intel Xeon E-2314, 31 GB de RAM. Distribución del almacenamiento:
sdb(SSD de 465 GB) → sistema operativo Debian 13sda+sdc+sdd(3× SSD WD Red SA500 de 1,8 TB) → ZFS RAIDZ1sde(HDD Toshiba de 1,8 TB) →/mnt/usb, copia de seguridad externa
El rol de Ansible crea el pool así:
zpool create -f
-o ashift=12 # 4K sector alignment for modern SSDs
-o autotrim=on # TRIM commands for SSD health
-O compression=zstd # transparent compression
-O atime=off # no access-time writes on reads
-O xattr=sa # Samba xattrs in inodes (faster)
-O recordsize=128k # overridden to 1M per dataset
-O mountpoint=/raid5
data raidz /dev/disk/by-id/ata-WD_Red_SA500_...
📁 Samba: una única fuente de verdad
La decisión de diseño clave: las definiciones de recursos compartidos de Samba en vars.yml lo controlan todo. El rol de Ansible las recorre en bucle para crear los datasets de ZFS, asignar los propietarios y escribir smb.conf. Añades un recurso compartido en un solo sitio y lo demás viene solo:
nas_samba_shares:
- name: shared
path: "{{ nas_zfs_mountpoint }}/shared"
valid_users: user3
force_user: user3
- name: user1
path: "{{ nas_zfs_mountpoint }}/user1"
valid_users: user3
force_user: user3
Samba funciona con SMB3, soporte multicanal y E/S asíncrona. La propiedad de ZFS xattr=sa guarda los atributos extendidos de Windows directamente en el inodo en lugar de en archivos ocultos, lo que hace los metadatos notablemente más rápidos. 🎛️
🤖 Jenkins, GitLab & Pi-hole
El MicroServer hace algo más que servir archivos:
Jenkins (puerto 8090) ejecuta dos tareas de copia de seguridad nocturnas: copias basadas en rsync de dos instancias remotas de Nextcloud (instance-a e instance-b). La clave SSH para estas conexiones se guarda cifrada en Ansible Vault y se restaura en /home/user3/.ssh/ en cada instalación nueva. Ni siquiera una reinstalación completa del sistema rompe la conectividad de las copias.
GitLab CE 19.1 (puerto 80) hace de servidor Git local. Tener un GitLab propio para los proyectos del homelab significa no depender de servicios externos. El rol de Ansible se encarga de toda la configuración posterior a la instalación a través de la API de GitLab: establece la contraseña de root, crea un usuario estándar, un grupo homelab y un proyecto vacío www_k3s, todo de forma idempotente.
Pi-hole v6 (puerto 8000 para la interfaz web, puerto 53 para DNS) bloquea la publicidad a nivel de red. Está en el puerto 8000 en lugar del 80 por defecto porque ahí ya vive GitLab. Los DNS upstream son 8.8.8.8/8.8.4.4.
Y como es un servidor HP: HPE AMSD (Agentless Management Service) se instala lo primero, antes que todo lo demás. Sin él, el BMC iLO no recibe datos de temperatura del sistema operativo y los ventiladores giran a tope. Ruidoso. Muy ruidoso.
Todo esto —tanto el NAS como los servidores de Internet— está a un solo comando ansible-playbook de reconstruirse desde cero:
👉 github.com/aptupgrademe/www_k3s
Lo siguiente: reinstalar de verdad hp1 y ejecutar el playbook por primera vez en un Debian 13 limpio. Ya te contaré si ZFS en Linux está a la altura de la fama. 🤞






