Para quién es
Tienes un servidor PostgreSQL, en un VPS o en una máquina en un rincón de la oficina, y tu backup es un pg_dump nocturno. Eso te protege de perder el disco. No te ayuda cuando alguien ejecuta DELETE FROM orders sin WHERE a las 10:15 y tú te das cuenta a las 10:40. Un dump de anoche te devuelve 12 horas atrás. La recuperación a un punto en el tiempo te devuelve a las 10:14.
pgBackRest y Barman son herramientas completas y requieren una tarde para aprenderlas. Para un servidor pequeño, este kit es la versión corta: scripts bash, un archivo, un cluster, nada escondido.
Qué hace
- Archivado continuo de WAL configurado con seguridad: nunca sobrescribe un archivo, falla con claridad si el disco está lleno o en solo lectura, y un archivado que falla se detecta antes de que se llene el disco.
- Base backups que se verifican con
pg_verifybackupuna vez hechos, se empaquetan y se comparan con un checksum. - Retención que calcula qué borrar a partir del base backup más antiguo que conservas, de modo que no puede eliminar WAL que un backup conservado todavía necesita.
- Restauración a una marca de tiempo, a un LSN, a un punto de restauración con nombre o al último WAL archivado, sobre un directorio nuevo y con el manejo de timelines resuelto por ti.
- Un monitor en cron que revisa la antigüedad del último segmento archivado y el atraso acumulado, con alertas por Telegram o webhook que no se repiten y avisan cuando todo se recupera.
- Un simulacro que genera datos, hace un backup, comete un error a propósito, destruye el servidor y lo restaura en un container limpio, y después compara el número de filas y los checksums.
Cómo se usa en el día a día
Así se ven los comandos diarios y los de emergencia. Los scripts son bash simple; puedes leerlos todos.
./backup-base.sh && ./prune.sh # nightly
./check-archive.sh # every 5 minutes, exit code plus alert
./verify-archive.sh # daily: is the WAL chain complete?
# the bad DELETE happened around 10:15 UTC
./restore-to-time.sh --target-dir /srv/restore/r1 \
--time "2026-11-09 10:14:59+00" --start --port 5433
psql -h /tmp -p 5433 -d postgres # look around, then copy back what you need
Otros destinos: --name before_migration (un punto de restauración que hayas creado), --lsn 0/5000060 y restore-latest.sh para una recuperación ante desastres sin más. La opción --pause detiene la recuperación en el destino para que puedas inspeccionar los datos en solo lectura antes de decidir.
Lo que se niega a hacer
La mayor parte del trabajo se fue en las cosas que no deben fallar en silencio.
- Un segmento de WAL ausente en mitad del archivo. La restauración se detiene, nombra el segmento y termina con un código distinto de cero. En nuestras pruebas, forzarla devolvió 200 de 410 filas sin ningún error, y por eso se niega por defecto.
- Una hora de destino anterior al primer base backup, restaurar sobre un directorio de datos que no está vacío o sobre el que está en uso, y ejecutarse como root.
- Sobrescribir un archivo ya archivado, incluso cuando un servidor restaurado reinicia la numeración de su timeline.
- Borrar WAL que necesita un base backup conservado.
- Tablespaces. El script de backup se detiene en lugar de producir algo que no se podría restaurar.
Mediciones
Una ejecución en una máquina ARM64 de gama portátil, con PostgreSQL con la configuración por defecto.
Tiempo de restauración (destruir el servidor y restaurar en un container limpio)
| Pequeño | Grande | |
|---|---|---|
| Datos | 200,000 filas en la tabla principal, 78 MB | 5,000,000 filas, 989 MB |
| Restauración, total | 2.4 s | 42.0 s |
| de los cuales arranque y replay de WAL | 2.0 s | 36.1 s |
| Filas y checksums | coinciden | coinciden |
Cuánto puedes perder
20 inserts por segundo, luego kill -9 y una restauración solo a partir del archivo. "Perdidos" son los commits que se confirmaron pero faltaban después.
archive_timeout | Confirmados | Recuperados | Perdidos |
|---|---|---|---|
| 10 s | 794 | 764 | 30 (el commit perdido más reciente es 1.9 s posterior al estado recuperado) |
| 10 s | 513 | 400 | 113 (6.1 s) |
| 60 s | 1,896 | 1,175 | 721 (36.0 s) |
| 0 (valor por defecto de PostgreSQL) | 740 | 0 | todo lo posterior al base backup |
La última fila es la que hay que recordar. Con el archive_timeout por defecto y un servidor tranquilo, perder el disco significa perder todo lo posterior al último base backup. La guía explica este parámetro y su coste: forzar el cambio de segmento archiva un archivo completo de 16 MiB, salvo que comprimas.
Sobrecarga
pgbench, cinco rondas intercaladas: mediana de 5,156 tps con el archivado desactivado, 5,112 con gzip y 5,167 sin comprimir. Las diferencias caen dentro de la dispersión de 2 por ciento entre rondas: en esta máquina no apareció ninguna sobrecarga por el archivado.
Cómo se probó
122 comprobaciones automáticas en PostgreSQL 15 (paquete de Debian) y otra vez en PostgreSQL 17 (PGDG), en containers Debian 12 limpios, más el simulacro de destruir y restaurar con dos containers en cada versión. Cubren un archivado que falla y frena el reciclaje de WAL, el comando de archivado con destinos locales y SFTP, base backups con un archivo corrupto, todos los destinos de restauración, una segunda recuperación en una timeline nueva, la retención y todos los rechazos anteriores.
Requisitos
Debian 12 con el empaquetado de PostgreSQL de Debian, un cluster, bash, curl para las alertas y openssh-client si archivas por SFTP. Necesitas root para la instalación y el usuario postgres para todo lo demás.
Preguntas frecuentes
Ya uso pgBackRest. ¿Necesito esto?
No necesariamente. pgBackRest es una herramienta con muchas más funciones. Este kit es para cuando quieres algo lo bastante pequeño como para leerlo entero, o una forma de entender qué hace pgBackRest por ti.
¿Puedo restaurar una sola tabla?
Restauras un cluster completo en un directorio nuevo, en el punto que elijas, y de ahí copias la tabla que necesitas. El simulacro usa exactamente ese patrón.
¿Funciona con Docker o con Postgres gestionado?
No. Necesita acceso a la configuración y a los archivos del servidor. En un servicio gestionado, usa la recuperación a un punto en el tiempo del propio proveedor.
¿Cuánto disco consume?
Depende del volumen de escritura y de archive_timeout. La guía da volúmenes de WAL para varias cargas de trabajo y las cifras de compresión que medimos.
Licencia
Úsalo en tus servidores y en los de tu empresa. Por favor, no lo revendas ni redistribuyas los archivos.
Historial de cambios
- 0.1.0: primera versión.
Leer más
- Restore PostgreSQL to a timestamp with recovery_target_time (en inglés)
- PostgreSQL WAL archiving from scratch on a single Debian VPS (en inglés)
- How much data a disk failure costs with WAL archiving (en inglés)
- pg_dump vs physical backup vs PITR: which to use (en inglés)
Obtener
Polar, como merchant of record, se ocupa del pago, los impuestos y las facturas. Al terminar la compra recibes un enlace de descarga.