Что такое резервная копия
Резервная копия — это выводpg_dump --format=custom --no-owner --no-privileges --compress=6,
зашифрованный AES-256-GCM и записанный в APP_BACKUP_DIR. Omniflow вызывает
pg_dump и pg_restore как внешние программы, а не переписывает их заново, поэтому
резервную копию всегда можно восстановить штатными средствами PostgreSQL, даже если сам
Omniflow не запускается.
Шифрование кадровое, а не один запечатанный блок, поэтому многогигабайтный дамп никогда не
обязан помещаться в память:
omniflow-<kind>-<UTC timestamp>.dump.enc, например
omniflow-scheduled-20260811T030000Z.dump.enc. kind — это scheduled или manual и ничего
больше: на столбце стоит check-ограничение, поэтому третий вид потребует миграции. Имя
уникально, а файл создаётся эксклюзивно, поэтому коллизия приводит к ошибке, а не к
перезаписи.
Кто её создаёт
Операторская панель в отношении резервных копий работает только на чтение. Нет ни маршрута
панели, ни маршрута
/v1/admin, который создаёт или восстанавливает копию; единственные два
пути записи в продукте — это расписание воркера и поверхность /ops у бота. Это сделано
намеренно: восстановление разрушительно, и оно живёт за явно перечисленным списком аккаунтов
Telegram, а не за правом доступа, которое можно выдать шести ролям.Включение резервных копий
Образы бота и воркера поставляются с соответствующими клиентскими утилитами PostgreSQL 18. В
compose-стеке оба монтируют общий том
backup-data в /var/lib/omniflow/backups, поэтому
пересборка контейнера никогда не выбрасывает резервные копии.
Пароль базы данных никогда не попадает в argv дочернего процесса, где любой локальный
пользователь мог бы прочитать его из списка процессов. Вместо этого DSN раскладывается на
PGHOST, PGPORT, PGDATABASE, PGUSER, PGPASSWORD и PGSSLMODE в окружении дочернего
процесса.
Проверка
Резервная копия записывается какcompleted только после того, как её прочитали обратно: файл
расшифровывается от начала до конца, а его SHA-256-дайджест сравнивается с дайджестом,
посчитанным при записи. Копия, не прошедшая любую из этих проверок, удаляется и записывается
как failed с классифицированным кодом ошибки.
Это выполняется при каждой резервной копии, а не только по требованию. Непроверенная резервная
копия — это догадка.
Управление из Telegram
Telegram несёт только операторские уведомления и действия по резервным копиям и восстановлению. Все остальные административные органы управления живут в веб-панели./ops вообще никакого ответа — даже
отказа, который подтвердил бы существование команды. Команда также игнорируется вне приватного
чата с ботом.
/ops показывает пять последних резервных копий с именем файла, статусом (и кодом ошибки, если
он записан), размером и меткой времени в UTC, а также:
- 💾 Сделать копию сейчас — немедленно создаёт ручную резервную копию. Если одна уже выполняется, ответом будет «A backup is already running», а не запуск второй.
- ♻️ Восстановить последнюю… — предлагается только при наличии завершённой копии. Подтверждение в два шага: первое нажатие лишь показывает предупреждение, а второе несёт идентификатор той резервной копии, которую оператор видел.
- 🔄 Обновить — перерисовывает список.
backup.created для ручной копии,
затем backup.restore_requested и backup.restored вокруг восстановления. Причина
восстановления записывается как «restore requested from Telegram by operator <id>».
Восстановление
Восстановление сначала проверяет резервную копию, затем запускаетpg_restore --clean --if-exists --no-owner --no-privileges --single-transaction с
расшифрованным потоком на stdin. Оно намеренно прямолинейно, и именно поэтому настаивает,
чтобы вызывающая сторона подтвердила разрушительное намерение и чтобы было записано, кто
попросил.
Оно отказывает, а не выполняется наполовину, в следующих случаях:
Перед восстановлением:
- Остановите
api,botиworker. Живой воркер продолжит выдавать доступ поверх состояния, которое вот-вот будет заменено. - Сделайте свежую резервную копию текущей базы, даже если вы считаете её сломанной. Это единственный путь назад из ошибочного восстановления.
- Убедитесь, что статус целевой резервной копии —
completed.
- Запустите сначала
workerи следите за/readyzи топиком исполнения заказов. - Запустите
apiиbot. - Сверьтесь с Remnawave. Выдача доступа, случившаяся после точки резервной копии, всё ещё живёт в панели, но отсутствует в Omniflow. Плановое обнаружение расхождений сообщит о несоответствиях в течение пятнадцати минут, и каждое из них решается из представления расхождений.
- Перепроверьте платежи в ожидании. Платёж, проведённый после точки резервной копии, подхватывается опросом сверки или повторной доставкой вебхука провайдера. Оба идемпотентны, поэтому ничто не списывается и не зачисляется дважды.
/ops, поэтому именно в
его логе описан сбой, хотя сообщение на экране упоминает воркер.
Восстановление без бота
Бинарник воркера заодно работает как фильтр расшифровки, потому что аварийное восстановление не должно зависеть от способности остального стека запуститься. Ему не нужно ничего, кроме бинарника, ключа и файла:--decrypt-backup должен быть первым аргументом, а ключ читается из окружения до загрузки
какой-либо конфигурации — не требуется ни база данных, ни Valkey, ни учётные данные Remnawave.
Он падает с APP_BACKUP_ENCRYPTION_KEY is required to decrypt a backup или
APP_BACKUP_ENCRYPTION_KEY must be base64-encoded 32 bytes, а при неверном ключе или
повреждённом файле падает громко, а не выдаёт частичный вывод.
Atlas записывает применённые миграции в собственную схему
atlas_schema_revisions, а не в
public. Дамп, снятый Omniflow, несёт всю базу целиком, поэтому обычное восстановление
переносит эту историю вместе с ней. Если вы пересобираете базу иным способом, перенесите эту
схему тоже, иначе сервис migrate попытается применить историю заново, а диагностический
комплект сообщит о нуле применённых миграций.Срок хранения и очистка
Каждая строка резервной копии при создании помечаетсяretain_until — на
APP_BACKUP_RETENTION_DAYS вперёд. После каждого планового запуска воркер очищает до 100
просроченных копий: файл удаляется, а строка помечается как pruned. Строка сохраняется,
поэтому история того, какие копии существовали, остаётся пригодной для аудита после того, как
файлы исчезли.
Файл, который не удалось удалить, логируется и пропускается, а его строка сохраняет свой
статус, поэтому следующий проход пробует снова, а не теряет его из виду.
Просмотр истории
Резервная копия, которую никто никогда не восстанавливал, — это копия, о которой никто не
знает, работает ли она; именно поэтому история восстановлений находится рядом со списком
копий, а не на отдельном экране.
Обновление Omniflow
Миграции применяются только вперёд, и их накатывает сервисmigrate до старта любого
прикладного процесса.
- Сделайте резервную копию и убедитесь, что она
completed. - Загрузите новые образы. Закрепляйте явный тег; плавающие теги делают откат неоднозначным.
- Выполните
docker compose up -d. Сервисmigrateзапускаетatlas migrate apply, и все остальные сервисы ждут его успешного завершения. - Следите за
/readyzна каждом процессе.
Сервис
migrate в compose использует жёстко заданную строку подключения и не читает
APP_DATABASE_URL. Если вы поменяли учётные данные базы, поменяйте их и в compose.yaml,
иначе мигратор подключится не к той базе.Откат
Omniflow не поставляет обратных миграций. Откат схемы — это восстановление:- Остановите
api,botиworker. - Восстановите резервную копию, снятую перед обновлением.
- Закрепите предыдущие теги образов и запустите стек.
- Сверьтесь с Remnawave, как описано выше.
Обновление PostgreSQL
Omniflow поддерживает PostgreSQL 18. Чтобы перейти между мажорными версиями:- Остановите
api,botиworker;postgresоставьте работающим. - Сделайте резервную копию и проверьте её.
- Остановите
postgresи запустите новую мажорную версию поверх пустого каталога данных. - Восстановите резервную копию.
- Запустите прикладные процессы.
pg_upgrade —
альтернатива, если вы предпочитаете обновление на месте, но путь «дамп и восстановление» — тот,
под который спроектирован этот формат резервных копий. Помните, что pg_dump и pg_restore
должны соответствовать мажорной версии сервера; поставляемые образы фиксируют клиентские
утилиты PostgreSQL 18 именно по этой причине.
Учения по аварийному восстановлению
Проводите их ежеквартально. Непроверенная резервная копия — это предположение.completed, расшифровывает её через worker --decrypt-backup, восстанавливает в
одноразовый экземпляр PostgreSQL в сети самого стека, сравнивает число строк, открывает
запечатанное значение ключом APP_DATA_ENCRYPTION_KEY и снова удаляет экземпляр. Он никогда
не пишет в боевую базу и завершается с ненулевым кодом, когда учения провалились, — поэтому
запуск по расписанию что-то значит.
Передайте COMPOSE, если стек использует файлы переопределения, и TABLES, чтобы сравнить
другой набор:
Шаг с запечатанным значением пропускают чаще всего, и он же чаще всего проваливается: база,
восстановленная без её ключа шифрования данных, поднимается безупречно, а секреты в ней
нечитаемы. Скрипт открывает запечатанный клиентский секрет customer OIDC в одноразовом
контейнере, поэтому на хосте ничего устанавливать не нужно. Если в установке не настроен ни
один OIDC-провайдер, запечатанного значения для проверки нет — скрипт скажет об этом, а не
пройдёт молча; проверьте вручную секрет TOTP или учётные данные провайдера, прежде чем
доверять такой копии.
Записывайте дату и результат.
Больше, чем база данных: полное аварийное восстановление
Всё выше отвечает на вопрос «PostgreSQL потерян или повреждён». Катастрофа на уровне хоста — более широкий вопрос, и ответ на большую его часть таков: специальная процедура не нужна, потому что PostgreSQL — единственное долговременное хранилище, — но для двух вещей вне базы план всё же нужен.Потеря всего хоста
Восстановлениеpg_dump возвращает каждую строку. Оно не возвращает то, что всегда жило
только вне базы данных:
.env, либо то, что хранит его в вашем менеджере секретов.APP_DATA_ENCRYPTION_KEY. Это то, что важнее всего восстановить в первую очередь. Каждое запечатанное значение — секреты TOTP, клиентские секреты OIDC, учётные данные провайдеров, контактные значения клиентов — навсегда недоступно без него, и пути повторного шифрования не существует. См. Безопасность.APP_BACKUP_ENCRYPTION_KEY, хранимый отдельно от резервных копий, которые он расшифровывает, — копия, несущая оба ключа, это единственный артефакт, который расшифровывает сам себя.APP_OPERATOR_TOKEN, поскольку новый никто не выпускает; утраченный токен означает повторную инициализацию поверхности с bearer-токеном.- Конфигурация обратного прокси и материал TLS перед стеком, которые живут в вашем собственном хозяйстве, а не в Omniflow. См. Обратный прокси.
- DNS, указывающий на то, что заменяет утраченный хост.
Потеря Valkey
Это вообще не требует восстановления. Valkey хранит записи кэша, счётчики ограничения частоты запросов, блокировки и токены однократного использования — ничего долговременного, — поэтому утраченный экземпляр Valkey — это просто новый, запущенный пустым. См. Развёртывание. Автоматическое определение режима обслуживания следит за Valkey наравне с PostgreSQL и Remnawave, поэтому сбой приостанавливает новые покупки после той же серии отказов, что и любая другая зависимость, вместо того чтобы клиенты сталкивались с противоречивыми отказами ограничения частоты запросов и защиты от повтора посреди оформления заказа.RPO и RTO
Изложено на основе того, что реально настраивается, а не обещанной цифры, которую эта страница не может гарантировать:- Целевая точка восстановления (RPO) определяется
APP_BACKUP_INTERVAL_HOURS— по умолчанию 24 часа между плановыми резервными копиями, поэтому в худшем случае можно потерять активность за этот период. Уменьшите интервал ради более узкого RPO; ручная резервная копия из/opsперед рискованной операцией сужает его до нуля на этот момент. - Целевое время восстановления (RTO) определяется прежде всего временем восстановления, которое растёт вместе с размером базы данных, плюс окном сверки после возвращения стека — расхождения с Remnawave устраняются в течение пятнадцати минут после планового прохода сверки, а платежи в процессе рассчитываются на следующем тике сверятеля. Здесь нет фиксированной цифры, которую можно обещать: используйте продолжительность собственных учений как ориентир для вашей установки.
Связанные страницы
Развёртывание
Топология compose, тома и путь обновления, которые предполагают эти процедуры.
Диагностика неисправностей
Что означает каждый код ошибки резервного копирования и где читать лог.