pbs.local: a backup server from junk hardware and two retired disks

How a dead SATA port, mismatched non-ECC DDR3 modules, and 683 historical CRC errors became a 7.2 TB Proxmox Backup Server in one afternoon.

El clúster tiene un nodo nuevo, y vive sobre hardware que nadie más tocaría. pbs.local está respaldando ahora nuestras máquinas virtuales sobre 7,2 TB de XFS montados encima de una ASRock 970 Extreme3 de 2012, un FX-8350 y tres Seagate Barracuda en distintos estados de dignidad. Esta es la historia de cómo se montó — incluido un puerto SATA muerto, 683 errores CRC históricos y un debate sobre sistema de archivos que tuvimos con nosotros mismos.

Por qué molestarse

Nuestros dos nodos Proxmox VE (pve1 en casa, ipve1 en OVH) venían respaldándose contra almacenamiento tipo directorio. Barato, simple y un punto único de fallo cada uno. Proxmox Backup Server, en cambio, nos da chunks deduplicados, backups incrementales para siempre, integridad por contenido y verify jobs que recorren cada byte en un horario. Levantar un tercer host dedicado para esto significaba que los backups dejaban de competir por disco y IOPS con la producción.

La placa para este host llevaba en un cajón desde el último upgrade. Los discos venían de vidas anteriores. Todo lo demás vino del presupuesto que no gastamos en hardware nuevo.

Recorrido por el hardware

  • Placa base: ASRock 970 Extreme3 R2.0 (chipset AMD 970 + SB950, cuatro puertos SATA — luego volveremos a esto).
  • CPU: AMD FX-8350, ocho núcleos a 4 GHz. Más que suficiente para los SHA-256 de chunking.
  • RAM: 17 GB DDR3-1333 Kingston, no-ECC, en cuatro módulos desiguales (8 + 4 + 2 + 4). El de 2 GB se irá en una limpieza futura — cuando salga, los 8 + 4 + 4 que quedan se quedan perfectamente simétricos en dual-channel.
  • Disco de sistema: Seagate Barracuda 7200.14 de 500 GB que ya teníamos. SMART PASSED con 32 727 horas. Aloja la raíz de PBS y el swap.
  • Discos de backup: dos Seagate ST4000DM004 de 4 TB. Uno prácticamente nuevo (916 horas). El otro tiene 29 881 horas — tres años y medio de servicio continuo — y vino con 683 errores UDMA CRC históricos a cuestas. Ya llegaremos a ellos.

El arranque que no arrancaba

Primer arranque tras instalar PBS 4.2 en el disco de 500 GB: la pantalla de splash se queda colgada, luego scroll de texto rojo y finalmente vemos Timed out while waiting for udev queue to empty. Cuando por fin llega al prompt, solo uno de los dos discos de 4 TB aparece en lsblk. El buffer de dmesg nos contó exactamente por qué:

ata5: reset failed (errno=-32), retrying in 8 secs
ata5: limiting SATA link speed to <unknown>
ata5: hardreset failed
ata5: reset failed, giving up
INFO: task (udev-worker):150 blocked for more than 122 seconds.

El quinto puerto SATA del SB950 está físicamente muerto. El kernel estaba intentando hacer hardreset diez veces con backoff exponencial — dos minutos largos — y bloqueando udev-worker mientras tanto. En cuanto movimos el disco al ata6 (el último puerto, que había estado vacío) y aceptamos que ata5 nunca volvería a funcionar, el boot pasó de tres minutos a uno. Aparecieron los dos discos. El timeout de udev desapareció.

Lección: cuando una placa vieja tiene cuatro puertos SATA y uno está muerto, ese está muerto para siempre. Márcalo con rotulador en la serigrafía. El truco es tratarlo como un diente que falta en vez de intentar arreglarlo.

Los 683 errores CRC

En cuanto los dos discos fueron visibles, SMART nos dio la siguiente sorpresa. El más viejo — el veterano de 3,4 años — reportaba UDMA_CRC_Error_Count: 683. La cifra parece alarmante, pero la propia SMART marca el atributo bien por encima del umbral (VALUE 200, WORST 197, THRESH 0), y los contadores que sí predicen muerte de disco (realocados, pendientes, offline uncorrectable) estaban todos a cero.

Los errores UDMA CRC no son daño del disco. Son errores de transmisión en el bus — un cable flaco, un conector flojo, alimentación marginal en el raíl de +5 V. Los 683 que heredamos casi seguro se acumularon en el hogar anterior del disco. Ahora en este servidor, en el puerto ata6 (que sí funciona) y con cable nuevo, el contador no debería moverse. Lo vigilaremos las próximas semanas y solo entraremos en pánico si empieza a subir.

XFS, not ZFS

La decisión interesante fue el sistema de archivos. Nos planteamos seriamente ZFS, un pool single-disk por cada disco, solo por los checksums. Dos argumentos lo mataron:

El primero es la RAM. 17 GB de DDR3 no-ECC, módulos desiguales. ZFS te da detección de bit-rot, pero su fiabilidad depende de que el checksum que computó fuera correcto en primer lugar. Con RAM no-ECC, un bit-flip durante el cómputo del checksum es invisible. El debate clásico "ZFS necesita ECC" está exagerado — ZFS sin ECC no es peor que XFS sin ECC — pero el valor que aporta encima es menor de lo que la gente piensa.

El segundo es la redundancia. ZFS single-disk detecta corrupción pero no la repara. Te llega un "este bloque está malo" y un chunk muerto. PBS ya da exactamente esa capacidad a nivel de aplicación: cada chunk es un blob con dirección por contenido y hash SHA-256, y verify-job los recorre en un horario. Conseguimos la misma detección, sin el ARC comiéndose la RAM y sin la ansiedad de "si muere esta placa, ¿dónde están mis pools?".

XFS, dos datastores separados, sin redundancia, nofail en fstab para que un disco muerto no deje colgado el host. HDD1 y HDD2, 3,6 TB usables cada uno, dirigidos a sets de backups separados de manera que la pérdida de uno sea la mitad de la pérdida en vez de toda.

Topología y acceso

Cada nodo PVE recibe su propio token API (revocable de forma independiente — nunca compartas credenciales entre hosts), y cada uno toma la ruta más directa a pbs.local:

  • pve1 está en la misma LAN y conecta directamente a 192.168.1.4:8007.
  • ipve1 está en OVH y nos alcanza por DNS + port forward: pbs.secretplace.com:8007 → router → 192.168.1.4. El certificado de PBS se valida por fingerprint SHA-256, que es lo que PVE comprueba realmente.

Un pequeño gotcha de PBS que merece quedar por escrito: los tokens API tienen privilege separation por defecto. El ACL efectivo del token es la intersección con el ACL del usuario padre. Si solo le das ACL al token y no al usuario, te encuentras con el simpático error Cannot find datastore desde pvesm add, y una tarde de confusión. Concede DatastoreBackup a ambos — usuario y tokens — y PVE encuentra el datastore al instante.

Dónde estamos ahora

  • PBS 4.2 corriendo sobre kernel 7.0.0-3-pve, SATA en modo AHCI.
  • Dos datastores, verify jobs semanales los sábados a las 03:00 y 03:30.
  • Ambos nodos PVE pueden empujar backups vía tokens dedicados.
  • Los dos discos de 4 TB aún necesitan un backup job real apuntando contra ellos — política de retención, prune, garbage collection, notificaciones por mail. Pronto.

El clúster es un poco menos frágil esta semana que la anterior. Gasto total: cero. Satisfacción total: alta.

Customizing my system: pinning PulseAudio's default sink
My MSI monitor kept stealing the audio output every time it woke up. Three lines of PulseAudio config and a MATE autostart entry made it stop. The trail through pactl, switch-on-port-available, and a fresh dotfiles repo.