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:
2026-02-26 23:06:02 +03:00
parent feaa31f702
commit 56cee83198
10 changed files with 727 additions and 20 deletions

View File

@@ -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

View 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."

View File

@@ -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:0003: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)..."

View 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

View 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"