mirror of
https://gitverse.ru/kpa39l/gotosocial.git
synced 2026-09-29 09:55:10 +00:00
chore: STATUS.md обновлён (деплой завершён), backup.sh на SQLite Backup API
This commit is contained in:
@@ -2,35 +2,52 @@
|
||||
# =============================================================
|
||||
# GoToSocial backup: SQLite consistent + медиа → backups/
|
||||
# + копия на Яндекс.Диск (ротация 7 дней локально / 30 на ЯД)
|
||||
#
|
||||
# Топология: /opt/gotosocial/data → /gotosocial/storage (контейнер)
|
||||
# data/sqlite.db + media лежат прямо в data/ (storage-маунт)
|
||||
# SQLite: Backup API через python3 (sqlite3 CLI не установлен)
|
||||
# Тихий: stdout пуст при успехе (для no_agent cron), не-ноль при ошибке
|
||||
# =============================================================
|
||||
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"
|
||||
YANDEX_MOUNT="/mnt/yandex-disk"
|
||||
YANDEX_DIR="${YANDEX_MOUNT}/backup/gotosocial-backups"
|
||||
STAGE="${BACKUP_DIR}/stage"
|
||||
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}';"
|
||||
rm -rf "${STAGE}" && mkdir -p "${STAGE}"
|
||||
|
||||
# --- Сбор архива: consistent db + медиа ---
|
||||
# --- Компактный снапшот БД через SQLite Backup API (online, без конфликтов) ---
|
||||
python3 - "${DATA_DIR}/sqlite.db" "${STAGE}/sqlite.db" <<'PYEOF'
|
||||
import sqlite3, sys
|
||||
src, dst = sys.argv[1], sys.argv[2]
|
||||
s = sqlite3.connect(src)
|
||||
d = sqlite3.connect(dst)
|
||||
with d:
|
||||
s.backup(d)
|
||||
d.close()
|
||||
s.close()
|
||||
PYEOF
|
||||
|
||||
# --- Медиа копируем в stage (без WAL/SHM, с сохранением структуры) ---
|
||||
# Исключаем служебные sqlite-файлы из data/, чтобы не дублировать БД
|
||||
(cd "${DATA_DIR}" && tar -cf - --exclude='sqlite.db*' .) | tar -xf - -C "${STAGE}"
|
||||
|
||||
# --- Итоговый архив: 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}"
|
||||
tar -C "${STAGE}" -czf "${ARCHIVE}" .
|
||||
|
||||
# --- Архив секретов (.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
|
||||
if ! mountpoint -q "${YANDEX_MOUNT}"; then
|
||||
echo "ERROR: Яндекс.Диск не примонтирован (${YANDEX_MOUNT})" >&2
|
||||
exit 1
|
||||
fi
|
||||
mkdir -p "${YANDEX_DIR}"
|
||||
@@ -40,6 +57,7 @@ cp -p "${ARCHIVE}" "${ENV_ARCHIVE}" "${YANDEX_DIR}/"
|
||||
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}"
|
||||
rm -rf "${STAGE}"
|
||||
|
||||
# Успех — тихо (для no_agent cron)
|
||||
exit 0
|
||||
Reference in New Issue
Block a user