Add automated backup scripts for PostgreSQL and S3 files to Backblaze B2
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,129 @@
|
||||
# Настройка бекапов на сервере
|
||||
|
||||
## Что бекапится
|
||||
- **PostgreSQL** → дамп каждую ночь → Backblaze B2
|
||||
- **S3-файлы** (Hetzner Object Storage) → синхронизация → Backblaze B2
|
||||
- Хранение: последние 7 дневных дампов БД + все файлы (sync зеркало)
|
||||
|
||||
---
|
||||
|
||||
## Шаг 1 — Backblaze B2: создать bucket и ключи
|
||||
|
||||
1. Зарегистрироваться на https://www.backblaze.com/b2/
|
||||
2. **Buckets → Create a Bucket**:
|
||||
- Name: `lms-backups-second-brain`
|
||||
- Files in Bucket are: `Private`
|
||||
3. **App Keys → Add a New Application Key**:
|
||||
- Name: `lms-server`
|
||||
- Access: `Read and Write`
|
||||
- Bucket: `lms-backups-second-brain`
|
||||
- Сохранить `keyID` и `applicationKey` — показываются один раз
|
||||
|
||||
---
|
||||
|
||||
## Шаг 2 — Установить rclone на сервере
|
||||
|
||||
```bash
|
||||
curl https://rclone.org/install.sh | sudo bash
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Шаг 3 — Настроить rclone: Backblaze B2
|
||||
|
||||
```bash
|
||||
rclone config
|
||||
```
|
||||
|
||||
Ответы:
|
||||
```
|
||||
n (новый remote)
|
||||
name: b2lms
|
||||
type: b2
|
||||
account: <keyID из шага 1>
|
||||
key: <applicationKey из шага 1>
|
||||
<Enter для остальных — defaults>
|
||||
q (quit)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Шаг 4 — Настроить rclone: Hetzner S3
|
||||
|
||||
Значения берём из `.env` на сервере.
|
||||
|
||||
```bash
|
||||
rclone config
|
||||
```
|
||||
|
||||
Ответы:
|
||||
```
|
||||
n
|
||||
name: hetzner
|
||||
type: s3
|
||||
provider: Other
|
||||
env_auth: false
|
||||
access_key_id: <S3_ACCESS_KEY>
|
||||
secret_access_key: <S3_SECRET_KEY>
|
||||
region: <пусто — Enter>
|
||||
endpoint: <S3_ENDPOINT, например: fsn1.your-objectstorage.com>
|
||||
<Enter для остальных>
|
||||
q
|
||||
```
|
||||
|
||||
Проверить:
|
||||
```bash
|
||||
rclone ls hetzner:lms-uploads
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Шаг 5 — Установить скрипт
|
||||
|
||||
```bash
|
||||
sudo mkdir -p /opt/lms-backup
|
||||
sudo cp scripts/backup.sh /opt/lms-backup/backup.sh
|
||||
sudo chmod +x /opt/lms-backup/backup.sh
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Шаг 6 — Настроить cron
|
||||
|
||||
```bash
|
||||
sudo crontab -e
|
||||
```
|
||||
|
||||
Добавить строку (запуск каждую ночь в 3:00):
|
||||
```
|
||||
0 3 * * * /opt/lms-backup/backup.sh >> /var/log/lms-backup.log 2>&1
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Шаг 7 — Проверить вручную
|
||||
|
||||
```bash
|
||||
sudo /opt/lms-backup/backup.sh
|
||||
tail -50 /var/log/lms-backup.log
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Восстановление из бекапа
|
||||
|
||||
### База данных
|
||||
```bash
|
||||
# Скачать нужный дамп с B2
|
||||
rclone copy b2lms:lms-backups-second-brain/db/db_20260408_0300.sql.gz /tmp/
|
||||
|
||||
# Восстановить в контейнер
|
||||
gunzip -c /tmp/db_20260408_0300.sql.gz \
|
||||
| docker exec -i lms-system-db-1 psql -U lms_user lms_db
|
||||
```
|
||||
|
||||
### Файлы
|
||||
```bash
|
||||
# Синхронизировать файлы обратно на Hetzner S3
|
||||
rclone sync b2lms:lms-backups-second-brain/files hetzner:lms-uploads
|
||||
```
|
||||
@@ -0,0 +1,70 @@
|
||||
#!/bin/bash
|
||||
# LMS Second Brain — Backup Script
|
||||
# Backs up PostgreSQL (from Docker) + S3 files to Backblaze B2
|
||||
# Place at: /opt/lms-backup/backup.sh on the server
|
||||
# Cron: 0 3 * * * /opt/lms-backup/backup.sh >> /var/log/lms-backup.log 2>&1
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# ── Config ───────────────────────────────────────────────────────────────────
|
||||
DB_CONTAINER="lms-system-db-1"
|
||||
DB_USER="lms_user"
|
||||
DB_NAME="lms_db"
|
||||
|
||||
BACKUP_DIR="/tmp/lms-backups"
|
||||
DATE=$(date +%Y%m%d_%H%M)
|
||||
DUMP_FILE="${BACKUP_DIR}/db_${DATE}.sql.gz"
|
||||
|
||||
# B2 rclone remote name (configured via: rclone config)
|
||||
B2_REMOTE="b2lms"
|
||||
B2_BUCKET="lms-backups-second-brain"
|
||||
B2_DB_PATH="${B2_REMOTE}:${B2_BUCKET}/db"
|
||||
B2_FILES_PATH="${B2_REMOTE}:${B2_BUCKET}/files"
|
||||
|
||||
# Hetzner S3 rclone remote name
|
||||
S3_REMOTE="hetzner"
|
||||
S3_BUCKET="lms-uploads"
|
||||
|
||||
# Retention: keep last N daily backups
|
||||
KEEP_DAYS=7
|
||||
|
||||
# ── Functions ─────────────────────────────────────────────────────────────────
|
||||
log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*"; }
|
||||
|
||||
# ── Main ──────────────────────────────────────────────────────────────────────
|
||||
log "=== LMS Backup started ==="
|
||||
mkdir -p "$BACKUP_DIR"
|
||||
|
||||
# 1. PostgreSQL dump
|
||||
log "Dumping PostgreSQL from container ${DB_CONTAINER}..."
|
||||
docker exec "$DB_CONTAINER" \
|
||||
pg_dump -U "$DB_USER" "$DB_NAME" \
|
||||
| gzip > "$DUMP_FILE"
|
||||
log "Dump created: ${DUMP_FILE} ($(du -sh "$DUMP_FILE" | cut -f1))"
|
||||
|
||||
# 2. Upload DB dump to B2
|
||||
log "Uploading DB dump to Backblaze B2..."
|
||||
rclone copy "$DUMP_FILE" "$B2_DB_PATH"
|
||||
log "DB dump uploaded: ${B2_DB_PATH}/$(basename "$DUMP_FILE")"
|
||||
|
||||
# 3. Sync S3 files to B2
|
||||
log "Syncing S3 files to Backblaze B2..."
|
||||
rclone sync \
|
||||
"${S3_REMOTE}:${S3_BUCKET}" \
|
||||
"$B2_FILES_PATH" \
|
||||
--progress \
|
||||
--transfers=8
|
||||
log "S3 files synced to ${B2_FILES_PATH}"
|
||||
|
||||
# 4. Cleanup local temp files
|
||||
rm -f "$DUMP_FILE"
|
||||
log "Local temp files cleaned"
|
||||
|
||||
# 5. Prune old DB backups on B2 (keep last KEEP_DAYS)
|
||||
log "Pruning DB backups older than ${KEEP_DAYS} days..."
|
||||
rclone delete "$B2_DB_PATH" \
|
||||
--min-age "${KEEP_DAYS}d" \
|
||||
--include "db_*.sql.gz"
|
||||
log "Pruning done"
|
||||
|
||||
log "=== LMS Backup finished successfully ==="
|
||||
Reference in New Issue
Block a user