Backup del VPS y del nodo Proxmox: cuando el script dice OK pero no hace nada

Terminal mostrando la ejecución de un script de backup con salida de rsync hacia el Storage Box de Hetzner

Hace algo más de un mes montamos PBS para gestionar los backups de todas las CTs y VMs del homelab. Quedó bastante bien: grupos por criticidad, retención diferenciada, notificaciones Telegram. La infraestructura de backup de las máquinas virtuales, cubierta.

Lo que no teníamos cubierto era el resto: el propio VPS donde viven las webs, el nodo Proxmox en sí, y las máquinas físicas. Era el momento de ponerse con ello.

Pero antes de añadir nada nuevo, quise ver qué había realmente en el Storage Box. Hasta ese momento había trabajado con él a ciegas — sabía que los archivos se subían, pero nunca los había visto.


Ver el Storage Box desde Dolphin — y la sorpresa al abrirlo

La forma más cómoda en KDE es Dolphin — sin instalar nada, sin montar nada. En la barra de direcciones (Ctrl+L):

sftp://uXXXXXX@uXXXXXX.your-storagebox.de

Introduce la contraseña una vez, navegas como si fuera una carpeta local, y puedes guardar el marcador para tenerlo siempre a mano.

Al abrirlo me encontré con diecisiete copias diarias acumuladas. Seis copias de prueba del día que montamos el sistema. Una carpeta proxmox-backups con un testfile olvidado. La retención, que teníamos configurada en 7 copias diarias, no había funcionado ni una sola vez.


El script decía OK. Los archivos no se borraban.

El log del VPS decía esto cada día:

[2026-03-19 03:00:26] Limpiando backups antiguos (daily, retención: 7)...
[2026-03-19 03:00:27]   OK Limpieza completada

Según el log, todo correcto. En realidad, ningún archivo borrado.

El culpable: el shell restringido de Hetzner

El Storage Box de Hetzner no expone un bash completo. Es un shell restringido que soporta comandos básicos (ls, rm, mkdir, cp...) pero no soporta pipes ni redirects.

El script de limpieza hacía esto:

ssh ... "ls -t ${RUTA}/*.tar.gz 2>/dev/null | tail -n +8 | xargs -r rm"

El ls funcionaba. Pero el pipe al tail y el xargs nunca se ejecutaban. El comando terminaba con exit code 0, el script registraba "OK", y los archivos seguían ahí. Sin error, sin aviso. Silenciosamente.

La solución

Toda la lógica tiene que ejecutarse en el servidor que hace el backup, no en el Storage Box. Al Storage Box solo le mandamos comandos rm individuales, sin pipes:

# Obtener lista completa desde el Storage Box
ALL_FILES=$(ssh -p "$PUERTO" -i "$CLAVE" \
    "${USUARIO}@${HOST}" \
    "ls -t ${RUTA}/${TIPO}/backup_${TIPO}_*.tar.gz 2>/dev/null")

# Calcular qué borrar localmente
FILES_TO_DELETE=$(echo "$ALL_FILES" | tail -n +$((RETENTION + 1)))

# Borrar uno a uno con rm individual
while IFS= read -r FILE; do
    ssh -p "$PUERTO" -i "$CLAVE" \
        "${USUARIO}@${HOST}" \
        "rm \"$FILE\""
done <<< "$FILES_TO_DELETE"

Más extenso, pero funciona.


El backup del nodo Proxmox

Con el VPS arreglado, el siguiente paso lógico era el propio nodo Proxmox. PBS cubre las CTs y VMs perfectamente, pero no hace backup del hipervisor en sí. Si el miniPC muere mañana, ¿cuánto tarda reconstruir todo el entorno?

La respuesta honesta era "demasiado". Y la solución es sencilla: un script que comprime la configuración crítica del nodo y la sube al Storage Box.

¿Qué entra en el backup?

/etc/pve/          → configuración del clúster, VMs y CTs
/etc/wireguard/    → configuración VPN
/etc/network/      → interfaces de red
/etc/ufw/          → reglas del firewall
/etc/ssh/          → configuración SSH
/usr/local/bin/    → scripts propios
/etc/cron.*        → tareas programadas
/root/.ssh/        → claves SSH de root (sin authorized_keys)
/etc/hosts, /etc/fstab, /etc/environment, /etc/resolv.conf

Además, guardamos información del sistema útil para reconstruir:

pvesh get /nodes/$(hostname)/version > pve-version.txt
dpkg --get-selections > dpkg-selections.txt
ip addr show > ip-addr.txt

Todo esto junto, comprimido, pesa menos de 100KB. Noventa y dos kilobytes en mi caso. Para poder reconstruir todo el entorno del hipervisor desde cero.

Configurar el acceso SSH desde Proxmox al Storage Box

El nodo necesita su propia clave SSH para conectarse al Storage Box. Hetzner no soporta ssh-copy-id estándar — hay que usar el flag -s:

ssh-copy-id -p 23 -s -i /root/.ssh/id_rsa.pub uXXXXXX@uXXXXXX.your-storagebox.de

Verificar que conecta sin contraseña:

ssh -p 23 uXXXXXX@uXXXXXX.your-storagebox.de "ls"

Y crear el fichero de credenciales en /etc/jaws.conf siguiendo el mismo patrón que el VPS.

Retención y cron

La retención que uso para el nodo: 7 copias diarias + 4 semanales. Sin mensual — el nodo Proxmox cambia poco, con eso es más que suficiente.

El cron lo puse a las 5:00, después del backup del VPS (3:00) y de los jobs de PBS (madrugada), para no solapar cargas:

echo '0 5 * * * /usr/local/bin/proxmox-node-backup.sh' >> /var/spool/cron/crontabs/root

Al terminar, notificación por Telegram:

✅ Backup nodo Proxmox completado
📦 Tipo: daily
🕒 2026-03-28 17:21

Estado actual del sistema de backup

Con esto, el panorama de backups queda así:

Qué Herramienta Destino Cron
CTs y VMs del homelab PBS Storage Box Madrugada
VPS (webs + BBDD + configs) Script bash + rsync Storage Box 3:00
Nodo Proxmox (configuración) Script bash + rsync Storage Box 5:00
Máquinas físicas Pendiente

Las máquinas físicas — Sobremesa y el portátil — son el siguiente capítulo, y la solución es diferente: restic, una interfaz gráfica con kdialog y zenity, y la opción de apagar el equipo automáticamente al terminar el backup. Lo cuento en el próximo artículo.


Los scripts están disponibles en el repositorio jferrep/jaws-audit en GitHub.

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