# Фаза 1: Стратегия бэкапов Proxmox Цель: при смерти SSD с системой или потере `/etc/pve` — развернуть Proxmox, восстановить контейнеры/ВМ, поднять сервисы без многочасового восстановления и угадывания паролей. **Приоритет №1.** ИБП уже есть; защищаемся от смерти диска. --- ## Что бэкапить | Объект | Зачем | |--------|--------| | **LXC и VM целиком** (vzdump) | Восстановление контейнера/ВМ из одного архива: ОС, конфиги, данные на корневом томе. Не только данные внутри — сам образ для restore. | | **/etc/pve** | Конфиги кластера, VM/LXC (ID, сеть, диски, задачи), пользователи Proxmox, права. Без этого после переустановки Proxmox не восстановить привязку дисков и настройки. | --- ## Пошаговый план ### Шаг 1. Определить хранилище для бэкапов **Выбранная схема:** | Место | Описание | Что туда | |-------|----------|----------| | **Локально: /dev/sdb1 (1 ТБ под бэкапы)** | Отдельный SSD 2 ТБ; под копии выделен 1 ТБ, смонтирован в `/mnt/backup`. Второй ТБ — в запас. | Proxmox vzdump (через UI), затем те же данные (dump, etc-pve, фотки, VPS) в Yandex через restic. Фотки: оригиналы + метаданные + БД Immich; остальное пересчитать можно. VPS: Amnezia — конфиг; Миран — БД бота + контент (контент можно в S3 Мирана; копию на sdb1 — опционально). Конфигурацию серверов не бэкапим — есть Ansible. | | **Офсайт: Yandex Object Storage (S3)** | Арендованный бакет, S3-совместимый API. [Yandex Object Storage](https://yandex.cloud/ru/docs/storage/s3/). | **Restic** с хоста (cron на ноде Proxmox): выгрузка содержимого `/mnt/backup`. Retention: 3 daily, 2 weekly, 2 monthly. | **Принято:** Вариант A — отдельный диск/раздел на хосте (sdb1, 1 ТБ в `/mnt/backup`). Варианты B (NFS/SMB) и C (внешний USB) в текущей схеме не используются; USB опционально для параноидального 3-2-1 (см. выше). **3-2-1:** Три копии: (1) прод — система и данные на основном диске; (2) локальный бэкап — sdb1; (3) офсайт — Yandex. Два типа носителей: локальный SSD и облачное object storage. Один офсайт — да. **Стратегия удовлетворяет 3-2-1.** Опционально: четвёртая копия на внешнем USB/другом ПК для параноидального сценария (пожар/кража) — по желанию. **Принято:** Точка монтирования — `/mnt/backup`. На диске 2 ТБ выделено 1 ТБ под бэкапы; второй ТБ пока в запас, назначение не определено. **Действие:** Разметить 1 ТБ на /dev/sdb1, создать ФС (ext4/xfs), смонтировать в `/mnt/backup`. Структуру каталогов — см. раздел «Структура локального хранилища» ниже. --- ### Шаг 2. Добавить Backup Storage в Proxmox 1. В веб-интерфейсе: **Datacenter → Storage → Add**. 2. Тип: **Directory** (если папка на локальном диске) или **NFS/CIFS** (если сетевое). 3. Указать: - **ID** (например `backup-local` или `backup-nfs`), - **Directory** — путь, например `/mnt/backup/dump`, - Включить опции **Content: VZDump backup file** (и при необходимости **ISO**, **Container template** — по желанию). 4. Сохранить. Убедиться, что storage виден и доступен для записи. Если используешь NFS: сначала смонтировать NFS в `/mnt/backup` на хосте (fstab или systemd mount), затем добавить Storage с Directory `/mnt/backup/dump`. **Для выбранной схемы:** Directory = `/mnt/backup/proxmox/dump` (см. структуру ниже). --- ### Структура локального хранилища (1 ТБ на sdb1) «Аналог S3» на одном диске — это просто понятная иерархия каталогов. **MinIO не используем:** лишний сервис; достаточно директорий и restic с бэкендом `local` (если понадобится локальный restic) и `s3` для Yandex. Proxmox пишет в **Directory** — ему достаточно пути. Пример структуры под `/mnt/backup`: ``` /mnt/backup/ ├── proxmox/ │ ├── dump/ ← Proxmox Backup Job (VZDump) — сюда добавляем Storage в PVE │ └── etc-pve/ ← архивы tar.gz из cron: etc-pve-*, etc-host-configs-* (backup-etc-pve.sh) ├── restic/ │ ├── local/ ← репозитории restic для локальных снапшотов (опционально) │ └── ... ← или restic только в Yandex, локально только сырые копии ├── photos/ ← Immich: оригиналы фото + метаданные + БД (остальное пересчитать) ├── vps/ ← Amnezia: конфиг. Миран: БД бота (+ контент при необходимости; основной контент можно в S3 Мирана) └── other/ ← прочие важные данные (конфиги, скрипты, что ещё решите) ``` Квоты: при необходимости ограничить размер по каталогам (например `proxmox/dump` — не более 500 ГБ) через отдельные подразделы или скрипты очистки (retention). --- ### Шифрование диска бэкапов (LUKS) **LUKS** (Linux Unified Key Setup) — стандартное шифрование раздела в Linux. Если диск с бэкапами украдут или вынесут, без пароля/ключа данные не прочитать. Минусы: нужно вводить пароль при загрузке (или хранить ключ на другом носителе), небольшая нагрузка на CPU. **Принято:** LUKS пока не используем. Раздел sdb1 — без шифрования. При необходимости можно добавить позже (потребуется перенос данных). --- ### Restic и Yandex Object Storage - **Restic** поддерживает бэкенд **S3**. Yandex Object Storage совместим с S3 API — используешь endpoint бакета и ключи (Access Key / Secret). - **Retention в Yandex:** 3 daily, 2 weekly, 2 monthly — `restic forget --keep-daily 3 --keep-weekly 2 --keep-monthly 2` и затем `prune`. - **Что гнать в Yandex через restic:** Proxmox dump (каталог `proxmox/dump`), `/etc/pve` (архивы из `proxmox/etc-pve`), фотки (оригиналы + метаданные + БД Immich), бэкапы с VPS — см. «Принятые решения: что куда» ниже. **Локально отдельной политики retention для restic не нужно:** на sdb1 retention задаётся в самом Proxmox Backup Job (например «keep last 7») и в скрипте бэкапа `/etc/pve` (удалять архивы старше N дней). Restic используется только для отправки в Yandex с политикой 7/4/6. Локальных restic-репозиториев можно не заводить — только каталоги и выгрузка их содержимого в облако. Документация Yandex: [Object Storage S3](https://yandex.cloud/ru/docs/storage/s3/). Нужны: bucket name, region, endpoint, Static Key (Access Key ID + Secret Access Key). **Бакет создан; ключи и endpoint зафиксировать при настройке restic.** --- ### Хранилище паролей Чтобы не терять пароли при восстановлении и держать креды в одном месте. Рассматривались варианты: Vaultwarden (self-hosted), Bitwarden Cloud, KeePass/KeePassXC, 1Password и др. **Принято и сделано:** **Vaultwarden** развёрнут на **CT 103** LXC. Домен через NPM (HTTPS), клиенты Bitwarden на ПК/телефоне. Бэкап данных Vaultwarden включён в общий план (restic → Yandex). --- ### Где запускать бэкапы (централизация) **С хоста Proxmox (cron на ноде):** - **Proxmox Backup Job** уже выполняется на хосте и пишет vzdump всех выбранных LXC/VM в `/mnt/backup/proxmox/dump` — это и есть «бэкапы всех контейнеров и ВМ», централизованно. - **Restic** (backup/forget/prune) тоже запускаем с хоста по cron: бэкапит каталоги на хосте (например весь `/mnt/backup` или выбранные подкаталоги) в Yandex S3. Данные для бэкапа — локальные пути (dump, etc-pve, а фотки и данные с VPS нужно либо копировать на хост в `/mnt/backup` скриптами, либо монтировать и тогда restic будет их читать с хоста). Контейнеры и ВМ целиком не бэкапим через restic — ими занимается только Proxmox Backup Job. --- ### Шаг 3. Настроить расписание бэкапа LXC и VM 1. **Datacenter → Backup** (или **Backup** в меню узла). 2. **Add** — создаётся задача (Job). 3. Параметры: - **Storage** — выбранное хранилище (шаг 2). - **Schedule** — например `0 2 * * *` (каждую ночь в 02:00). Подстроить под окно, когда нагрузка минимальна. - **Selection mode:** включить нужные узлы (или **All**), затем отметить **галочками** конкретные **LXC (100–108) и VM (200)**. Либо выбрать "Backup all" для всех VMs/containers. - **Mode:** - **Snapshot** — контейнер/ВМ не останавливается, создаётся снимок (рекомендуется для минимизации даунтайма). - **Suspend** — ВМ приостанавливается на время бэкапа (более консистентно для БД, но даунтайм). Для LXC обычно достаточно **Snapshot**. Для **VM 200** (PostgreSQL и др.): Snapshot **не гарантирует консистентность БД** — PostgreSQL может быть в середине транзакции. **Правильная стратегия:** внутри VM делать логический бэкап БД (`pg_dump`), а **vzdump snapshot** использовать для остального (ОС, конфиги, файлы). Итого: VM 200 — vzdump snapshot ок для образа; консистентность БД — отдельно через `pg_dump` внутри гостя. - **Compression:** ZSTD (хороший компромисс скорость/размер). - **Retention:** например «Keep last 7» или «Keep last 4 weekly» — чтобы не забивать диск. 4. Сохранить job. Проверить по кнопке **Backup now**, что задача запускается и файлы появляются в Storage. Важно: бэкап должен включать **и LXC, и VM 200**. Не только данные внутри них (те уже описаны в документации контейнеров), а именно полный dump для restore. --- ### Шаг 4. Бэкап /etc/pve и конфигов хоста Конфиги кластера и виртуалок лежат в `/etc/pve`. Плюс для восстановления хоста полезны: `/etc/network/interfaces`, `/etc/hosts`, `/etc/resolv.conf`. Всё это нужно копировать регулярно и хранить в безопасном месте (желательно не только на том же диске, что и система). **Принято: вариант A — cron на хосте Proxmox.** 1. Создать скрипт, например `/root/scripts/backup-etc-pve.sh`: ```bash #!/bin/bash BACKUP_ROOT="/mnt/backup/proxmox/etc-pve" # по структуре выше DATE=$(date +%Y%m%d-%H%M) mkdir -p "$BACKUP_ROOT" tar -czf "$BACKUP_ROOT/etc-pve-$DATE.tar.gz" -C / etc/pve tar -czf "$BACKUP_ROOT/etc-host-configs-$DATE.tar.gz" -C / etc/network/interfaces etc/hosts etc/resolv.conf # опционально: удалять бэкапы старше N дней # find "$BACKUP_ROOT" -name 'etc-pve-*.tar.gz' -mtime +30 -delete # find "$BACKUP_ROOT" -name 'etc-host-configs-*.tar.gz' -mtime +30 -delete ``` 2. Сделать исполняемым: `chmod +x /root/scripts/backup-etc-pve.sh`. 3. Добавить в cron: `crontab -e`. Окно внутренних бэкапов 01:00–03:30; пример для etc-pve: `15 2 * * * /root/scripts/backup-etc-pve.sh` **Вариант B:** Тот же скрипт можно вызывать из задачи в Proxmox (Script/Command в задаче типа Hook script), но проще и надёжнее — отдельный cron на хосте. Бэкапы (`etc-pve-*.tar.gz`, `etc-host-configs-*.tar.gz`) хранить **локально** (`/mnt/backup/proxmox/etc-pve`) и **в Yandex** — включить этот каталог в источники restic (мало весит, критично при потере хоста). Файлы с ограниченными правами (chmod 600); `/etc/pve` содержит секреты — не выкладывать в открытый доступ. --- ### Шаг 5. Хранить секреты отдельно (пароли, ключи) Чтобы «не вспоминать пароли 3 часа» после восстановления: **Секретное хранилище** — Vaultwarden на **CT 103** (см. выше). Туда: root Proxmox, пользователи PVE, пароли БД и сервисов (Nextcloud, Gitea, Paperless, Immich, NPM, Galene и т.д.), API-ключи (Beget, certbot, Wallos и др.). Полный список кредов по контейнерам — в статьях container-100 … container-200; свести в один список в Vaultwarden и обновлять при смене паролей. Это не «шаг бэкапа», но обязательная часть восстановления: без паролей восстановленные контейнеры не войдут в сервисы. **Инвентаризация секретов для переноса в Vaultwarden** — ниже сводная таблица: где лежат креды сейчас и какой объект в Vaultwarden им соответствует. Команды для получения значений из Vaultwarden и переключение скриптов — в разделе «Получение секретов из Vaultwarden» ниже. | Хост / CT / VM | Текущее место | Объект Vaultwarden | |----------------|----------------|---------------------| | Proxmox (хост) | root, пользователи PVE | (в менеджере вручную) | | Proxmox (хост) | `/root/.restic-yandex.env`, `/root/.restic-password` | **RESTIC** (поля: RESTIC_BACKUP_KEY, RESTIC_REPOSITORY, AWS_ACCESS_KEY_ID, AWS_DEFAULT_REGION, AWS_SECRET_ACCESS_KEY, TELEGRAM_SELF_CHAT_ID) | | Proxmox (хост) | `/root/.telegram-notify.env` | **HOME_BOT_TOKEN** (пароль = токен бота), **RESTIC** (поле TELEGRAM_SELF_CHAT_ID = chat_id) | | CT 100 | `/root/.secrets/certbot/beget.ini` | **beget** (логин, пароль) | | CT 100 | NPM админка | (в менеджере вручную) | | CT 100 | VPN Route Check compose | **localhost** (логин admin, пароль, поле ROUTER_TELNET_HOST) | | CT 100 | custom_ssl / letsencrypt | (восстановление из /etc/letsencrypt; в Vaultwarden не храним) | | CT 101 | Nextcloud compose, config.php | **NEXTCLOUD** (логин nextcloud, пароль; поля: NEXTCLOUD_TRUSTED_DOMAINS, instanceid, passwordsalt, secret, dbpassword) | | CT 103 | Gitea compose, .env, app.ini | **GITEA** (логин gitea, пароль; поля: GITEA__database__DB_TYPE, GITEA__database__HOST, GITEA_RUNNER_REGISTRATION_TOKEN, LFS_JWT_SECRET, INTERNAL_TOKEN) | | CT 103 | CouchDB local.ini | **OBSIDIAN** (логин obsidian, пароль) | | CT 103 | Vaultwarden .env | **VAULTWARDEN** (пароль = ADMIN_TOKEN, поле SIGNUPS_ALLOWED) | | CT 104 | Paperless compose, docker-compose.env | **PAPERLESS** (логин paperless, пароль; поля: PAPERLESS_URL, PAPERLESS_SECRET_KEY, PAPERLESS_TIME_ZONE, PAPERLESS_OCR_LANGUAGE, PAPERLESS_OCR_LANGUAGES) | | CT 107 | Invidious compose | **INVIDIOUS** (логин kemal, пароль; поля: SERVER_SECRET_KEY, test) | | CT 108 | ice-servers.json | **GALENE** (поле config — JSON TURN) | | VM 200 | `/opt/immich/.env` | **IMMICH** (логин/пароль и поля по .env) | | VM 200 | `/opt/immich-deduper/.env` | **IMMICH_DEDUPER** (логин postgres, пароль; поля: DEDUP_PORT, DEDUP_DATA, DEDUP_IMAGE, IMMICH_PATH, PSQL_HOST, PSQL_PORT, PSQL_DB) | | Proxmox (хост) | `/root/.vps-miran-s3.env` | **MIRAN_S3** (поля: S3_ACCESS_KEY, S3_SECRET_KEY, S3_BUCKET_NAME) | --- #### Получение секретов из Vaultwarden **Требования:** установлены `bw` (Bitwarden CLI) и `jq`; настроен сервер: `bw config server https://vault.katykhin.ru`. Мастер-пароль задаётся через переменную `BW_MASTER_PASSWORD` или через **файл с доступом только для текущего пользователя** (`chmod 600`), например `/root/.bw-master`; файл не хранить в репозитории. Перед запросами: `bw sync` и разблокировка: `export BW_SESSION=$(bw unlock --passwordenv BW_MASTER_PASSWORD --raw)` или `bw unlock --passwordfile /path/to/file --raw`. **Команды по объектам** (выполнять после `bw unlock` в той же сессии): | Объект | Логин / пароль | Кастомное поле | |--------|----------------|----------------| | **beget** | `bw get username "beget"`, `bw get password "beget"` | — | | **GALENE** | — | `bw get item "GALENE" \| jq -r '.fields[] \| select(.name=="config") \| .value'` | | **GITEA** | `bw get username "GITEA"`, `bw get password "GITEA"` | `bw get item "GITEA" \| jq -r '.fields[] \| select(.name=="ИМЯ_ПОЛЯ") \| .value'` — подставить GITEA_RUNNER_REGISTRATION_TOKEN, LFS_JWT_SECRET, INTERNAL_TOKEN, GITEA__database__DB_TYPE, GITEA__database__HOST | | **HOME_BOT_TOKEN** | — | пароль = токен: `bw get password "HOME_BOT_TOKEN"` | | **IMMICH** | по структуре в Vaultwarden | `bw get item "IMMICH" \| jq '.fields'` | | **IMMICH_DEDUPER** | `bw get username "IMMICH_DEDUPER"`, `bw get password "IMMICH_DEDUPER"` | поля DEDUP_*, IMMICH_PATH, PSQL_* — через `jq -r '.fields[] \| select(.name=="X") \| .value'` | | **INVIDIOUS** | `bw get username "INVIDIOUS"`, `bw get password "INVIDIOUS"` | `bw get item "INVIDIOUS" \| jq -r '.fields[] \| select(.name=="SERVER_SECRET_KEY") \| .value'` | | **localhost** | `bw get username "localhost"`, `bw get password "localhost"` | `bw get item "localhost" \| jq -r '.fields[] \| select(.name=="ROUTER_TELNET_HOST") \| .value'` | | **MIRAN_S3** | — | S3_ACCESS_KEY: `bw get item "MIRAN_S3" \| jq -r '.fields[] \| select(.name=="S3_ACCESS_KEY") \| .value'`; аналогично S3_SECRET_KEY, S3_BUCKET_NAME | | **NEXTCLOUD** | `bw get username "NEXTCLOUD"`, `bw get password "NEXTCLOUD"` | secret: `bw get item "NEXTCLOUD" \| jq -r '.fields[] \| select(.name=="secret") \| .value'`; dbpassword, passwordsalt, instanceid, NEXTCLOUD_TRUSTED_DOMAINS — то же с `.name=="..."` | | **OBSIDIAN** | `bw get username "OBSIDIAN"`, `bw get password "OBSIDIAN"` | — | | **PAPERLESS** | `bw get username "PAPERLESS"`, `bw get password "PAPERLESS"` | PAPERLESS_SECRET_KEY, PAPERLESS_URL и др. — `bw get item "PAPERLESS" \| jq -r '.fields[] \| select(.name=="PAPERLESS_SECRET_KEY") \| .value'` | | **RESTIC** | — | RESTIC_BACKUP_KEY: `bw get item "RESTIC" \| jq -r '.fields[] \| select(.name=="RESTIC_BACKUP_KEY") \| .value'`; RESTIC_REPOSITORY, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_DEFAULT_REGION, TELEGRAM_SELF_CHAT_ID — то же с нужным `.name` | | **VAULTWARDEN** | — | пароль = ADMIN_TOKEN: `bw get password "VAULTWARDEN"`; SIGNUPS_ALLOWED — из полей | **Универсальный шаблон для поля по имени:** `bw get item "ИМЯ_ОБЪЕКТА" | jq -r '.fields[] | select(.name=="ИМЯ_ПОЛЯ") | .value'` --- #### Переключение скриптов на секреты из Vaultwarden Ниже — как перейти с чтения из файлов на подстановку из `bw` на **хосте Proxmox**. Мастер-пароль хранить **только в файле с доступом для текущего пользователя:** `chmod 600 /root/.bw-master` (владелец root — только root читает/пишет); в репозиторий файл не коммитить. Либо задавать переменную окружения при запуске по крону. **1. Restic (backup-restic-yandex.sh, backup-restic-yandex-photos.sh, restore-one-vzdump-from-restic.sh)** Сейчас: `source /root/.restic-yandex.env`, пароль из `/root/.restic-password`. Переключение: в начале скрипта (после `set -e`) разблокировать BW и выставить переменные из объекта **RESTIC**: ```bash # Разблокировать Vaultwarden (мастер-пароль из файла с chmod 600 или env) BW_MASTER_PASSWORD_FILE="${BW_MASTER_PASSWORD_FILE:-/root/.bw-master}" if [ -f "$BW_MASTER_PASSWORD_FILE" ]; then export BW_SESSION=$(bw unlock --passwordfile "$BW_MASTER_PASSWORD_FILE" --raw) fi # Подставить секреты из RESTIC ITEM=$(bw get item "RESTIC") export RESTIC_REPOSITORY=$(echo "$ITEM" | jq -r '.fields[] | select(.name=="RESTIC_REPOSITORY") | .value') export AWS_ACCESS_KEY_ID=$(echo "$ITEM" | jq -r '.fields[] | select(.name=="AWS_ACCESS_KEY_ID") | .value') export AWS_SECRET_ACCESS_KEY=$(echo "$ITEM" | jq -r '.fields[] | select(.name=="AWS_SECRET_ACCESS_KEY") | .value') export AWS_DEFAULT_REGION=$(echo "$ITEM" | jq -r '.fields[] | select(.name=="AWS_DEFAULT_REGION") | .value') RESTIC_PASSWORD=$(echo "$ITEM" | jq -r '.fields[] | select(.name=="RESTIC_BACKUP_KEY") | .value') export RESTIC_PASSWORD_FILE=$(mktemp -u) echo -n "$RESTIC_PASSWORD" > "$RESTIC_PASSWORD_FILE" chmod 600 "$RESTIC_PASSWORD_FILE" trap 'rm -f "$RESTIC_PASSWORD_FILE"' EXIT ``` Убрать из скрипта: проверку/чтение `ENV_FILE` и `RESTIC_PASSWORD_FILE` из файлов; оставить использование переменных `RESTIC_REPOSITORY`, `AWS_*`, `RESTIC_PASSWORD_FILE` как выше. Для restore-one-vzdump-from-restic.sh — тот же блок в начале. **2. Telegram (notify-telegram.sh)** Сейчас: `source /root/.telegram-notify.env`, переменные `TELEGRAM_BOT_TOKEN`, `TELEGRAM_CHAT_ID`. Переключение: читать токен из **HOME_BOT_TOKEN** (пароль), chat_id из объекта **RESTIC** (поле TELEGRAM_SELF_CHAT_ID). В начале скрипта (если нет уже разблокировки): ```bash BW_MASTER_PASSWORD_FILE="${BW_MASTER_PASSWORD_FILE:-/root/.bw-master}" if [ -f "$BW_MASTER_PASSWORD_FILE" ]; then export BW_SESSION=$(bw unlock --passwordfile "$BW_MASTER_PASSWORD_FILE" --raw) fi TELEGRAM_BOT_TOKEN=$(bw get password "HOME_BOT_TOKEN") TELEGRAM_CHAT_ID=$(bw get item "RESTIC" | jq -r '.fields[] | select(.name=="TELEGRAM_SELF_CHAT_ID") | .value') ``` Дальше в скрипте использовать `TELEGRAM_BOT_TOKEN` и `TELEGRAM_CHAT_ID` как раньше (проверка на пустоту, вызов curl). Файл `/root/.telegram-notify.env` можно не использовать. **3. Дампы БД (backup-ct101-pgdump.sh, backup-ct104-pgdump.sh, backup-ct103-gitea-pgdump.sh)** Скрипты уже берут PGPASSWORD из Vaultwarden: в начале разблокировка `bw unlock --passwordfile "$BW_MASTER_PASSWORD_FILE" --raw`, затем для pg_dump передаётся `-e PGPASSWORD=...` в `docker exec`. Источники паролей: - **Nextcloud (CT 101):** объект **NEXTCLOUD** — поле `dbpassword` или пароль записи (`bw get password "NEXTCLOUD"`). - **Paperless (CT 104):** объект **PAPERLESS** — пароль (`bw get password "PAPERLESS"`). - **Gitea (CT 103):** объект **GITEA** — пароль (`bw get password "GITEA"`). Требования на хосте: `bw`, для Nextcloud — `jq`; файл `/root/.bw-master` с мастер-паролем (chmod 600). При ошибке (дамп < 512 байт) скрипт завершается с кодом 1 и выводит stderr; уведомление в Telegram при ошибке не отправляется. **4. Остальные места** Конфиги сервисов (Nextcloud config.php, Gitea compose, Paperless .env, Immich .env и т.д.) подставлять вручную при восстановлении или написать небольшие скрипты-обёртки, которые один раз получают нужные значения через `bw get item` / `bw get password` и пишут в .env или конфиг. Имена объектов и полей — по таблице выше. После переключения: обновить чек-лист (отметить «Секреты перенесены в Vaultwarden») и при необходимости добавить в cron установку `BW_MASTER_PASSWORD_FILE` или вызов разблокировки в общем wrapper’е. --- ### Шаг 6. Тестовое восстановление одного контейнера Без проверки восстановления нельзя считать стратегию рабочей. 1. Выбрать **некритичный** контейнер (например 105 — RAG, или 107 — Invidious), для которого краткий даунтайм допустим. 2. Убедиться, что есть свежий backup этого контейнера в Storage (после шага 3). 3. **Восстановление:** - В Proxmox UI: **Datacenter → Backup** → выбрать storage → найти backup нужного CT → **Restore**. Указать **new VMID** (например 999 для теста) и **Storage** для дисков. - Или с CLI: `qmrestore` для VM, для LXC — через GUI или `pct restore` (см. справку `pct restore`). Для LXC типично: Backup → Restore → задать новый ID (например 999), node, storage. 4. Запустить восстановленный контейнер (ID 999), проверить: - заходит по SSH/консоль; - сервисы внутри запускаются (docker/ systemd); - с хоста пинг и при необходимости один сервис по порту. 5. После проверки удалить тестовый контейнер (999), освободить место. Если что-то пошло не так (не находится диск, ошибка прав, сеть) — зафиксировать и поправить стратегию (пути storage, режим backup, права). --- ### Шаг 7. Документировать процедуру восстановления «с нуля» Кратко зафиксировать в отдельном разделе (здесь или в architecture): 1. Установка Proxmox на новое железо (или новый диск). 2. Восстановление конфигов: распаковать последний `etc-pve-*.tar.gz` в `/etc/pve` (с учётом того, что нужно корректно подставить ноды и storage; при одномузловой установке обычно достаточно скопировать файлы). 3. Подключение storage с backup (или копирование последних vzdump на новый storage). 4. Восстановление контейнеров и ВМ из backup по одному (Restore с указанием VMID и storage). 5. Запуск контейнеров/ВМ, проверка сети и сервисов. 6. Использование сохранённых паролей/ключей для входа и проверки сервисов. После первого успешного тестового восстановления (шаг 6) эту процедуру можно уточнить и дописать по факту. --- ## Чек-лист фазы 1 - [x] Разметка: 1 ТБ на sdb1, ФС, монтирование в `/mnt/backup` (без LUKS). *(скрипт `scripts/backup-setup-sdb1-mount.sh`, каталоги созданы.)* - [x] В Proxmox добавлен Storage для VZDump → `/mnt/backup/proxmox/dump`. - [x] Настроена регулярная задача Backup: LXC (100–108), расписание ночь (02:00), retention задан. *VM 200 исключена из задания (образ ~380 ГБ); восстановление VM 200 — по инструкции «с нуля» в [backup-howto](backup-howto.md).* - [x] Проверен ручной запуск Backup now — файлы появляются в storage. *(рекомендуется проверить разово.)* - [x] Настроен бэкап `/etc/pve` (скрипт + cron) → `/mnt/backup/proxmox/etc-pve`. *(backup-etc-pve.sh, 02:15, 30 дней.)* - [x] Restic: cron на хосте, выгрузка каталогов из `/mnt/backup` в Yandex S3. *(backup-restic-yandex.sh 04:00, backup-restic-yandex-photos.sh 04:10, retention 3 daily / 2 weekly / 2 monthly.)* - [x] Yandex: ключи и endpoint зафиксированы в `/root/.restic-yandex.env`, restic пишет в бакет. - [x] Vaultwarden развёрнут (CT 103). - [ ] Секреты перенесены в Vaultwarden. *(на усмотрение: root PVE, пароли БД, API и т.д.)* - [x] Бэкап данных Vaultwarden включён в restic (Yandex S3). *Локально: backup-vaultwarden-data.sh → `/mnt/backup/other/vaultwarden/`; restic выгружает весь `/mnt/backup` (кроме photos), каталог vaultwarden входит в снимок.* - [x] Выполнено тестовое восстановление одного контейнера (другой VMID), проверена работоспособность. *(26.02.2026: восстановлен CT 107 в слот 999 из `/mnt/backup/proxmox/dump/dump/vzdump-lxc-107-*.tar.zst`, проверены консоль, пинг, Docker, Invidious на 3000; тестовый CT удалён.)* - [x] В документации зафиксирована процедура полного восстановления Proxmox «с нуля». *[backup-howto.md](backup-howto.md): восстановление из vzdump, конфигов, БД, VM 200 с нуля, Vaultwarden, VPS и др.* --- ## Ссылки - [Архитектура и подключение](../architecture/architecture.md) — хосты, IP, домены. - [Схема сети и зависимости](../network/network-topology.md) — SPOF, зависимость от Proxmox и бэкапов. - [Vaultwarden и использование секретов](../vaultwarden-secrets.md) — установка bw, разблокировка, получение секретов в скриптах. - Документация контейнеров (100–108, 200) — бэкапы *данных внутри* сервисов (БД, тома); фаза 1 дополняет это бэкапом на уровне PVE. --- ## Принятые решения (сводка) | Вопрос | Решение | |--------|---------| | Точка монтирования, второй ТБ | `/mnt/backup`; второй ТБ на sdb1 — в запас, назначение позже. | | Шифрование (LUKS) | Пока не делаем; раздел без шифрования. | | Proxmox vzdump | Локально в `proxmox/dump` + дублировать в Yandex через restic. | | Фотки | Оригиналы + метаданные + БД Immich; остальное пересчитать. | | VPS | Amnezia — конфиг. Миран — БД бота + контент (контент можно в S3 Мирана; копия на sdb1 — по желанию). Конфиг серверов не бэкапим — Ansible. | | Где запускать бэкапы | Cron на хосте Proxmox: Backup Job (vzdump) + restic в Yandex. | | Retention локально | Только в Proxmox Job и в скрипте etc-pve; отдельного restic-репозитория локально не делаем. | | /etc/pve + конфиги хоста (interfaces, hosts, resolv.conf) | Вариант A: cron на хосте → `etc-pve` и `etc-host-configs` в `/mnt/backup/proxmox/etc-pve`; локально и в Yandex (restic). | | Пароли | Vaultwarden на CT 103. | | VM 200 (БД PostgreSQL) | vzdump snapshot — для образа ВМ; консистентность БД — отдельно: внутри VM логический бэкап (`pg_dump`). | | Yandex | Бакет создан; ключи и endpoint зафиксировать при настройке restic. | | MinIO | Не используем; директории + restic (s3 для Yandex). | --- ## Осталось сделать - **Проверка ручного Backup:** один раз запустить «Backup now» в Proxmox UI (Datacenter → Backup) и убедиться, что файлы появляются в `/mnt/backup/proxmox/dump/dump/`. - **Секреты (по желанию):** перенести пароли/ключи (root PVE, БД, API) в Vaultwarden и обновлять при смене. *Выполнено ранее: Yandex + Restic (cron, retention 3/2/2), тестовое восстановление CT 107 → 999 (26.02.2026).*