PBS resucitado: diagnóstico de disco, grupos de backup y notificaciones Telegram

Terminal mostrando diagnóstico SMART de disco duro y logs de Proxmox Backup Server

Llevaba semanas convencido de que el disco duro de mi Proxmox Backup Server había muerto. Los errores de I/O fueron contundentes, lo desconecté y empecé a buscar alternativas. Spoiler: el disco estaba perfectamente sano. Lo que había muerto era el cable USB... o más bien, la paciencia del miniPC para alimentarlo.

El contexto: PBS con disco USB externo

Mi homelab corre sobre un miniPC BMAX con Intel Celeron N4120. PBS (Proxmox Backup Server) vive en una VM y usa como datastore un WD Elements de 1TB conectado por USB, pasado a la VM mediante USB passthrough.

La configuración funcionaba bien hasta que el SAI tuvo que actuar y el miniPC se reinició. Después de ese reinicio, el disco dejó de ser visible. Los logs de Proxmox mostraban errores de I/O y decidí desconectarlo. Error mío: no investigué más.

Diagnóstico: el disco no estaba muerto

Semanas después, con el disco en mi PC de escritorio, lancé un análisis SMART completo:

sudo smartctl -a /dev/sda

El resultado fue claro:

SMART overall-health self-assessment test result: PASSED
Reallocated_Sector_Ct   0
Current_Pending_Sector  0
Offline_Uncorrectable   0
No Errors Logged

Cero sectores reasignados, cero errores. El disco estaba impecable. Entonces ¿qué había pasado?

El culpable: el miniPC BMAX y la alimentación USB

Al reconectar el disco al miniPC y revisar dmesg, el kernel detectaba el dispositivo pero fallaba al leer la capacidad:

sd 2:0:0:0: [sda] Read Capacity(10) failed: Result: hostbyte=DID_ERROR
sd 2:0:0:0: [sda] 0 512-byte logical blocks: (0 B/0 B)
sd 2:0:0:0: [sda] Asking for cache data failed

En mi equipo, con el mismo cable, el disco funcionaba perfectamente:

sd 4:0:0:0: [sda] 1953458176 512-byte logical blocks: (1.00 TB/931 GiB)
sda: sda1
sd 4:0:0:0: [sda] Attached SCSI disk

El problema es conocido: el Celeron N4120 es un procesador de gama baja (Gemini Lake) y estos miniPCs tienen controladores USB con alimentación muy justa. El WD Elements es un disco bus-powered — se alimenta del USB — y el BMAX no le entrega suficiente corriente para completar el Read Capacity.

Es exactamente el mismo patrón que el problema de Zigbee2MQTT: el reinicio del SAI cambia el orden de arranque o la disponibilidad de energía, y el dispositivo USB no responde como debería.

La solución: un hub USB3 con alimentación externa. En mi caso, un TP-Link UH720 con 7 puertos y adaptador de corriente propio. El disco se alimenta del hub, no del miniPC. El miniPC solo gestiona los datos.

Arreglando PBS: fstab y WireGuard

Con el disco fuera de juego, la VM de PBS arrancaba en emergency mode porque /etc/fstab intentaba montar /dev/sdb1 en /mnt/datastore y fallaba al no encontrarlo.

Solución: añadir nofail a la entrada del fstab para que PBS arranque aunque el disco no esté disponible. Como la VM estaba inaccesible, lo hice desde el host PVE sin arrancarla:

apt install libguestfs-tools
virt-edit -a /dev/pve/vm-103-disk-0 /etc/fstab \
  -e 's|/dev/sdb1 /mnt/datastore ext4 defaults 0 2|/dev/sdb1 /mnt/datastore ext4 defaults,nofail,x-systemd.device-timeout=10 0 2|'

El segundo problema: WireGuard dentro de PBS no arrancaba automáticamente tras el reinicio. El servicio estaba instalado pero no habilitado:

systemctl enable wg-quick@wg0

Sin WireGuard activo, PBS no era accesible desde el VPS de Hetzner (que actúa como punto de entrada mediante nginx reverse proxy). El panel web en pbs.jaumeferre.casa simplemente no respondía. Un systemctl enable de nada y todo volvió a funcionar.

Lección: instalar un servicio no es suficiente. Hay que habilitarlo explícitamente para que sobreviva a los reinicios.

El caso especial del backup de PBS

PBS no puede hacerse backup a sí mismo de la forma habitual. Cuando PVE intenta hacer backup de la VM 103 (PBS), QEMU intenta conectarse a 192.168.1.13:8007 para transferir los datos — pero si el QEMU Guest Agent está activo, la VM queda en un estado de freeze que le impide responder a esas conexiones. Resultado: timeout.

La solución es desactivar el QEMU Guest Agent en la configuración de la VM de PBS en PVE. Se puede hacer desde la interfaz web (Hardware → QEMU Guest Agent → Disabled) o por línea de comandos:

qm set 103 --agent 0

Con el agente desactivado, el backup de PBS funciona sin problemas. La contrapartida es que PVE no puede ver la IP de la VM directamente en el panel — hay que consultarla en PBS directamente o por SSH.

Reorganización de los jobs de backup

Con PBS funcionando, aproveché para reorganizar los jobs de backup. Antes tenía varios grupos heredados de cuando PBS daba problemas; ahora los redefiní por criticidad:

Críticos — diario a las 2:00 101 (HAOS), 102 (wireguard), 109 (zigbee2mqtt)

Importantes — diario a las 3:00 104 (uptimekuma), 106 (mqtt), 107 (webserver-local), 110 (adguard), 114 (piwigo), 126 (loki-grafana)

Normal — domingos a las 4:00 108 (transmission), 116 (watchyourlan), 122 (homepage), 124 (jellyfin), 125 (vikunja)

PBS — diario a las 6:00 103 (pbs) — job separado por el motivo explicado arriba

También eliminé dos VMs/LXCs obsoletos: VM 105 (webserver antiguo, sustituido por LXC 107) y LXC 112 (npmplus, un intento de proxy que finalmente no usé).

La retención configurada en PBS es keep-last=30, keep-daily=7, keep-weekly=4, keep-monthly=3, con GC a las 3:30 y verificación diaria a las 4:00.

Notificaciones: Telegram para resumen, email solo en errores

El sistema de notificaciones anterior mandaba un email detallado por cada job, tanto si iba bien como si fallaba. Demasiado ruido.

El nuevo esquema:

  • Telegram: un mensaje al terminar cada job con el resultado de cada VM/LXC
  • Email: solo si hay errores, con el log completo de detalle

Para Telegram, usé el sistema de hook scripts de vzdump. PVE permite especificar un script que se ejecuta en cada fase del backup. Lo añadí en /etc/vzdump.conf:

script: /usr/local/bin/backup-notify.sh

El script acumula los resultados de cada VM en un fichero temporal y envía el resumen por Telegram al terminar el job completo:

#!/bin/bash

TELEGRAM_TOKEN="<MITOKEN>"
TELEGRAM_CHAT_ID="<MIID>"
RESULTS_FILE="/tmp/backup-results-${STOREID}"

send_telegram() {
    curl -s -X POST "https://api.telegram.org/bot${TELEGRAM_TOKEN}/sendMessage" \
        --data-urlencode "chat_id=${TELEGRAM_CHAT_ID}" \
        --data-urlencode "text=$1" > /dev/null
}

phase=$1
mode=$2
vmid=$3

case "$phase" in
    job-start)
        rm -f "${RESULTS_FILE}"
        ;;
    backup-end)
        echo "✅ ${HOSTNAME} (${vmid})" >> "${RESULTS_FILE}"
        ;;
    backup-abort)
        echo "❌ ${HOSTNAME} (${vmid})" >> "${RESULTS_FILE}"
        ;;
    job-end)
        RESULTS=$(cat "${RESULTS_FILE}" 2>/dev/null || echo "Sin detalles")
        MSG="✅ Backup completado
📦 Storage: ${STOREID}
📅 $(date '+%Y-%m-%d %H:%M')

${RESULTS}"
        send_telegram "$MSG"
        rm -f "${RESULTS_FILE}"
        ;;
    job-abort)
        RESULTS=$(cat "${RESULTS_FILE}" 2>/dev/null || echo "Sin detalles")
        MSG="❌ Backup FALLIDO
📦 Storage: ${STOREID}
📅 $(date '+%Y-%m-%d %H:%M')

${RESULTS}

⚠️ Revisa el log en PBS"
        send_telegram "$MSG"
        rm -f "${RESULTS_FILE}"
        ;;
esac

exit 0

Un detalle importante: en la fase backup-start y backup-end, la variable $HOSTNAME contiene el nombre del contenedor o VM, no el del host. Esto permite mostrar nombres legibles en el mensaje.

Para el email, tanto PVE como PBS tienen sistemas de notificación independientes. En ambos configuré un matcher que solo envía cuando la severidad es error:

En PVE:

pvesh set /cluster/notifications/matchers/default-matcher --match-severity error

En PBS, desde la interfaz web en Configuration → Notifications → Notification Matchers, edité el default-matcher para que solo tenga la regla Match severity: Error.

Resultado final

✅ Backup completado
📦 Storage: pbs
📅 2026-03-28 13:32
✅ pbs (103)

✅ Backup completado
📦 Storage: pbs
📅 2026-03-28 13:30
✅ uptimekuma (104)
✅ mqtt (106)
✅ webserver-local (107)
✅ adguard (110)
✅ piwigo (114)
✅ loki-grafana (126)

15 contenedores y VMs respaldados, notificaciones funcionando, PBS accesible. Lo que parecía una catástrofe resultó ser un cable y un systemctl enable pendiente.

Queda pendiente conectar el hub USB cuando llegue y configurar el Sync Job hacia la Storage Box de Hetzner para tener copia remota. Eso será el siguiente post.

Jaume Ferré

Jaume Ferré

Tengo un trabajo que no tiene nada que ver con esto. Pero me gusta cacharrear con webs, Linux y el homelab. De vez en cuando alguien me paga por ello, lo cual siempre sorprende. Canon R7 en mano y Arch Linux de fondo.

¿Te ha sido útil?

Ayúdame a mejorar con tu puntuación.

0.0 (0 votos)
Comentarios