Add notification feature to backup scripts for various services
Enhance backup scripts for Nextcloud, Gitea, Paperless, Vaultwarden, Immich, and VPS configurations by adding Telegram notifications upon completion. Include details such as backup size and objects backed up. Update backup documentation to reflect these changes and ensure clarity on backup processes and retention policies.
This commit is contained in:
@@ -1,46 +1,54 @@
|
||||
#!/bin/bash
|
||||
# Выгрузка только /mnt/backup/photos в Yandex Object Storage (S3) через restic.
|
||||
# Тот же репозиторий, что и backup-restic-yandex.sh; фото вынесены в отдельный снимок (больше всего данных).
|
||||
# Запускать на хосте Proxmox под root. Требуется тот же /root/.restic-yandex.env и /root/.restic-password.
|
||||
# Cron: 0 1 * * * (01:00).
|
||||
# Запускать на хосте Proxmox под root. Секреты из Vaultwarden (объект RESTIC), файл /root/.bw-master (chmod 600).
|
||||
# Cron: 10 4 * * * (04:10, после основного restic в 04:00).
|
||||
set -e
|
||||
|
||||
ENV_FILE="/root/.restic-yandex.env"
|
||||
BACKUP_PATH="/mnt/backup/photos"
|
||||
# Время запуска (для логов и уведомлений)
|
||||
START_TS=$(date +%s)
|
||||
START_HUMAN=$(date '+%Y-%m-%d %H:%M:%S')
|
||||
|
||||
if [ "$(id -u)" -ne 0 ]; then
|
||||
echo "Запускайте под root."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -f "$ENV_FILE" ]; then
|
||||
echo "Нет файла $ENV_FILE. Скопируйте restic-yandex-env.example и задайте ключи."
|
||||
# Секреты из Vaultwarden (объект RESTIC)
|
||||
BW_MASTER_PASSWORD_FILE="${BW_MASTER_PASSWORD_FILE:-/root/.bw-master}"
|
||||
if [ ! -f "$BW_MASTER_PASSWORD_FILE" ]; then
|
||||
echo "Нет файла с мастер-паролем Vaultwarden: $BW_MASTER_PASSWORD_FILE (chmod 600). См. docs/backup/proxmox-phase1-backup.md"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# shellcheck source=/dev/null
|
||||
source "$ENV_FILE"
|
||||
|
||||
if ! command -v bw >/dev/null 2>&1 || ! command -v jq >/dev/null 2>&1; then
|
||||
echo "Установите bw (Bitwarden CLI) и jq для получения секретов из Vaultwarden."
|
||||
exit 1
|
||||
fi
|
||||
export BW_SESSION
|
||||
BW_SESSION=$(bw unlock --passwordfile "$BW_MASTER_PASSWORD_FILE" --raw 2>/dev/null) || { echo "Не удалось разблокировать Vaultwarden."; exit 1; }
|
||||
RESTIC_ITEM=$(bw get item "RESTIC" 2>/dev/null) || { echo "Не найден объект RESTIC в Vaultwarden."; exit 1; }
|
||||
export RESTIC_REPOSITORY
|
||||
RESTIC_REPOSITORY=$(echo "$RESTIC_ITEM" | jq -r '.fields[] | select(.name=="RESTIC_REPOSITORY") | .value')
|
||||
export AWS_ACCESS_KEY_ID
|
||||
AWS_ACCESS_KEY_ID=$(echo "$RESTIC_ITEM" | jq -r '.fields[] | select(.name=="AWS_ACCESS_KEY_ID") | .value')
|
||||
export AWS_SECRET_ACCESS_KEY
|
||||
AWS_SECRET_ACCESS_KEY=$(echo "$RESTIC_ITEM" | jq -r '.fields[] | select(.name=="AWS_SECRET_ACCESS_KEY") | .value')
|
||||
export AWS_DEFAULT_REGION
|
||||
AWS_DEFAULT_REGION=$(echo "$RESTIC_ITEM" | jq -r '.fields[] | select(.name=="AWS_DEFAULT_REGION") | .value')
|
||||
[ -z "$AWS_DEFAULT_REGION" ] && AWS_DEFAULT_REGION="ru-central1"
|
||||
RESTIC_PASS=$(echo "$RESTIC_ITEM" | jq -r '.fields[] | select(.name=="RESTIC_BACKUP_KEY") | .value')
|
||||
for var in RESTIC_REPOSITORY AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY; do
|
||||
if [ -z "${!var}" ]; then
|
||||
echo "В $ENV_FILE не задано: $var"
|
||||
echo "В Vaultwarden (RESTIC) не задано поле для $var"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
if [ -z "$RESTIC_PASSWORD_FILE" ]; then
|
||||
RESTIC_PASSWORD_FILE="/root/.restic-password"
|
||||
fi
|
||||
if [ ! -f "$RESTIC_PASSWORD_FILE" ]; then
|
||||
echo "Файл с паролем репозитория не найден: $RESTIC_PASSWORD_FILE"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
export AWS_ACCESS_KEY_ID
|
||||
export AWS_SECRET_ACCESS_KEY
|
||||
RESTIC_PASSWORD_FILE=$(mktemp -u)
|
||||
echo -n "$RESTIC_PASS" > "$RESTIC_PASSWORD_FILE"
|
||||
chmod 600 "$RESTIC_PASSWORD_FILE"
|
||||
trap 'rm -f "$RESTIC_PASSWORD_FILE"' EXIT INT TERM
|
||||
export RESTIC_PASSWORD_FILE
|
||||
export RESTIC_REPOSITORY
|
||||
export AWS_DEFAULT_REGION="${AWS_DEFAULT_REGION:-ru-central1}"
|
||||
|
||||
if ! command -v restic >/dev/null 2>&1; then
|
||||
echo "restic не установлен. Установите: apt install restic."
|
||||
@@ -53,7 +61,8 @@ if [ ! -d "$BACKUP_PATH" ]; then
|
||||
fi
|
||||
|
||||
echo "Restic backup (photos): $BACKUP_PATH -> $RESTIC_REPOSITORY"
|
||||
restic backup "$BACKUP_PATH" --quiet
|
||||
# Показываем прогресс restic (без --quiet), чтобы был виден ход бэкапа
|
||||
restic backup "$BACKUP_PATH"
|
||||
|
||||
echo "Restic forget (retention 3 daily, 2 weekly, 2 monthly)..."
|
||||
restic forget --keep-daily 3 --keep-weekly 2 --keep-monthly 2 --prune --quiet
|
||||
@@ -61,4 +70,42 @@ restic forget --keep-daily 3 --keep-weekly 2 --keep-monthly 2 --prune --quiet
|
||||
echo "Restic prune..."
|
||||
restic prune --quiet
|
||||
|
||||
# Время окончания и длительность
|
||||
END_TS=$(date +%s)
|
||||
END_HUMAN=$(date '+%Y-%m-%d %H:%M:%S')
|
||||
DURATION_SEC=$(( END_TS - START_TS ))
|
||||
if [ "$DURATION_SEC" -lt 0 ] 2>/dev/null; then
|
||||
DURATION_SEC=0
|
||||
fi
|
||||
DUR_MIN=$(( DURATION_SEC / 60 ))
|
||||
DUR_SEC=$(( DURATION_SEC % 60 ))
|
||||
|
||||
echo "Restic photos backup done."
|
||||
echo "Время запуска: $START_HUMAN"
|
||||
echo "Время завершения: $END_HUMAN"
|
||||
echo "Длительность: ${DUR_MIN} мин ${DUR_SEC} сек"
|
||||
|
||||
# Уведомление в Telegram (шлюз тихо выходит, если конфига нет)
|
||||
NOTIFY_SCRIPT="${NOTIFY_SCRIPT:-/root/scripts/notify-telegram.sh}"
|
||||
if [ -x "$NOTIFY_SCRIPT" ]; then
|
||||
STATS=$(restic stats latest 2>/dev/null) || true
|
||||
FILES=$(echo "$STATS" | grep "Total File Count" | sed 's/.*:[[:space:]]*//')
|
||||
SIZE=$(echo "$STATS" | grep "Total Size" | sed 's/.*:[[:space:]]*//')
|
||||
if [ -n "$FILES" ] && [ -n "$SIZE" ]; then
|
||||
BODY="Резервное копирование завершено.
|
||||
Объекты: снимок /mnt/backup/photos в Yandex. Файлов в снимке: $FILES.
|
||||
Размер копии: ${SIZE}.
|
||||
Время запуска: ${START_HUMAN}.
|
||||
Время завершения: ${END_HUMAN}.
|
||||
Длительность: ${DUR_MIN} мин ${DUR_SEC} сек."
|
||||
"$NOTIFY_SCRIPT" "📷 Restic Yandex (photos)" "$BODY" || true
|
||||
else
|
||||
BODY="Резервное копирование завершено.
|
||||
Объекты: снимок /mnt/backup/photos в Yandex.
|
||||
Размер копии: — (stats недоступны).
|
||||
Время запуска: ${START_HUMAN}.
|
||||
Время завершения: ${END_HUMAN}.
|
||||
Длительность: ${DUR_MIN} мин ${DUR_SEC} сек."
|
||||
"$NOTIFY_SCRIPT" "📷 Restic Yandex (photos)" "$BODY" || true
|
||||
fi
|
||||
fi
|
||||
|
||||
Reference in New Issue
Block a user