Резервное копирование и восстановление
Система записи Planeon — это PostgreSQL. Всё, что платформа знает о вашем
развёртывании — пулы, сессии, ролевые привязки, история аудита, состояние
лицензирования и все хранимые учётные данные — находится там, запечатанное
в состоянии покоя ключом SECRETS_MASTER_KEY. Резервируйте все три вещи
ниже вместе, по одному расписанию — и вы сможете восстановить рабочее
развёртывание из ничего, кроме бэкапа и работающего кластера Proxmox.
Этот runbook предполагает раскладку эталонного production-стека:
compose.yaml и файл .env в одном каталоге, с заданными в .env
POSTGRES_DB, POSTGRES_USER, POSTGRES_PASSWORD и SECRETS_MASTER_KEY.
Скорректируйте пути, если ваша установка отличается.
Что резервировать
Три вещи, каждый раз — ни одна из них не опциональна:
- База данных Postgres, через
pg_dump. Это всё состояние платформы целиком: desktop-пулы, владение управляемыми ВМ, сессии, RBAC, история аудита, состояние активации лицензии и каждый зашифрованный секрет (API-токены Proxmox, учётные данные гостя/присоединения к домену). SECRETS_MASTER_KEY, резервируемый отдельно от дампа базы данных. Это ключ конверта AES, шифрующий каждое учётное данное выше. Резервная копия базы данных бесполезна без точного ключа, который был активен на момент её снятия — восстановление дампа под неверным ключом не деградирует мягко, оно падает прямо (см. предостережение ниже). Поскольку ключ может меняться со временем (окно ротации задаётSECRETS_MASTER_KEY_PREVIOUSи позднее выводит старый ключ из обращения), храните ключ, соответствующий каждому дампу, вместе с ним — не полагайтесь на то, какое значение случайно окажется в текущем.envна момент восстановления. Храните его в менеджере секретов или парольном хранилище, а не только внутри копии.env, лежащей рядом с SQL-дампом.- Файл
.env— домен, конфигурация OIDC-клиента, учётные данные Postgres и всё остальное, что нужно стеку для запуска. Без него вы всё ещё сможете восстановить базу данных, но вам придётся вручную заново вводить каждую настройку.
Что восстановимо из PVE, а что нет
Не всё, что хранит Planeon, обходится одинаково дорого, если бэкап к моменту восстановления устарел на несколько часов или дней (частичная потеря — гораздо более частый сценарий, чем полная потеря Postgres):
- Восстановимо: владение управляемыми ВМ и членство в desktop-пулах
выводятся из инвентаря Proxmox VE. Как только вы восстановите Postgres и
снова направите worker на живой кластер, следующий цикл сверки
пересканирует PVE и пересинхронизирует состояние пулов/ВМ — любое
расхождение между бэкапом и фактическим состоянием кластера само
устраняется в пределах одного интервала сверки
(
POOL_RECONCILE_INTERVAL, по умолчанию30s). - Не восстановимо — Postgres единственная копия: история аудита, ролевые привязки RBAC, состояние активации лицензии и каждое зашифрованное учётное данное (API-токены Proxmox, учётные данные гостя/присоединения к домену). Ничего из этого не существует больше нигде. Восстановление дампа старше вашего последнего изменения конфигурации безвозвратно теряет всё, что произошло после снятия дампа — ни со стороны PVE, ни где-либо ещё нет резервного источника, откуда это можно было бы воспроизвести.
Токены подключения Guacamole — особый случай, о котором стоит сказать отдельно именно потому, что резервировать их не нужно: они короткоживущие, выпускаются в Redis (не в Postgres) и истекают сами. Их потеря стоит пользователю одного переподключения, не больше.
Процедура резервного копирования
Запускайте это по расписанию (cron, systemd timer или ваш инструмент
резервного копирования) из каталога, где лежат compose.yaml и .env:
# Экспортируем .env в shell, чтобы $POSTGRES_USER/$POSTGRES_DB ниже
# разрешились — перенаправление вывода pg_dump происходит на хосте,
# а не внутри контейнера.
set -a
source .env
set +a
docker compose exec -T postgres pg_dump -U "$POSTGRES_USER" "$POSTGRES_DB" \
> "planeon-$(date +%F).sql"
date +%F даёт реальную календарную дату на момент запуска (например,
planeon-2026-07-12.sql) — ставьте метку времени на каждом дампе, чтобы
отличать бэкапы друг от друга и выбирать нужный для восстановления.
Вместе с дампом скопируйте текущее значение SECRETS_MASTER_KEY и сам файл
.env в защищённое хранилище резервных копий. Храните все три —
SQL-дамп, мастер-ключ, активный на момент его снятия, и .env — как один
согласованный набор.
Процедура восстановления
-
Остановите сервисы приложения, чтобы ничто не писало в Postgres во время восстановления и ни один сервис не стартовал против наполовину восстановленной схемы:
docker compose stop api worker gateway web caddy -
Восстановите в чистый Postgres. Если вы восстанавливаетесь на хосте, где уже есть том Postgres (аварийное восстановление на той же машине), сначала очистите его —
docker compose down -vудаляет именованные тома стека, включаяpostgres_data, поэтому делайте это только тогда, когда уверены, что хотите его перезаписать. Затем поднимите пустую базу данных:docker compose up -d postgres redisЗагрузите в неё дамп:
set -asource .envset +adocker compose exec -T postgres psql -U "$POSTGRES_USER" "$POSTGRES_DB" \< planeon-2026-07-12.sql -
Восстановите
.envиSECRETS_MASTER_KEY— перезапишите рабочий.envрезервной копией, соответствующей этому дампу (или как минимум убедитесь, чтоSECRETS_MASTER_KEYв текущем.env— это точное значение, которое было активно на момент снятия дампа). -
Убедитесь, что схема актуальна, прежде чем запускать сервисы приложения:
docker compose run --rm migrate statusКаждая миграция должна показывать
Applied. Восстановленный дамп уже несёт собственную строкуgoose_db_version, поэтому обычно она уже актуальна; если вы восстанавливаетесь на более старуюPLANEON_VERSION, чем та, на которой был снят дамп, сначала примените недостающие миграции командойdocker compose run --rm migrate. -
Запустите остальной стек:
docker compose up -dПроверьте готовность так же, как при свежей установке — см. Наблюдаемость → Семантика readiness.
Предостережение: несовпадающий мастер-ключ падает громко
Каждое приложение (api, worker, gateway) перед началом обслуживания
запросов выполняет стартовую проверку, которая пытается открыть каждый
хранимый конверт секрета сконфигурированным SECRETS_MASTER_KEY. Если ключ
не совпадает с тем, которым были запечатаны секреты в дампе, запуск
падает прямо с ошибкой, называющей таблицу и строку, которую не
удалось расшифровать — процесс не стартует в деградированном или тихо
сломанном состоянии.
Это сделано намеренно: тихо работать с нерасшифровываемыми учётными
данными было бы намного хуже, чем отказаться запускаться. Если вы видите
эту ошибку после восстановления, значит SECRETS_MASTER_KEY в
восстановленном .env не совпадает с ключом, который был активен на
момент снятия дампа — восстановите правильный ключ (а если восстановление
пришлось на окно ротации — и его пару SECRETS_MASTER_KEY_PREVIOUS) и
перезапустите сервисы.
Это самая частая ошибка при восстановлении: восстановить базу данных, не
восстановив соответствующий ей мастер-ключ. Храните их вместе в процессе
резервного копирования, а не только в .env — см. «Что резервировать»
выше.