Enhance backup documentation for Proxmox and VPS configurations. Add details for MTProto proxy setup on VPS, clarify backup processes for Immich photos, and update restic backup scripts to exclude photo directories. Include test recovery results and refine instructions for restoring various services and configurations.
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
#!/bin/bash
|
||||
# Копирование библиотеки фото Immich (оригиналы) с VM 200 на диск бэкапов хоста.
|
||||
# Запускать на хосте Proxmox под root. Требуется SSH без пароля: root → admin@192.168.1.200.
|
||||
# Запускать на хосте Proxmox под root. Требуется: SSH без пароля root → admin@192.168.1.200; на VM 200 установлен rsync (apt install rsync).
|
||||
# Результат: /mnt/backup/photos/library/ (зеркало /mnt/data/library с VM 200).
|
||||
# Без --delete: удалённые в Immich фото в бэкапе остаются (страховка).
|
||||
set -e
|
||||
|
||||
64
scripts/backup-restic-yandex-photos.sh
Normal file
64
scripts/backup-restic-yandex-photos.sh
Normal file
@@ -0,0 +1,64 @@
|
||||
#!/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).
|
||||
set -e
|
||||
|
||||
ENV_FILE="/root/.restic-yandex.env"
|
||||
BACKUP_PATH="/mnt/backup/photos"
|
||||
|
||||
if [ "$(id -u)" -ne 0 ]; then
|
||||
echo "Запускайте под root."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -f "$ENV_FILE" ]; then
|
||||
echo "Нет файла $ENV_FILE. Скопируйте restic-yandex-env.example и задайте ключи."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# shellcheck source=/dev/null
|
||||
source "$ENV_FILE"
|
||||
|
||||
for var in RESTIC_REPOSITORY AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY; do
|
||||
if [ -z "${!var}" ]; then
|
||||
echo "В $ENV_FILE не задано: $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
|
||||
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."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -d "$BACKUP_PATH" ]; then
|
||||
echo "Каталог $BACKUP_PATH не найден. Пропуск."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "Restic backup (photos): $BACKUP_PATH -> $RESTIC_REPOSITORY"
|
||||
restic backup "$BACKUP_PATH" --quiet
|
||||
|
||||
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
|
||||
|
||||
echo "Restic photos backup done."
|
||||
@@ -1,5 +1,6 @@
|
||||
#!/bin/bash
|
||||
# Выгрузка /mnt/backup в Yandex Object Storage (S3) через restic.
|
||||
# Выгрузка /mnt/backup в Yandex Object Storage (S3) через restic (без каталога photos).
|
||||
# Фото бэкапятся отдельно: backup-restic-yandex-photos.sh.
|
||||
# Запускать на хосте Proxmox под root.
|
||||
# Перед первым запуском: установить restic, создать /root/.restic-yandex.env и /root/.restic-password, выполнить restic init.
|
||||
# Cron: 0 4 * * * (04:00, после окна 01:00–03:30; 05:00 зарезервировано под перезагрузку).
|
||||
@@ -7,8 +8,8 @@ set -e
|
||||
|
||||
ENV_FILE="/root/.restic-yandex.env"
|
||||
BACKUP_PATH="/mnt/backup"
|
||||
# Исключаем служебные каталоги
|
||||
EXCLUDE_OPTS=(--exclude="$BACKUP_PATH/lost+found")
|
||||
# Исключаем служебные каталоги и photos (фото — отдельный бэкап)
|
||||
EXCLUDE_OPTS=(--exclude="$BACKUP_PATH/lost+found" --exclude="$BACKUP_PATH/photos")
|
||||
|
||||
if [ "$(id -u)" -ne 0 ]; then
|
||||
echo "Запускайте под root."
|
||||
@@ -49,7 +50,7 @@ if ! command -v restic >/dev/null 2>&1; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Restic backup: $BACKUP_PATH -> $RESTIC_REPOSITORY"
|
||||
echo "Restic backup: $BACKUP_PATH (excl. photos) -> $RESTIC_REPOSITORY"
|
||||
restic backup "$BACKUP_PATH" "${EXCLUDE_OPTS[@]}" --quiet
|
||||
|
||||
echo "Restic forget (retention 3 daily, 2 weekly, 2 monthly)..."
|
||||
|
||||
42
scripts/backup-vps-mtproto.sh
Normal file
42
scripts/backup-vps-mtproto.sh
Normal file
@@ -0,0 +1,42 @@
|
||||
#!/bin/bash
|
||||
# Бэкап конфигов MTProto + сайт-заглушка с VPS Германия (185.103.253.99).
|
||||
# Запускать на хосте Proxmox под root.
|
||||
# Требуется: SSH без пароля с хоста к root@185.103.253.99 (ключ в ~/.ssh).
|
||||
# Результат: /mnt/backup/vps/mtproto-germany/mtproto-config-YYYYMMDD-HHMM.tar.gz
|
||||
set -e
|
||||
|
||||
VPS_HOST="185.103.253.99"
|
||||
VPS_USER="root"
|
||||
SSH_OPTS=(-o ConnectTimeout=15 -o BatchMode=yes)
|
||||
BACKUP_ROOT="/mnt/backup/vps/mtproto-germany"
|
||||
RETENTION_DAYS=14
|
||||
|
||||
if [ "$(id -u)" -ne 0 ]; then
|
||||
echo "Запускайте под root."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkdir -p "$BACKUP_ROOT"
|
||||
DATE=$(date +%Y%m%d-%H%M)
|
||||
ARCHIVE="$BACKUP_ROOT/mtproto-config-$DATE.tar.gz"
|
||||
|
||||
# Проверка доступа к VPS
|
||||
if ! ssh "${SSH_OPTS[@]}" "${VPS_USER}@${VPS_HOST}" "echo ok" >/dev/null 2>&1; then
|
||||
echo "Ошибка: нет доступа по SSH к ${VPS_USER}@${VPS_HOST}. Настройте ключ: ssh-copy-id ${VPS_USER}@${VPS_HOST}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Архив с VPS: mtg, nginx, letsencrypt (katykhin.store), статика сайта
|
||||
ssh "${SSH_OPTS[@]}" "${VPS_USER}@${VPS_HOST}" "tar -chzf - -C / \
|
||||
etc/systemd/system/mtg.service \
|
||||
etc/nginx/sites-available \
|
||||
etc/nginx/sites-enabled \
|
||||
etc/letsencrypt/live/katykhin.store \
|
||||
etc/letsencrypt/archive/katykhin.store \
|
||||
etc/letsencrypt/renewal/katykhin.store.conf \
|
||||
var/www/katykhin.store" > "$ARCHIVE"
|
||||
|
||||
chmod 600 "$ARCHIVE"
|
||||
echo "Бэкап MTProto (VPS DE): $ARCHIVE ($(du -h "$ARCHIVE" | cut -f1))"
|
||||
|
||||
find "$BACKUP_ROOT" -name 'mtproto-config-*.tar.gz' -mtime +$RETENTION_DAYS -delete
|
||||
110
scripts/restore-one-vzdump-from-restic.sh
Normal file
110
scripts/restore-one-vzdump-from-restic.sh
Normal file
@@ -0,0 +1,110 @@
|
||||
#!/bin/bash
|
||||
# Восстановление одного файла vzdump из restic (Yandex S3) через mount.
|
||||
# Не выкачивает весь репозиторий — подгружаются только нужные данные для выбранного файла.
|
||||
# Запускать на хосте Proxmox под root. Требуется FUSE (restic mount).
|
||||
#
|
||||
# Использование:
|
||||
# restore-one-vzdump-from-restic.sh [SNAPSHOT] [ПУТЬ_В_СНИМКЕ] [КУДА_СОХРАНИТЬ]
|
||||
#
|
||||
# Пример (последний снимок, CT 107, сохранить в /mnt/backup):
|
||||
# ./restore-one-vzdump-from-restic.sh
|
||||
# ./restore-one-vzdump-from-restic.sh latest /mnt/backup/proxmox/dump/dump/vzdump-lxc-107-2026_02_26-02_03_14.tar.zst /mnt/backup
|
||||
#
|
||||
# Список снимков: restic snapshots
|
||||
# Список файлов в снимке: restic ls SNAPSHOT
|
||||
set -e
|
||||
|
||||
ENV_FILE="${ENV_FILE:-/root/.restic-yandex.env}"
|
||||
MOUNT_DIR="${MOUNT_DIR:-/mnt/backup/restic-mount}"
|
||||
RESTIC_PASSWORD_FILE="${RESTIC_PASSWORD_FILE:-/root/.restic-password}"
|
||||
|
||||
SNAPSHOT="${1:-latest}"
|
||||
# Путь к файлу внутри снимка (как в restic ls) — бэкапим /mnt/backup, пути вида /mnt/backup/proxmox/dump/dump/vzdump-lxc-107-...
|
||||
FILE_IN_SNAPSHOT="${2:-}"
|
||||
OUTPUT_DIR="${3:-/mnt/backup}"
|
||||
|
||||
if [ "$(id -u)" -ne 0 ]; then
|
||||
echo "Запускайте под root."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -f "$ENV_FILE" ]; then
|
||||
echo "Нет файла $ENV_FILE. Скопируйте restic-yandex-env.example и задайте ключи."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# shellcheck source=/dev/null
|
||||
source "$ENV_FILE"
|
||||
for var in RESTIC_REPOSITORY AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY; do
|
||||
if [ -z "${!var}" ]; then
|
||||
echo "В $ENV_FILE не задано: $var"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
export AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY RESTIC_REPOSITORY
|
||||
export RESTIC_PASSWORD_FILE
|
||||
export AWS_DEFAULT_REGION="${AWS_DEFAULT_REGION:-ru-central1}"
|
||||
|
||||
if ! command -v restic >/dev/null 2>&1; then
|
||||
echo "restic не установлен. Установите: apt install restic."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$FILE_IN_SNAPSHOT" ]; then
|
||||
echo "Использование: $0 [SNAPSHOT] ПУТЬ_В_СНИМКЕ [КУДА_СОХРАНИТЬ]"
|
||||
echo "Пример: $0 latest /mnt/backup/proxmox/dump/dump/vzdump-lxc-107-2026_02_26-02_03_14.tar.zst /mnt/backup"
|
||||
echo ""
|
||||
echo "Доступные снимки:"
|
||||
restic snapshots 2>/dev/null || true
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Resolve "latest" to snapshot ID (restic mount показывает ids/<short-id>/)
|
||||
if [ "$SNAPSHOT" = "latest" ]; then
|
||||
SNAPSHOT_ID=$(restic snapshots 2>/dev/null | grep -E '^[a-f0-9]{8}[[:space:]]' | tail -1 | awk '{print $1}')
|
||||
else
|
||||
SNAPSHOT_ID="$SNAPSHOT"
|
||||
fi
|
||||
[ -z "$SNAPSHOT_ID" ] && echo "Не удалось определить ID снимка." && exit 1
|
||||
echo "Снимок: $SNAPSHOT_ID"
|
||||
|
||||
mkdir -p "$OUTPUT_DIR"
|
||||
mkdir -p "$MOUNT_DIR"
|
||||
|
||||
# Проверяем, не смонтировано ли уже
|
||||
if mountpoint -q "$MOUNT_DIR" 2>/dev/null; then
|
||||
echo "Точка монтирования $MOUNT_DIR уже занята. Размонтируйте: fusermount -u $MOUNT_DIR"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Монтируем репозиторий в $MOUNT_DIR ..."
|
||||
restic mount "$MOUNT_DIR" &
|
||||
MOUNT_PID=$!
|
||||
trap 'kill $MOUNT_PID 2>/dev/null; fusermount -u "$MOUNT_DIR" 2>/dev/null; exit' EXIT INT TERM
|
||||
|
||||
# В смонтированном репо файлы снимка лежат в ids/<short_id>/<путь>
|
||||
SOURCE_FILE="$MOUNT_DIR/ids/$SNAPSHOT_ID/$FILE_IN_SNAPSHOT"
|
||||
for i in $(seq 1 45); do
|
||||
if [ -e "$SOURCE_FILE" ] 2>/dev/null; then
|
||||
break
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
if [ ! -e "$SOURCE_FILE" ]; then
|
||||
echo "Файл не найден: $SOURCE_FILE (подождали 45 с). Проверьте: restic ls $SNAPSHOT_ID"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
BASENAME_FILE="$(basename "$FILE_IN_SNAPSHOT")"
|
||||
OUTPUT_FILE="$OUTPUT_DIR/$BASENAME_FILE"
|
||||
echo "Копируем $SOURCE_FILE -> $OUTPUT_FILE ..."
|
||||
cp "$SOURCE_FILE" "$OUTPUT_FILE"
|
||||
echo "Готово: $OUTPUT_FILE ($(du -sh "$OUTPUT_FILE" | cut -f1))"
|
||||
|
||||
# Размонтировать
|
||||
kill $MOUNT_PID 2>/dev/null || true
|
||||
wait $MOUNT_PID 2>/dev/null || true
|
||||
fusermount -u "$MOUNT_DIR" 2>/dev/null || true
|
||||
trap - EXIT INT TERM
|
||||
echo "Размонтировано. Для восстановления контейнера:"
|
||||
echo " pct create NEW_VMID $OUTPUT_FILE --restore 1 --storage local-lvm"
|
||||
Reference in New Issue
Block a user