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/
This commit is contained in:
2026-05-19 08:49:02 +02:00
parent b62c02adc1
commit 2c6c847d76
5 changed files with 134 additions and 18 deletions
+5 -7
View File
@@ -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/
View File
+5 -11
View File
@@ -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:
+95
View File
@@ -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.
+29
View File
@@ -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