Files
homelab-docs/scripts/backup-restic-yandex-photos.sh
Andrey 53769e6832 Update architecture and backup documentation to include Healthchecks integration
Add Healthchecks service details to architecture and backup documentation, including its role as a Dead man's switch for backups. Update backup scripts to utilize systemd timers instead of cron for improved scheduling. Enhance network topology documentation to reflect Healthchecks integration in the VPS Miran setup. This update clarifies backup processes and enhances overall system reliability.
2026-02-28 15:43:39 +03:00

114 lines
5.1 KiB
Bash
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/bin/bash
# Выгрузка только /mnt/backup/photos в Yandex Object Storage (S3) через restic.
# Тот же репозиторий, что и backup-restic-yandex.sh; фото вынесены в отдельный снимок (больше всего данных).
# Запускать на хосте Proxmox под root. Секреты из Vaultwarden (объект RESTIC), файл /root/.bw-master (chmod 600).
# Cron: 10 4 * * * (04:10, после основного restic в 04:00).
set -e
export PATH="/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:${PATH:-}"
export HOME="${HOME:-/root}"
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
# Секреты из 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/vaultwarden-secrets.md"
exit 1
fi
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 "В Vaultwarden (RESTIC) не задано поле для $var"
exit 1
fi
done
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
if ! command -v restic >/dev/null 2>&1; then
echo "restic не установлен. Установите: apt install restic."
exit 1
fi
if [ ! -d "$BACKUP_PATH" ]; then
echo "Каталог $BACKUP_PATH не найден. Пропуск."
exit 0
fi
echo "Restic backup (photos): $BACKUP_PATH -> $RESTIC_REPOSITORY"
# Показываем прогресс 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
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