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:
+5
-7
@@ -24,14 +24,12 @@ Thumbs.db
|
|||||||
*.swp
|
*.swp
|
||||||
*.swo
|
*.swo
|
||||||
|
|
||||||
# Docker volumes (dati locali)
|
# Dati locali (bind mount Docker)
|
||||||
pgdata/
|
data/
|
||||||
caddy_data/
|
|
||||||
caddy_config/
|
# Backup
|
||||||
|
backups/
|
||||||
|
|
||||||
# Logs
|
# Logs
|
||||||
*.log
|
*.log
|
||||||
npm-debug.log*
|
npm-debug.log*
|
||||||
|
|
||||||
# Uploads / media locali
|
|
||||||
app/public/uploads/
|
|
||||||
|
|||||||
+5
-11
@@ -7,7 +7,7 @@ services:
|
|||||||
POSTGRES_PASSWORD: ecommerce_password
|
POSTGRES_PASSWORD: ecommerce_password
|
||||||
POSTGRES_DB: ecommerce
|
POSTGRES_DB: ecommerce
|
||||||
volumes:
|
volumes:
|
||||||
- pgdata:/var/lib/postgresql/data
|
- ./data/db:/var/lib/postgresql/data
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD-SHELL", "pg_isready -U ecommerce"]
|
test: ["CMD-SHELL", "pg_isready -U ecommerce"]
|
||||||
interval: 5s
|
interval: 5s
|
||||||
@@ -28,7 +28,7 @@ services:
|
|||||||
expose:
|
expose:
|
||||||
- "3000"
|
- "3000"
|
||||||
volumes:
|
volumes:
|
||||||
- uploads:/app/public/uploads
|
- ./data/uploads:/app/public/uploads
|
||||||
|
|
||||||
mailpit:
|
mailpit:
|
||||||
image: axllent/mailpit:latest
|
image: axllent/mailpit:latest
|
||||||
@@ -44,14 +44,8 @@ services:
|
|||||||
- "443:443"
|
- "443:443"
|
||||||
volumes:
|
volumes:
|
||||||
- ./Caddyfile:/etc/caddy/Caddyfile:ro
|
- ./Caddyfile:/etc/caddy/Caddyfile:ro
|
||||||
- caddy_data:/data
|
- ./data/caddy/data:/data
|
||||||
- caddy_config:/config
|
- ./data/caddy/config:/config
|
||||||
- uploads:/srv/uploads
|
- ./data/uploads:/srv/uploads
|
||||||
depends_on:
|
depends_on:
|
||||||
- app
|
- app
|
||||||
|
|
||||||
volumes:
|
|
||||||
pgdata:
|
|
||||||
caddy_data:
|
|
||||||
caddy_config:
|
|
||||||
uploads:
|
|
||||||
|
|||||||
@@ -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.
|
||||||
Executable
+29
@@ -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
|
||||||
Reference in New Issue
Block a user