From 2c6c847d766c643b9707c04da6ea27f671249fe2 Mon Sep 17 00:00:00 2001 From: Davide Grilli Date: Tue, 19 May 2026 08:49:02 +0200 Subject: [PATCH] feat: replace Docker named volumes with local bind mounts and add backup script - docker-compose.yml: sostituisce pgdata/uploads/caddy_data/caddy_config con bind mount su ./data/ - app/public/.gitkeep: crea cartella richiesta dal Dockerfile durante il build - scripts/backup.sh: backup automatico di DB (pg_dump) e uploads con rotazione 30 giorni - docs/BACKUP.md: guida completa backup, ripristino e setup cron - .gitignore: aggiorna con data/ e backups/ --- .gitignore | 12 +++--- app/public/.gitkeep | 0 docker-compose.yml | 16 +++----- docs/BACKUP.md | 95 +++++++++++++++++++++++++++++++++++++++++++++ scripts/backup.sh | 29 ++++++++++++++ 5 files changed, 134 insertions(+), 18 deletions(-) create mode 100644 app/public/.gitkeep create mode 100644 docs/BACKUP.md create mode 100755 scripts/backup.sh diff --git a/.gitignore b/.gitignore index 5049cf6..7a64e66 100644 --- a/.gitignore +++ b/.gitignore @@ -24,14 +24,12 @@ Thumbs.db *.swp *.swo -# Docker volumes (dati locali) -pgdata/ -caddy_data/ -caddy_config/ +# Dati locali (bind mount Docker) +data/ + +# Backup +backups/ # Logs *.log npm-debug.log* - -# Uploads / media locali -app/public/uploads/ diff --git a/app/public/.gitkeep b/app/public/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/docker-compose.yml b/docker-compose.yml index 72be136..3b9e236 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -7,7 +7,7 @@ services: POSTGRES_PASSWORD: ecommerce_password POSTGRES_DB: ecommerce volumes: - - pgdata:/var/lib/postgresql/data + - ./data/db:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U ecommerce"] interval: 5s @@ -28,7 +28,7 @@ services: expose: - "3000" volumes: - - uploads:/app/public/uploads + - ./data/uploads:/app/public/uploads mailpit: image: axllent/mailpit:latest @@ -44,14 +44,8 @@ services: - "443:443" volumes: - ./Caddyfile:/etc/caddy/Caddyfile:ro - - caddy_data:/data - - caddy_config:/config - - uploads:/srv/uploads + - ./data/caddy/data:/data + - ./data/caddy/config:/config + - ./data/uploads:/srv/uploads depends_on: - app - -volumes: - pgdata: - caddy_data: - caddy_config: - uploads: diff --git a/docs/BACKUP.md b/docs/BACKUP.md new file mode 100644 index 0000000..d4938f3 --- /dev/null +++ b/docs/BACKUP.md @@ -0,0 +1,95 @@ +# Backup e Ripristino + +## Cosa viene salvato + +| Dato | Posizione | Contenuto | +|------|-----------|-----------| +| Database | `data/db/` | Utenti, prodotti, ordini, impostazioni | +| Upload | `data/uploads/` | Immagini prodotti, favicon | + +--- + +## Backup manuale + +### Script automatico (consigliato) + +```bash +./scripts/backup.sh +``` + +Crea una cartella `backups/YYYYMMDD_HHMMSS/` con: +- `db.sql.gz` — dump compresso del database +- `uploads.tar.gz` — archivio delle immagini (se presenti) + +I backup più vecchi di 30 giorni vengono eliminati automaticamente. + +### Percorso di destinazione personalizzato + +```bash +BACKUP_DIR=/mnt/nas/backups ./scripts/backup.sh +``` + +--- + +## Backup manuale passo passo + +### 1. Database + +```bash +# Crea dump SQL compresso +docker compose exec -T db pg_dump -U ecommerce ecommerce | gzip > backup_db.sql.gz + +# Verifica che il file non sia vuoto +ls -lh backup_db.sql.gz +``` + +### 2. Immagini e file caricati + +```bash +# La cartella è leggibile direttamente dall'host +tar -czf backup_uploads.tar.gz -C data uploads +``` + +--- + +## Ripristino + +### 1. Ripristino database + +```bash +# I container devono essere in esecuzione +gunzip -c backups/20260519_120000/db.sql.gz | docker compose exec -T db psql -U ecommerce ecommerce +``` + +> Se il database contiene già dati, svuotalo prima: +> ```bash +> docker compose exec db psql -U ecommerce -c "DROP SCHEMA public CASCADE; CREATE SCHEMA public;" ecommerce +> ``` + +### 2. Ripristino immagini + +```bash +tar -xzf backups/20260519_120000/uploads.tar.gz -C data +``` + +--- + +## Backup automatico (cron) + +Per eseguire il backup ogni notte alle 02:00, aggiungi questa riga al crontab dell'host: + +```bash +crontab -e +``` + +``` +0 2 * * * /home/davide/ecommerce-platform/scripts/backup.sh >> /var/log/ecommerce-backup.log 2>&1 +``` + +--- + +## Note importanti + +- La cartella `data/db/` **non è leggibile** dall'utente host (appartiene all'utente interno di PostgreSQL). Usare sempre `pg_dump` per i backup del DB, mai copiare i file direttamente. +- La cartella `backups/` è esclusa da git (`.gitignore`). Salva i backup su storage esterno o NAS. +- I container devono essere **in esecuzione** durante il backup del database. diff --git a/scripts/backup.sh b/scripts/backup.sh new file mode 100755 index 0000000..5a3d15d --- /dev/null +++ b/scripts/backup.sh @@ -0,0 +1,29 @@ +#!/bin/bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_DIR="$(dirname "$SCRIPT_DIR")" +BACKUP_DIR="${BACKUP_DIR:-$PROJECT_DIR/backups}" +TIMESTAMP=$(date +%Y%m%d_%H%M%S) +BACKUP_PATH="$BACKUP_DIR/$TIMESTAMP" + +mkdir -p "$BACKUP_PATH" + +echo "[1/2] Backup database..." +docker compose -f "$PROJECT_DIR/docker-compose.yml" exec -T db \ + pg_dump -U ecommerce ecommerce | gzip > "$BACKUP_PATH/db.sql.gz" +echo " → $BACKUP_PATH/db.sql.gz" + +echo "[2/2] Backup uploads..." +if [ -d "$PROJECT_DIR/data/uploads" ] && [ "$(ls -A "$PROJECT_DIR/data/uploads")" ]; then + tar -czf "$BACKUP_PATH/uploads.tar.gz" -C "$PROJECT_DIR/data" uploads + echo " → $BACKUP_PATH/uploads.tar.gz" +else + echo " (nessun file in data/uploads, saltato)" +fi + +echo "" +echo "Backup completato: $BACKUP_PATH" + +# Rimuovi backup più vecchi di 30 giorni +find "$BACKUP_DIR" -maxdepth 1 -type d -mtime +30 -exec rm -rf {} + 2>/dev/null || true