#!/usr/bin/env bash # ============================================================= # GoToSocial backup: SQLite consistent + медиа → backups/ # + копия на Яндекс.Диск (ротация 7 дней локально / 30 на ЯД) # ============================================================= set -euo pipefail BASE_DIR="/opt/gotosocial" DATA_DIR="${BASE_DIR}/data" BACKUP_DIR="${BASE_DIR}/backups" YANDEX_DIR="/mnt/yandex-disk/backup/gotosocial-backups" TS="$(date +%Y%m%d_%H%M%S)" # --- SQLite consistent: VACUUM INTO (не горячая копия файла) --- SQLITE_TMP="${BACKUP_DIR}/sqlite-consistent-${TS}.db" mkdir -p "${BACKUP_DIR}" sqlite3 "${DATA_DIR}/sqlite.db" "VACUUM INTO '${SQLITE_TMP}';" # --- Сбор архива: consistent db + медиа --- ARCHIVE="${BACKUP_DIR}/gotosocial_${TS}.tar.gz" tar -C "${DATA_DIR}" -czf "${ARCHIVE}" \ --transform="s|sqlite-consistent-${TS}.db|sqlite.db|" \ "${SQLITE_TMP#${DATA_DIR}/}" storage 2>/dev/null \ || tar -C "${BACKUP_DIR}" -czf "${ARCHIVE}" "sqlite-consistent-${TS}.db" -C "${DATA_DIR}" storage rm -f "${SQLITE_TMP}" # --- Архив секретов (.env) отдельно --- ENV_ARCHIVE="${BACKUP_DIR}/gotosocial_env_${TS}.tar.gz" tar -C "${BASE_DIR}" -czf "${ENV_ARCHIVE}" .env # --- Копия на Яндекс.Диск --- if ! mountpoint -q "${YANDEX_DIR%/backup/*}"; then echo "ERROR: Яндекс.Диск не примонтирован (${YANDEX_DIR%/backup/*})" >&2 exit 1 fi mkdir -p "${YANDEX_DIR}" cp -p "${ARCHIVE}" "${ENV_ARCHIVE}" "${YANDEX_DIR}/" # --- Ротация: локально 7 дней, ЯД 30 дней --- find "${BACKUP_DIR}" -maxdepth 1 -type f -name 'gotosocial_*' -mtime +7 -delete find "${YANDEX_DIR}" -maxdepth 1 -type f -name 'gotosocial_*' -mtime +30 -delete echo "OK: ${ARCHIVE}" echo "OK: ${ENV_ARCHIVE}" ls -lh "${ARCHIVE}" "${ENV_ARCHIVE}"