#!/usr/bin/env bash
set -euo pipefail
DB_NAME="myapp_prod"
DB_USER="postgres"
BACKUP_DIR="/tmp/db_backups"
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
FILENAME="db_backup_${DB_NAME}_${TIMESTAMP}.dump"
B2_BUCKET="b2-remote:my-app-backups-bucket"
RETENTION_DAYS=30
mkdir -p "${BACKUP_DIR}"
echo "[$(date)] Început backup pentru ${DB_NAME}..."
pg_dump -U "${DB_USER}" -F c -b -v -f "${BACKUP_DIR}/${FILENAME}" "${DB_NAME}"
echo "[$(date)] Upload în Backblaze B2..."
rclone copy "${BACKUP_DIR}/${FILENAME}" "${B2_BUCKET}/daily/"
echo "[$(date)] Curățare backup-uri mai vechi de ${RETENTION_DAYS} zile..."
rclone delete --min-age "${RETENTION_DAYS}d" "${B2_BUCKET}/daily/"
rm -f "${BACKUP_DIR}/${FILENAME}"
echo "[$(date)] Backup finalizat cu succes!"Am văzut recent pe forum câteva discuții despre managed databases și costurile lor mari pe AWS sau DigitalOcean. Anul trecut, la un proiect cu o bază Postgres de ~35GB și 12k utilizatori activi, plăteam vreo 140$/lună doar ca să avem backup-uri gestionate de provider. Am mutat totul pe un VPS propriu și am configurat un script simplu de backup în Backblaze B2 cu pg_dump și cron. Costul actual de stocare? Sub 1$ pe lună.
De ce Backblaze B2 și nu S3?
Să fim sinceri: AWS S3 e excelent până când trebuie să faci un restore mare și te lovești de costurile fantastice de egress. Backblaze B2 îți oferă primii 10GB gratuit, iar după e $6/TB pe lună, cu egress gratuit în limita a 3x stocarea medie. Un alt plus e că folosești direct rclone sau aws-cli fiindcă au API compatibil S3.
Atenție la trade-off totuși: un script de bash pus pe cron nu îți oferă Point-In-Time Recovery (PITR) din oficiu, așa cum ai pe un RDS configurat ca la carte. Dacă ai o aplicație bancară unde ai nevoie de restore secundă cu secundă prin WAL archiving, soluția asta simplă nu e pentru tine. Dar pentru 90% din proiectele SaaS mici și medii, un dump zilnic plus o rotație bună de fișiere sunt mai mult decât suficiente.
Setup-ul minim necesar
Procesul e simplu: faci un dump comprimat cu format custom (-Fc), îl urci în bucket și ștergi ce e mai vechi de 30 de zile.
Am ales formatul -Fc din două motive mari:
- Comprimă nativ mai bine decât un export text pur trecut prin gzip.
- Îți permite să folosești
pg_restorecu parametrul--jobs=4la restaurare, ceea ce scade timpul de restore de la 45 de minute la sub 10 minute pe un server multicore.
În scriptul de mai jos folosesc rclone configurat cu un remote numit b2-remote. De asemenea, setez set -euo pipefail în bash. Fără asta, dacă pg_dump crapă (de exemplu din lipsă de spațiu pe disk), scriptul ar merge mai departe și ar urca un fișier gol de 0 bytes pe B2. Mi s-a întâmplat o dată acum 4 ani pe un server de staging. Nu vrei să pățești asta pe producție.
Partea pe care o ignoră toți: Testul de restore
Un backup netestat este egal cu zero. E o axiomă pe care am învățat-o pe pielea mea când am încercat să restaurez un dump mai vechi și am realizat că lipseau extensiile postgis pe serverul nou, iar pg_restore crăpa la jumătate fără avertisment.
Recomandarea mea e să pui pe un cron separat (poate săptămânal) o procedură automatizată:
- Tragi cel mai recent backup din B2.
- Îl restaurezi într-un container Docker temporar de Postgres.
- Execuți un query simplu (
SELECT count(*) FROM users;). - Dacă trece, trimiti un ping la un serviciu de monitorizare (Healthchecks.io sau Better Stack). Dacă pică, alertă direct pe Slack.
Voi cum gestionați backup-urile pe proiectele proprii? Mergeți pe varianta gestionată de cloud provider sau preferați un script custom și stocare ieftină?