La mascota oso polar de NordBastion de pie en una bóveda de piedra nórdica oscura junto a un rack de servidores, sosteniendo en alto una llave cian brillante, mientras una cadena de cinco bloques holográficos cian marcados con candados forma un arco a través de un portal rúnico hacia un segundo rack de servidores a lo lejos bajo una tenue aurora
Guía práctica · Opsec·16 min de lectura · 45 min prácticos

Backup de VPS cifrado.
Fuera de sitio, deduplicado y fuera de alcance.

Copia de seguridad de VPS cifrada en seis pasos: de un servidor sin protección a un repositorio cifrado y verificado en una segunda máquina, en una segunda jurisdicción — restic y Borg comparados, volcados de base de datos que restauran limpios, un temporizador systemd y un repositorio de solo anexado que un servidor comprometido no puede borrar. La segunda máquina cuesta $3.90 al mes. Probado en Debian 12.

Los seis pasos
  1. 01

    Inventario

    Lo que no se puede reconstruir

  2. 02

    Instalar

    restic o Borg

  3. 03

    Destino

    Un segundo bastión

  4. 04

    Inicializar

    Repositorio + primera ejecución

  5. 05

    Automatizar

    Dumps, timer, retención

  6. 06

    Simulacro

    Restaura, y cronométralo

Antes de empezar · Para qué sirve esto

Cuatro formas en que mueren los datos. Solo una de ellas es un disco roto.

Casi toda discusión sobre backups se tuerce en el primer minuto, porque las dos personas que hablan tienen en mente fallos distintos. Una está pensando en un disco muerto. La otra está pensando en un martes por la mañana en el que la cuenta ha desaparecido. Necesitan respuestas distintas, y una configuración que solo sobrevive al primero se siente segura hasta que la pone a prueba el segundo.

Hay cuatro modos de fallo contra los que merece la pena diseñar, y no son variaciones de un mismo tema — cada uno vence una defensa distinta.

Hardware. El NVMe falla, el nodo anfitrión muere, el array pierde dos miembros a la vez. Este es el fallo para el que todo el mundo se prepara, y es el más raro en la infraestructura virtualizada moderna. El almacenamiento redundante lo resuelve. El almacenamiento redundante no resuelve nada más, y por eso RAID no es una copia de seguridad y nunca lo fue: copia fielmente cada escritura, incluida la que dice «borrar todo».

Humano. Un script de migración ejecutado contra producción. Un DROP TABLE en la terminal equivocada. Un rsync con los argumentos invertidos. Esta es, con diferencia, la causa más común de pérdida real de datos, y la única defensa contra ella es el historial — una copia de antes del error, guardada en un lugar al que el error no llegó. El tiempo es el ingrediente: si la única copia es un espejo con treinta segundos de retraso, ya contiene el error.

Malicioso. Alguien obtiene acceso root, o el ransomware entra a través de una aplicación sin parchear. Lo primero que hace el ransomware moderno es buscar la configuración de las copias de seguridad — credenciales, recursos compartidos montados, claves de la nube — y destruir lo que encuentra, precisamente porque una restauración que funciona convierte una catástrofe en una tarde de trabajo. Una credencial de copia de seguridad que puede borrar es una credencial que el atacante hereda. Para este fallo existe el capítulo de solo anexado de esta guía.

De custodia. Nada se rompió y nada fue atacado; simplemente perdió el acceso. Una cuenta suspendida por una señal automática de fraude, una tarjeta que falló mientras viajaba, una disputa, una revisión de cumplimiento, una notificación cursada al proveedor. La máquina está intacta e inalcanzable, y cada instantánea dentro de esa cuenta es inalcanzable con ella. Este es el fallo que ninguna cantidad de redundancia dentro de un solo proveedor puede resolver, y la razón por la que un backup serio vive bajo un techo distinto.

Defensa Hardware Error humano Ransomware Cuenta perdida
RAID / almacenamiento redundanteNoNoNo
Instantánea del proveedor, misma cuentaParcialmenteNoNo
Repositorio externo, clave con permiso de escrituraNo
Repositorio externo, append-only, otra jurisdicción

La última fila es lo que construye el resto de esta guía. No es más cara que la fila anterior — la configuración de solo anexado es gratuita y la segunda jurisdicción cuesta lo mismo, $3.90, que la primera.

La regla 3-2-1, reformulada para un único VPS. Tres copias de los datos, en dos tipos de almacenamiento distintos, una de ellas fuera del sitio. La formulación clásica viene de una era de cintas y servidores de oficina, y el espíritu sobrevive a la traducción mejor que la letra. Para una sola máquina autoalojada, se lee así: los datos en vivo en el VPS, un repositorio en una segunda máquina en otro lugar, y — para cualquier cosa genuinamente irreemplazable — una tercera copia que puedas sostener en la mano, en un disco en casa o en un cajón. El número que realmente importa no es tres. Es cuántas cosas independientes tienen que fallar antes de que los datos desaparezcan. Dos es el mínimo que vale la pena tener.

Antes de empezar · Elección de herramienta

restic, Borg, o rsync. Dos de ellos son copias de seguridad.

La categoría que buscas se llama herramienta de instantáneas con deduplicación y cifrado. Divide cada archivo en fragmentos definidos por su contenido, cifra cada fragmento en la máquina propietaria de los datos, y lo almacena una sola vez sin importar cuántas instantáneas lo referencien. Eso te da tres propiedades a la vez: muchos puntos de restauración por apenas más espacio que uno solo, texto plano que nunca sale del origen, y una transferencia que solo mueve lo que cambió.

Dos programas dominan este espacio y ambos son excelentes. restic es un único binario estático de Go con una amplia gama de backends de almacenamiento. BorgBackup es un programa en Python que habla SSH con una copia de sí mismo en el extremo remoto. Todo lo que sigue es la diferencia honesta entre ambos.

Propiedad restic BorgBackup rsync / rclone
Cifrado del lado del clienteSiempre activo, no opcionalSiempre activo, no opcionalSolo mediante un remoto rclone crypt
DeduplicaciónFragmentos definidos por contenidoFragmentos definidos por contenidoNinguno, o árboles de hardlinks
Historial de instantáneasSí, con políticas de retenciónSí, con políticas de retenciónUn espejo de ahora mismo
Requisitos del destinoNada — SFTP, S3, REST, rcloneBorg instalado en ambos extremosUna cuenta SSH o una API
Aplicación de append-onlyMediante rest-server o bloqueo de objetosIncorporado, sobre SSH simpleNinguno
Adecuado paraCasi cualquiera, la mayoría de backendsUna máquina SSH de su propiedad, en modo append-onlyEspejo, no backup

rsync está en la tabla porque es lo primero a lo que recurre la mayoría, y porque es, genuinamente, la herramienta equivocada: un espejo reproduce fielmente una eliminación, y un espejo de un disco cifrado en reposo no está cifrado en ningún sitio por sí mismo. Se gana su lugar dentro de una copia de seguridad como lo que mueve un archivo ya terminado, no como el archivo en sí.

Esta guía muestra tanto restic como Borg para cada comando que difiere, para que puedas seguirla con cualquiera de los dos. Donde hay que elegir uno solo — el ejemplo trabajado, el temporizador, el script — usa restic, porque así el destino no necesita más que una cuenta SSH, lo cual mantiene la segunda máquina aburrida.

Paso 01 · Inventario

Lo que no se puede reconstruir. Anótalo antes de automatizarlo.

Hacer backup de todo el sistema de archivos es una elección defendible y también derrochadora. La mayor parte de un servidor está a un gestor de paquetes de distancia de poder recrearse, y cada gigabyte que arrastra hace que el repositorio sea más lento de podar, más caro de mantener y más lento de buscar cuando tiene prisa. El ejercicio útil es el contrario: liste lo que una instalación nueva no le devolvería.

Para un VPS autoalojado típico, esa lista es corta, y siempre contiene estas cinco cosas:

  • 01Contenido de la base de datos. No el directorio de datos — el dump. El paso 05 explica por qué.
  • 02Archivos subidos por los usuarios. Volúmenes de Docker, un directorio de subidas o de medios, un almacén de correo. Normalmente el grueso de los bytes.
  • 03Configuración y secretos. Los archivos Compose, los archivos .env, las claves de cifrado, los tokens de API. Pequeños, y la diferencia entre una restauración de dos horas y una de dos días.
  • 04Estado del sistema que has editado. /etc en su conjunto es lo bastante pequeño como para incluirlo entero — configuración de sshd, reglas de firewall, unidades de systemd, entradas de cron, el enrutamiento de correo al que dedicó una tarde.
  • 05Cualquier cosa con una identidad asociada. Una clave de servicio oculto de Tor, una clave de firma de Matrix, una clave privada de WireGuard, un monedero de nodo. Pierda una de estas y el servicio no vuelve — vuelve un servicio distinto con el mismo nombre.

Convierte la lista en dos archivos en el servidor de origen. Una lista de inclusión mantiene visible la intención; una lista de exclusión mantiene fuera el ruido. Ambas las lee el comando de copia de seguridad, y ambas deben formar parte también de la propia copia de seguridad.

/etc/backup/include.txt

/etc
/opt
/root
/var/backups
/var/lib/docker/volumes
/home

/etc/backup/exclude.txt

# Caches and rebuildable artefacts
**/node_modules
**/.cache
**/*.tmp
/var/lib/docker/volumes/*/_data/cache
# Log noise — keep the config, drop the volume
/var/log/journal
# Never back up the mount point you restore into
/mnt/restore

Dos notas sobre esa línea de Docker, porque suele confundir a la gente. Los volúmenes con nombre viven bajo /var/lib/docker/volumes y son lo que quieres; los bind mounts viven donde tú los pongas, normalmente junto al archivo Compose, y quedan cubiertos por /opt. Las imágenes de contenedor no son datos — vuelven con un pull, y una copia de seguridad que las incluye carga con gigabytes que no necesita.

Por último, mida el resultado antes de construir nada alrededor de él. El número le dice qué nivel de repositorio pedir y si la primera ejecución tardará cuatro minutos o cuarenta:

du -sh --exclude=/var/lib/docker/overlay2 /etc /opt /root /home /var/lib/docker/volumes
Paso 02 · Instalar

Un binario en el origen. Nada más cambia.

Instale la herramienta en la máquina propietaria de los datos. En Debian y Ubuntu ambas están empaquetadas, y en el caso de restic el paquete de la distribución suele ir una o dos versiones por detrás — lo cual importa, porque las funciones de repositorio y las mejoras de rendimiento llegan en las versiones menores. Instale el paquete y después deje que restic se actualice a sí mismo:

apt update && apt install -y restic
restic self-update
restic version

Para Borg, el paquete de la distribución es la elección correcta, porque la versión del origen y la versión del destino tienen que entenderse entre sí, y un par emparejado de la misma versión de la distribución es la forma menos dolorosa de conseguirlo:

apt install -y borgbackup
borg --version

Una palabra sobre las versiones mayores antes de confiar años de historial a un repositorio: el formato de repositorio de Borg cambió entre sus líneas mayores, y mover un repositorio a través de ese límite es una conversión, no una actualización. Lea las notas de la versión que va a instalar y mantenga el destino en la misma línea mayor que el origen. restic ha sido compatible hacia adelante entre sus versiones y añade funciones tras una versión de repositorio explícita, así que ahí la preocupación equivalente es menor.

Ninguna de las dos herramientas necesita un daemon, un agente o un puerto abierto en el origen. Merece la pena decirlo en voz alta: el sistema de backup que está instalando no añade ningún servicio a la escucha ni ninguna superficie de ataque nueva a la máquina que protege. Todo lo que hace es saliente, según un horario, por SSH.

Paso 03 · Destino

Un segundo bastión, y una clave que no puede borrar. Este es el paso que importa.

El host del repositorio tiene una sola tarea y casi ningún requisito. No necesita núcleos de CPU, porque nunca lee tus datos — solo guarda blobs cifrados que no puede abrir. No necesita memoria, porque el trabajo de deduplicación ocurre en el origen. Necesita disco, una dirección estable, y estar en algún lugar donde los problemas de la máquina de origen no lo alcancen.

En el panel: Order → VPS → Sentinel, imagen Debian 12, y — el objetivo de todo esto — un bastión distinto de aquel en el que funciona el origen. Helsinki trabajando, Reykjavík guardando. No se requiere ninguna dirección de correo para abrir la cuenta y la factura se liquida en Monero, Bitcoin, Lightning o cualquier otro de los activos admitidos, lo que significa que la segunda máquina no vuelve a introducir la identidad que la primera había cuidado tanto.

Destino del repositorio Mensual Almacenamiento Conjunto de trabajo que contiene Coste de restaurar
Sentinel$3.90120 GB NVMe~30 GBNada — sin medición
Garrison$7.90240 GB NVMe~70 GBNada — sin medición
Ravelin$16.90480 GB NVMe~150 GBNada — sin medición
Bulwark$32.90960 GB NVMe~300 GBNada — sin medición
Almacenamiento de objetos de clase S3~$0.023/GBElásticoCualquieraSalida medida

La columna del conjunto de trabajo asume instantáneas diarias conservadas durante un año con una rotación normal; un repositorio que contiene sobre todo archivos que cambian poco llega mucho más lejos, y uno lleno de binarios grandes reescritos llega mucho menos lejos. La última fila está ahí por la escala, y por el detalle que la gente olvida hasta el mal día: el almacenamiento de objetos también cobra por la descarga, y la descarga es justo lo que haces en una emergencia.

En el destino — un usuario sin privilegios y un directorio.

adduser --disabled-password --gecos "" backup
install -d -m 0700 -o backup -g backup /srv/restic/web01

El usuario de la copia de seguridad no tiene contraseña, ni sudo, ni nada en lo que iniciar sesión. Existe solo para ser propietario de un directorio. Dale un directorio propio por cada máquina de origen si respaldas varias — un repositorio por origen evita que el compromiso de una máquina afecte al historial de otra.

En el origen — una clave que no se usa para nada más.

ssh-keygen -t ed25519 -f /root/.ssh/id_backup -N "" -C "backup:web01"
cat /root/.ssh/id_backup.pub

No reutilice su clave de acceso habitual. Esta vive sin cifrar en disco porque un timer desatendido tiene que usarla a las tres de la madrugada, que es exactamente el tipo de clave que conviene limitar a un único destino y un único propósito.

De vuelta en el destino — restrinja lo que esa clave puede hacer. Pega la clave pública en /home/backup/.ssh/authorized_keys con un prefijo delante. Para restic sobre SFTP:

restrict,from="198.51.100.7" ssh-ed25519 AAAAC3NzaC1lZDI1... backup:web01

La opción restrict desactiva de una vez el reenvío de puertos, el reenvío del agente, X11 y la asignación de PTY, dejando solo la transferencia de archivos y nada más. La cláusula from= fija la clave a la dirección de origen, así que una copia de ella robada del servidor es inútil en cualquier otro sitio. Para Borg, ve un paso más allá y fuerza el comando, que es donde vive su modo de solo anexado:

command="borg serve --append-only --restrict-to-path /srv/borg/web01",restrict ssh-ed25519 AAAAC3NzaC1lZDI1... borg:web01

Esa línea concentra toda la defensa contra el ransomware en un solo lugar: sea lo que sea lo que envíe el origen, el destino solo ejecutará borg serve, solo dentro de esa ruta, y solo en un modo que anexa. Una shell root en el origen no puede usar esta clave para borrar el mes pasado.

Nombre el destino una vez, en el origen. Ponlo en /root/.ssh/config para que cada comando posterior sea corto y la dirección viva en un único archivo:

Host rkv-repo
    HostName 198.51.100.42
    User backup
    IdentityFile /root/.ssh/id_backup
    IdentitiesOnly yes

Luego conéctate una vez a mano — ssh rkv-repo — para aceptar la clave del host. Un temporizador desatendido no responderá a un aviso de huella digital, y una primera copia de seguridad que se queda colgada en silencio durante una semana es un clásico. Mientras estés en el destino, dale el mismo trato que a cualquier otra máquina tuya: ejecuta también en él la lista de refuerzo de la primera hora. Guarda una copia de todo, y se merece la hora completa.

Paso 04 · Inicializar

La frase de contraseña, y luego la primera instantánea. En ese orden, y fuera de la máquina.

Genere una frase de contraseña que nunca tendrá que teclear. Un script la lee desde un archivo, así que la longitud no cuesta nada y no hay razón para hacerla memorizable:

openssl rand -base64 32 > /root/.restic-pass
chmod 600 /root/.restic-pass
cat /root/.restic-pass

Ahora deténgase y copie esa cadena en algún sitio que no sea este servidor. Un gestor de contraseñas, una nota en papel en un cajón, una segunda máquina — cualquier lugar que sobreviva a la pérdida del origen. Es el mismo fallo que destruye los vaults autoalojados y los motores de automatización: la clave que descifra todo se guarda junto a todo, y ambos se pierden juntos. Un repositorio cuya frase de contraseña existía solo en la máquina que protegía no es un backup; es un montón de ruido muy bien ordenado.

Escribe el archivo de entorno que leerán todos los comandos posteriores:

/etc/backup/restic.env

RESTIC_REPOSITORY=sftp:rkv-repo:/srv/restic/web01
RESTIC_PASSWORD_FILE=/root/.restic-pass
chmod 600 /etc/backup/restic.env
set -a; . /etc/backup/restic.env; set +a
restic init

El par equivalente para Borg — el modo repokey almacena la clave de cifrado dentro del repositorio, protegida por la frase de contraseña, lo cual es cómodo y es precisamente la razón por la que también exportas una copia de ella:

export BORG_REPO=ssh://borg@rkv-repo/srv/borg/web01
export BORG_PASSCOMMAND="cat /root/.restic-pass"
borg init --encryption=repokey-blake2
borg key export ::  /root/borg-key.txt   # copy this off the server too

La primera instantánea. Ejecútalo a mano, obsérvalo y deja que termine antes de automatizar nada. Esta es la ejecución lenta — cada fragmento es nuevo — y es la que te dice si la lista de inclusión era correcta:

restic backup \
  --files-from /etc/backup/include.txt \
  --exclude-file /etc/backup/exclude.txt \
  --tag nightly --one-file-system --verbose

Si el origen está sirviendo tráfico y la subida está saturando el enlace, límitela. El flag toma kibibytes por segundo, así que 20000 son aproximadamente 20 MB/s:

restic backup --limit-upload 20000 --files-from /etc/backup/include.txt

Cuando termine, mira qué obtuviste realmente. Estos tres comandos son los que debes ejecutar ahora, y de nuevo dentro de seis meses, cuando ya hayas dejado de pensar en todo esto:

restic snapshots                    # the list, with dates and tags
restic stats latest                 # what the newest snapshot contains
restic ls latest /etc/backup        # confirm a path you expected is in there

Ese tercer comando merece un momento de atención. La mitad de las copias de seguridad «rotas» no están rotas en absoluto — son repositorios completos y sanos del directorio equivocado. Listar una ruta que esperabas encontrar, ya en la primera instantánea, detecta esto mientras el archivo de inclusión todavía está fresco en tu memoria.

Paso 05 · Automatizar

Primero el dump, luego la instantánea. Un script, un timer, una política de retención.

La regla de las bases de datos, dicha una sola vez. Un motor de base de datos en ejecución mantiene el estado en memoria y lo escribe a su propio ritmo. Si lee sus archivos mientras hace eso, obtiene un conjunto de páginas de varios momentos distintos — un archivo que puede restaurarse, puede restaurarse corrupto, o puede restaurarse en algo que abre sin problemas y silenciosamente le falta la última hora. No hay forma de saber cuál desde fuera. Por eso el backup nunca toca los archivos en vivo: primero se escribe un dump en disco, y el backup recoge ese dump.

Todo va en un solo script. Colóquelo en /usr/local/sbin/nb-backup.sh, hágalo ejecutable, e inclúyalo en el propio backup:

#!/bin/sh
set -eu

# ---- 1. Consistent dumps, written where the include list will find them.
install -d -m 0700 /var/backups/db

# PostgreSQL in a container:
docker exec -t app-db pg_dumpall -U postgres | gzip -9 > /var/backups/db/postgres.sql.gz

# MariaDB / MySQL, InnoDB tables:
# docker exec -t mail-db mariadb-dump --single-transaction --all-databases \
#   | gzip -9 > /var/backups/db/mariadb.sql.gz

# SQLite — never a plain file copy:
# sqlite3 /opt/app/data/app.db ".backup '/var/backups/db/app.db'"

# ---- 2. The snapshot.
restic backup \
  --files-from /etc/backup/include.txt \
  --exclude-file /etc/backup/exclude.txt \
  --tag nightly --one-file-system

# ---- 3. Retention, then reclaim the space it freed.
restic forget --keep-daily 7 --keep-weekly 4 --keep-monthly 12 --prune

# ---- 4. Structural check every night; read 5% of the data on Sundays.
restic check
[ "$(date +%u)" = "7" ] && restic check --read-data-subset=5%

echo "backup ok: $(date -u +%FT%TZ)"

Tres detalles de ese script hacen más trabajo del que parece. El set -eu al principio significa que un volcado fallido aborta la ejecución en lugar de guardar en silencio, durante los siguientes seis meses, una instantánea del volcado de ayer. El forget y el prune son un solo comando, porque una política de retención que nunca recupera espacio es un disco que se llena. Y la comprobación del domingo lee una porción de los datos reales en lugar de solo el índice — la corrupción del repositorio es rara, y silenciosa, y lo único que la detecta es leer.

El temporizador. Dos pequeños archivos de unidad. systemd es el planificador correcto aquí, y no cron, porque un timer te da Persistent — una ejecución perdida mientras la máquina estaba apagada ocurre en el siguiente arranque en lugar de saltarse en silencio — y porque journalctl guarda entonces el historial de cada ejecución.

/etc/systemd/system/nb-backup.service

[Unit]
Description=Nightly encrypted offsite backup
Wants=network-online.target
After=network-online.target docker.service

[Service]
Type=oneshot
EnvironmentFile=/etc/backup/restic.env
ExecStart=/usr/local/sbin/nb-backup.sh
Nice=10
IOSchedulingClass=idle

/etc/systemd/system/nb-backup.timer

[Unit]
Description=Nightly encrypted offsite backup

[Timer]
OnCalendar=*-*-* 03:00:00
RandomizedDelaySec=45m
Persistent=true

[Install]
WantedBy=timers.target
systemctl daemon-reload
systemctl enable --now nb-backup.timer
systemctl list-timers nb-backup.timer
systemctl start nb-backup.service && journalctl -u nb-backup.service -n 40 --no-pager

El retraso aleatorio no es decorativo. Todos los servidores autoalojados de internet ejecutan su mantenimiento exactamente a las 03:00, y una copia de seguridad que empieza en el mismo segundo que la rotación de logs, la renovación del certificado y la actualización de contenedores pasa la noche compitiendo con ellos por E/S. Repartir el inicio en un margen de cuarenta y cinco minutos no cuesta nada y elimina toda una categoría de noches lentas y misteriosas.

Después, haz que el fallo sea ruidoso. Este es el paso que todo el mundo se salta y es el que decide si todo lo anterior valió la pena. Una copia de seguridad que deja de funcionar no lo anuncia: el temporizador sigue disparándose, el servicio sigue fallando, y la última instantánea buena se aleja cada vez más en el pasado mientras el panel sigue en verde. Añade una unidad OnFailure= al servicio que te envíe algo que realmente vayas a ver, y una vez al mes echa un vistazo a la parte superior de la lista de instantáneas. Una línea, un hábito.

restic snapshots --latest 3        # is the newest one from last night?
systemctl list-timers nb-backup.timer   # is the timer still armed?
Paso 06 · Simulacro

Restáuralo ahora, mientras nada está ardiendo. Una copia de seguridad no probada es un rumor.

Hay dos simulacros, y responden a preguntas distintas. El pequeño pregunta «¿los datos realmente están ahí y son legibles?» y toma noventa segundos. El grande pregunta «¿cuánto tardaría realmente en recuperar el servicio?» y toma una tarde, una vez al año. Haz el pequeño mensualmente. Haz el grande al menos una vez, porque la respuesta nunca es la que la gente imagina.

El simulacro pequeño. Extrae un directorio y un volcado a una ruta temporal, y compáralos con lo que está en producción:

install -d -m 0700 /mnt/restore
restic restore latest --target /mnt/restore --include /etc/backup
restic restore latest --target /mnt/restore --include /var/backups/db

diff -r /etc/backup /mnt/restore/etc/backup && echo "config identical"
gzip -t /mnt/restore/var/backups/db/postgres.sql.gz && echo "dump readable"

Mejor aún, cuando la herramienta lo ofrece: monte el repositorio en modo solo lectura y recórralo como un sistema de archivos. Cada instantánea aparece como un directorio con fecha, y puede explorar el historial con ls y cat sin necesidad de restaurar nada. Requiere FUSE en la máquina que hace el montaje:

restic mount /mnt/snapshots      # then: ls /mnt/snapshots/snapshots/latest/
borg mount ::  /mnt/snapshots     # the Borg equivalent

El simulacro grande. Pide un VPS temporal por horas, y reconstruye el servicio en él solo a partir del repositorio — sin notas de memoria, sin archivos copiados de la máquina en producción. Trabaja a partir de un runbook escrito y corrígelo sobre la marcha, porque los vacíos que encuentres son el objetivo mismo del ejercicio. Los descubrimientos habituales, por orden de frecuencia: la frase de contraseña solo estaba en la máquina caída; los registros DNS nunca se anotaron; un directorio montado con bind mount quedaba fuera de toda ruta de inclusión; la restauración necesitaba una versión de paquete que ya no es la predeterminada; nadie sabía qué contenedor debía arrancar primero.

Cronométralo. Anota el número en la parte superior del runbook junto con la fecha. Ese número — no el tamaño del repositorio, ni el número de instantáneas — es la única medida honesta de cuán protegido está realmente el servicio.

Y lea los datos de vez en cuando. La comprobación nocturna verifica la estructura: que el índice concuerda consigo mismo y que no falta ningún blob. No lee los blobs. Una vez al mes, o en la ejecución del domingo, lee una porción de ellos — un cinco por ciento rotativo cubre todo el repositorio en un par de meses sin que ninguna noche se alargue demasiado:

restic check --read-data-subset=5%
borg check --verify-data              # the Borg equivalent, slower and thorough
La parte difícil · Solo anexado

Una clave que puede escribir, pero no borrar. La diferencia entre una mala semana y un negocio cerrado.

Todo lo anterior protege contra accidentes. Este capítulo protege contra un adversario, y el problema de diseño resulta incómodo en cuanto se ve: la máquina de origen tiene que alcanzar el repositorio cada noche, lo que significa que la máquina de origen guarda una credencial funcional del repositorio. Quien controla el origen controla esa credencial. Si la credencial puede borrar, el atacante borra — y el ransomware moderno hace exactamente esto, a propósito, antes de cifrar nada, porque una víctima que puede restaurar no paga.

La solución no es una contraseña mejor. Es un permiso asimétrico: el origen puede añadir datos y no puede eliminar ninguno. Tres formas de construirlo, en orden descendente de facilidad para hacerlo bien.

Uno — solo anexado forzado por SSH. Este es el terreno natural de Borg y es la respuesta más limpia disponible en una máquina que posees. La entrada de authorized_keys del paso 03 fuerza borg serve --append-only, así que el extremo remoto rechaza las eliminaciones sin importar lo que pida el extremo cercano. La poda sigue teniendo que ocurrir, pero ocurre desde el lado del destino, según un calendario que el origen no puede influir, ejecutada por una cuenta a la que el origen no puede acceder. Un atacante con root en el origen puede llenar el repositorio de basura; no puede eliminar el archivo de la noche anterior a su llegada.

Dos — un endpoint REST de solo anexado. El rest-server que acompaña a restic tiene un modo --append-only con la misma propiedad: se aceptan blobs nuevos, los existentes no se pueden eliminar. Ejecútalo en el destino detrás de TLS, apunta RESTIC_REPOSITORY a la URL https:// en lugar de la sftp:, y la forma de la defensa es idéntica. Cuesta un servicio más en el destino y compra la misma garantía.

Tres — bloqueo de objetos. En almacenamiento compatible con S3, el versionado más un periodo de retención con object-lock hace imposible el borrado hasta que expira el periodo, aplicado por la capa de almacenamiento y no por un programa. Es el más fuerte de los tres y el más caro, e introduce una cuenta de proveedor — lo que reintroduce el riesgo de custodia que toda esta guía intenta repartir. Sensato como tercera copia, incómodo como la única.

Si nada de eso encaja — SFTP simple, una clave que puede escribir y por tanto borrar — no finja lo contrario; añada una segunda copia, independiente, que el origen no pueda tocar en absoluto. Pull en lugar de push: deje que el destino inicie sesión en el origen, lea lo que necesita y lo guarde. Las credenciales viven entonces en la máquina que no está expuesta, y un atacante en el origen no encuentra nada que apunte al backup. Cuesta un poco más de trabajo montarlo, pero invierte el riesgo exactamente en la dirección correcta.

Elijas lo que elijas, verifícalo como verificarías cualquier otro control de seguridad — intentando romperlo. Desde el origen, con la clave de la copia de seguridad, intenta borrar algo. El resultado correcto es un rechazo.

borg delete ::name-of-an-old-archive
# → Remote: Repository is in append-only mode. Refusing to delete.
Notas de campo · Por servicio

El único archivo sin el que cada servicio no puede volver. Rara vez es el más grande.

Cada servicio tiene un pequeño fragmento de estado que no es datos ni es configuración, y perderlo no daña el servicio — lo sustituye por un servicio distinto que resulta tener el mismo nombre. Los enlaces antiguos se rompen, los pares federados rechazan la nueva identidad, los clientes regeneran sus claves. Estas son las piezas, por stack, para las cosas de las que este sitio tiene guías.

Nextcloud

El directorio de datos, config/config.php, y un volcado de la base de datos. Activa el modo de mantenimiento para el volcado, y desactívalo después — de lo contrario Nextcloud escribe en ambos a la vez.

Vaultwarden

Todo el directorio de datos: db.sqlite3 tomado con .backup en lugar de copiado, más los archivos rsa_key, los adjuntos y los envíos.

Matrix Synapse

La clave de firma, homeserver.yaml, el almacén de medios y un volcado de PostgreSQL. Si pierdes la clave de firma, la identidad de federación se pierde para siempre.

Servidor de correo

El propio almacén de correo, las tablas de usuarios virtuales, y las claves privadas DKIM — una nueva clave DKIM significa que todos los mensajes quedan sin firmar hasta que el DNS se pone al día.

n8n

Primero N8N_ENCRYPTION_KEY, luego el dump de PostgreSQL. La base de datos sin esa clave es una lista de flujos de trabajo cuyas credenciales son todas ilegibles.

Servicio onion de Tor

El directorio del servicio oculto. Esos pocos archivos son la dirección .onion — sin ellos el servicio vuelve bajo un nombre distinto y todos los enlaces hacia él quedan muertos.

WireGuard

/etc/wireguard completo. Pequeño, aburrido, y la diferencia entre una reconstrucción de cinco minutos y tener que regenerar las claves de cada dispositivo que posee.

Lightning node

La semilla y el estado de los canales, en los términos propios del nodo. Restaurar datos de canal obsoletos puede costarte fondos — sigue el procedimiento de copia de seguridad de la implementación, no una copia de archivos genérica.

La capa bajo el almacenamiento

La distancia es una respuesta técnica. La jurisdicción es la otra mitad.

Pregunte a la mayoría por qué el backup debería estar en otro sitio y la respuesta es incendio, inundación o un datacenter que pierde la corriente. Todo cierto, todo cada vez más raro, y todo resuelto con un centenar de kilómetros de distancia. Los fallos que realmente hunden negocios en 2026 son administrativos, y la distancia por sí sola no hace nada contra ellos.

Una cuenta es un único punto de fallo. Una suspensión por una señal automática de fraude, una devolución de cargo mientras estaba en un avión, una revisión de cumplimiento, una orden de retirada dirigida a la empresa y no a una máquina — cada una de ellas alcanza a todos los servidores de esa cuenta en el mismo instante, incluido el que guarda las instantáneas. La redundancia técnica era perfecta e irrelevante. Dos proveedores, o como mínimo dos cuentas bajo dos techos legales distintos, es la única estructura que responde a esto.

Una jurisdicción es un único marco legal. Los cuatro bastiones nórdicos no son intercambiables — Suecia, Finlandia, Noruega e Islandia protegen cada uno algo ligeramente distinto, y Noruega e Islandia quedan completamente fuera de la Unión Europea. Repartir una máquina de trabajo y su repositorio entre dos de ellos significa que la copia no está simplemente en otro lugar; está bajo un segundo conjunto de normas, independiente. La referencia de jurisdicciones nórdicas repasa la legislación una por una.

Y el destino no aprende nada. Esto es lo que hace que el reparto sea barato en lugar de un compromiso. Tanto restic como Borg cifran antes de que nada salga del origen, así que el host del repositorio almacena blobs para los que no tiene clave. No sabe qué archivos contiene, ni cuántos son, ni cómo se llaman. No estás extendiendo confianza a un tercero; estás alquilando un disco que no puede leerse a sí mismo. Esa es también la respuesta honesta a «¿debería usar como destino de copia de seguridad un proveedor en el que no confío del todo?» — para un repositorio cifrado, la confianza apenas entra en juego.

La latencia no es un factor. Helsinki a Reykjavík son 30 ms por la red troncal, Helsinki a Stockholm 8 ms, Stockholm a Oslo 11 ms. A un backup nocturno no le importa ninguno de esos números, y tampoco le importa a una restauración limitada por el rendimiento del disco. Elija el par por distancia legal, no por distancia de red — la distancia de red dentro de los países nórdicos es un error de redondeo.

Una cosa más que merece decirse sin rodeos, porque es la razón por la que esta guía está en este sitio y no en un blog genérico de sysadmin: la segunda máquina reabre todas las preguntas que la primera ya había respondido. Si el VPS de trabajo se pidió sin documento de identidad y se pagó en Monero, y luego la máquina de backup para ese VPS se pide con una tarjeta de empresa y un escaneo de pasaporte, el par es exactamente tan identificable como la mitad más débil. La guía pilar sobre hosting VPS anónimo recorre las tres capas — registro, pago, red — y se aplican a un destino de backup tan literalmente como a un servidor web.

Notas de campo · Seis trampas

Seis formas en que una copia de seguridad resulta no serlo. Todas ellas descubiertas en el mal día.

Trampa 01 · Irreversible

La frase de contraseña solo estaba en la máquina caída

El repositorio está intacto, cifrado, y es permanentemente ilegible. Guarda la frase de contraseña — y para Borg la clave exportada — en un gestor de contraseñas y en papel, antes de la primera instantánea.

Trampa 02 · Consistencia

La base de datos se restaura, y luego falla en la primera consulta

Se copiaron los archivos de datos en vivo en lugar de volcarlos con un dump. Escriba un dump en un paso previo al backup y haga backup del dump; nunca apunte la lista de inclusión al directorio de datos de un motor en ejecución.

Trampa 03 · Radio de impacto

El intruso borró primero las copias de seguridad

Una credencial con permiso de escritura en una máquina comprometida es una credencial con permiso de escritura para el atacante. Fuerce el modo append-only en el destino, o tome la segunda copia por pull en lugar de por push.

Trampa 04 · Capacidad

El repositorio es más grande que el servidor

forget sin prune marca instantáneas y no libera nada. Ejecútalos juntos, mantén espacio libre en el destino, y nunca respaldes imágenes de contenedor ni node_modules.

Trampa 05 · Silencio

La última instantánea buena tiene cinco meses

El temporizador falló tras una actualización y nada lo indicó. Añade una unidad OnFailure=, y revisa la parte superior de la lista de instantáneas una vez al mes — toma diez segundos.

Trampa 06 · Alcance

Todo se restauró excepto un directorio

Un bind mount fuera de /opt, un volumen movido durante una migración, un patrón de exclusión que coincidió con más de lo previsto. Verifique una ruta conocida en cada instantánea nueva, y vuelva a leer el archivo de inclusión tras cualquier cambio en el stack.

FAQ · Backup de VPS

Preguntas, respondidas.

Diez preguntas que surgen al configurarlo — y dos que solo surgen después, una sola vez.

¿Es una instantánea del proveedor un backup de verdad?

No — es un rollback, y útil, pero falla justo en los momentos para los que existe un backup. Una instantánea vive dentro de la misma cuenta de proveedor que el servidor que copia. Si la cuenta se suspende, si se disputa un pago, si un agente de soporte borra algo por error, o si un atacante consigue sus credenciales del panel, la instantánea se va con la máquina. Tampoco le da nada granular: no puede recuperar un único archivo eliminado de ayer, solo retroceder todo el disco y perder todo lo posterior. Conserve las instantáneas — son la forma más rápida de deshacer una mala actualización — pero no las confunda con una copia que existe en algún lugar al que el problema original no puede llegar. La regla general: si una credencial comprometida puede destruir ambas copias, tiene una sola copia.

restic o Borg: ¿cuál debería usar realmente?

Ambas cifran en el cliente, ambas deduplican a nivel de fragmento, ambas son maduras, y ambas hacen el trabajo. Elija restic si quiere un único binario estático, un repositorio que pueda vivir en SFTP, almacenamiento de objetos compatible con S3, un servidor REST o cualquier cosa a la que rclone pueda llegar, y nada instalado en el destino. Elija Borg si el destino es una máquina SSH que usted controla, quiere la aplicación de append-only más fuerte disponible sin almacenamiento con object-lock, y le gusta su compresión ligeramente más ajustada. Las diferencias prácticas que deciden la elección: Borg necesita borg instalado en ambos extremos y solo habla SSH o una ruta local; restic necesita un paso de poda que toma brevemente un bloqueo exclusivo sobre el repositorio. Si no puede decidirse, use restic — menos piezas móviles en el destino vale más que cualquier benchmark.

¿Cuánto disco necesita la máquina de backup?

Empieza por el tamaño de lo que realmente respaldas — no el tamaño del disco en el que vive. Una pila autoalojada típica son unos pocos gigabytes de base de datos y configuración, más lo que hayan subido los usuarios. Ahí es donde la deduplicación y la compresión demuestran su valor: una instantánea diaria de un conjunto de trabajo de 20 GB con una política de retención de doce meses suele acabar entre 40 y 80 GB de repositorio, porque solo los fragmentos modificados se almacenan más de una vez. Un Sentinel ($3.90/mes, 120 GB NVMe) cubre esto con holgura. Pasa a un Garrison (240 GB, $7.90) cuando varios servidores respalden en el mismo host de repositorio, y a un Bulwark (960 GB, $32.90) cuando el conjunto de trabajo en sí llegue a cientos de gigabytes. Dimensiona para el repositorio, y luego duplícalo — un repositorio sin espacio libre no puede podar, y un repositorio que no puede podar solo crece.

¿Puedo hacer backup de una base de datos en vivo copiando sus archivos?

Puedes copiarlos. Puede que no puedas restaurarlos. Una base de datos que escribe en disco mientras la lees te entrega un conjunto de archivos de varios instantes distintos, que es la definición misma de una copia de seguridad desgarrada — se restaura como una base de datos corrupta, o peor, como una base de datos que abre bien y a la que, en silencio, le faltan filas. La solución es un volcado: pg_dump o pg_dumpall para PostgreSQL, mariadb-dump --single-transaction para MariaDB y MySQL en tablas InnoDB, y sqlite3 db .backup out.db o VACUUM INTO para SQLite. Escribe el volcado en un archivo, y luego respalda ese archivo. Si la base de datos es demasiado grande para volcarla cada noche, las alternativas son una instantánea del sistema de archivos tomada mientras el motor está brevemente en pausa, o la propia herramienta de copia de seguridad física del motor — pero para cualquier cosa que ejecute un único VPS, un volcado es lo correcto y es sencillo.

¿Qué pasa si pierdo la frase de contraseña del repositorio?

Las copias de seguridad desaparecen. Tanto restic como Borg cifran del lado del cliente, y ninguno tiene una vía de recuperación, una clave maestra, ni un ticket de soporte que te desbloquee un repositorio. Ese es precisamente el punto: el host de destino — incluido uno que no es tuyo — nunca ve tu texto plano. Esto también significa que la frase de contraseña es ahora un dato que vale exactamente tanto como todo lo que protege, y no debe vivir únicamente en la máquina que se respalda. Guárdala en tu gestor de contraseñas, y guarda una copia en algún soporte físico. Para Borg, exporta también la clave del repositorio con borg key export y guárdala junto a ella; en modo repokey la clave vive dentro del repositorio, así que un repositorio al que ya no puedas acceder se lleva la clave consigo.

¿Cómo evito que un servidor comprometido borre sus propios backups?

Le das una credencial que puede añadir pero no eliminar. Esta es la decisión de diseño más importante de todo el ejercicio, porque el ransomware moderno busca primero la configuración de las copias de seguridad y la sigue hasta su origen. Tres formas de conseguirlo. Solo anexado por SSH: en el authorized_keys del destino, fuerza el comando borg serve --append-only --restrict-to-path /srv/borg — el origen puede escribir archivos nuevos y no puede borrar los antiguos. Solo anexado por REST: ejecuta el rest-server de restic con --append-only y apunta el repositorio hacia él por HTTPS. Bloqueo de objetos: un bucket compatible con S3 con versionado y un bloqueo de retención. El SFTP puro no te da nada de esto — una clave que puede escribir en un repositorio puede borrarlo — así que si SFTP es tu medio de transporte, combínalo con una segunda copia basada en pull tomada desde el lado del destino, donde las credenciales que un atacante capture en el origen no llegan.

¿Con qué frecuencia deben ejecutarse los backups, y cuánto tiempo debo conservarlos?

Plantéelo al revés: ¿cuánto trabajo está dispuesto a rehacer? Ese número es su objetivo de punto de recuperación, y es el que fija el intervalo. Una copia nocturna es adecuada para casi cualquier servicio autoalojado — un servidor de correo, un Nextcloud, un homeserver de Matrix, un motor de flujos de trabajo. Una copia cada hora merece la pena cuando los datos son transaccionales y volver a introducirlos es imposible. Para la retención, el patrón que sobrevive al contacto con la realidad es --keep-daily 7 --keep-weekly 4 --keep-monthly 12: una semana de deshacer granular, un mes de puntos de control semanales, un año de mensuales, para unas 23 instantáneas. La cola larga importa más de lo que se espera, porque el fallo que detecta no es un disco muerto — es una corrupción o una eliminación que nadie notó durante seis semanas.

¿De verdad la segunda copia tiene que estar en otro país?

Un edificio distinto es el mínimo técnico; una jurisdicción distinta es la parte que la mayoría se salta y luego lamenta. Un incendio, una inundación o un fallo a nivel de rack se resuelve solo con distancia. Lo que la distancia no resuelve es lo legal o lo comercial: una cuenta suspendida por un proveedor, una disputa de pago, una orden de retirada que alcanza a todas las máquinas bajo el mismo techo corporativo, una notificación cursada a una empresa. Si ambas copias viven con el mismo proveedor, una sola carta llega a las dos. Repartir el par entre dos bastiones nórdicos — la máquina de trabajo en Helsinki, el repositorio en Reykjavík, a 30 ms por la red troncal — no cuesta nada en latencia y compra un segundo marco legal. Los datos se cifran antes de salir del origen en cualquier caso, así que el destino no aprende nada al guardarlos.

¿Cuánto tarda el primer backup, y lo ralentiza el cifrado?

El cifrado no es el cuello de botella — las CPU modernas hacen AES más rápido de lo que un enlace de gigabit puede transportar el resultado, y ambas herramientas usan aceleración por hardware donde existe. El cuello de botella es la primera subida, porque todo es nuevo: en una subida de 1 Gbps, un conjunto de trabajo de 20 GB tarda unos minutos a velocidad de línea, y bastante más si el destino está limitado o los archivos son muchos y pequeños. Cada ejecución posterior transfiere solo los fragmentos que cambiaron, que para un stack típico son decenas de megabytes y termina en menos de un minuto. Si la primera ejecución compite con una carga de producción, límitela — restic acepta --limit-upload en KiB/s, Borg acepta --upload-ratelimit — y ejecútela bajo nice e ionice.

¿De verdad hay que probar las restauraciones?

Sí, y la razón no es la paranoia — es que los fallos habituales son silenciosos. El temporizador que dejó de dispararse tras una actualización de paquetes. El patrón de exclusión que se tragó en silencio el directorio de subidas. El volcado de base de datos escrito en una ruta que la copia de seguridad nunca cubrió. El repositorio que lleva semanas fallando su comprobación de integridad en un log que nadie lee. Ninguno de estos se anuncia por sí solo; todos se descubren en noventa segundos restaurando un archivo y mirándolo. Haz una restauración pequeña mensualmente — extrae un volcado de base de datos y un directorio de datos a una ruta temporal y compáralos — y una reconstrucción completa una vez al año, en un VPS nuevo, cronometrada. El número que resulta de esa reconstrucción es tu tiempo de recuperación real, y rara vez es el número que habrías imaginado.

Consiga la segunda máquina

Un bastión de repositorio en una segunda jurisdicción nórdica. Sin KYC, pago en criptomoneda.

Sentinel — 120 GB de NVMe por $3.90 al mes, en Helsinki, Stockholm, Oslo o Reykjavík. Ancho de banda sin medición, así que restaurar no cuesta nada. Sin correo electrónico al registrarte, sin documento de identidad, y un destino que no puede leer ni un byte de lo que almacena.

Última revisión · 2026-08-24 · Fuentes · Documentación de restic y BorgBackup, manuales de copias de seguridad de PostgreSQL y MariaDB, sshd authorized_keys(5), systemd.timer(5) · Cadencia · anual