Бэкапы
Minishop автоматически собирает ZIP-бэкапы в worker-контейнере, хранит архивы на сервере и отправляет их в Telegram. Из админки можно скачать архив, загрузить его на другой сервер и восстановить БД вместе с установленными плагинами и темами. Управляющие процессы сами останавливают backend и worker на время восстановления и запускают их после завершения.
На этой странице
Заголовок раздела «На этой странице»- Что попадает в архив
- Большие архивы и отправка частями
- Настройка
- Mount compose-папки
- Восстановление из админки
- Проверка архива перед восстановлением
- Перенос на другой сервер
- Резервный вариант: восстановление БД командой обслуживания
- Переменные
- Пользовательские темы
Что попадает в архив
Заголовок раздела «Что попадает в архив»Архив создается в BACKUP_DIR, по умолчанию data/backups внутри volume shop-data.
Типовой файл называется так:
Внутри:
database/<POSTGRES_DB>.dump-pg_dumpв custom format дляpg_restore;database/tariffs.json- каталог тарифов изTARIFFS_CONFIG_PATH, если файл существует;compose/- snapshot папки сdocker-compose.yml,.envи соседними конфигами;config/themes/— установленные пользовательские темы;config/plugin-store/— выбранные версии установленных подписанных плагинов, их состояние и доверенные ключи издателей;manifest.json— дата создания,minishop_version,database_metadata.migration_ids(полный список применённых миграций), версия PostgreSQL, адрес панели без учётных данных и параметров запроса, сведения о БД, compose snapshot и предупреждения.
Дамп и список миграций используют один экспортированный снимок PostgreSQL: миграционная история описывает именно данные архива. Версия формата ZIP и версия приложения — разные поля. Старые ZIP без новых метаданных поддерживаются: миграционная история читается из восстановленного дампа.
Если compose-папка не смонтирована или недоступна, worker не роняет весь бэкап: архив будет создан с дампом БД и предупреждением в manifest.json.
Большие архивы и отправка частями
Заголовок раздела «Большие архивы и отправка частями»ZIP до 45 000 000 байт отправляется одним документом. Более крупный архив автоматически
делится на бинарные части не больше 45 000 000 байт; вместе с ними отправляется
<archive>.zip.parts.json с порядком, размерами и SHA-256 частей и всего ZIP.
Telegram получает документы альбомами до 10 файлов, включая manifest. Если остаток состоит
из одного файла, он отправляется отдельным документом. Чат и topic/thread сохраняются.
Если Telegram отклоняет весь альбом по размеру запроса, файлы повторно отправляются отдельно.
При отклонении небольшого ZIP по размеру worker пробует более мелкие части.
Полный ZIP остаётся в BACKUP_DIR и доступен для скачивания из админки. Части создаются
только для доставки и удаляются из временной папки после успеха или ошибки. Ограничение
локального хранения полных ZIP применяется также при ошибке доставки. Для сетевых ошибок
и retry_after повторяется только текущая недоставленная группа, до трёх попыток;
после исчерпания попыток уведомление указывает число подтверждённых файлов. При сетевом
разрыве после принятия запроса Telegram возможен повтор группы; сверяйте имена и SHA-256.
Для восстановления через веб-интерфейс откройте Система → Бэкапы → Загрузить и выберите manifest и все части одного архива вместе. Порядок выбора не важен: сервер соберёт ZIP по manifest, проверит размеры и SHA-256 частей и всего ZIP, затем обычную целостность бэкапа. Готовый архив появится в списке: выберите его и восстановите БД или compose штатным способом. Части не требуют установки CLI или ручной сборки.
Нельзя смешивать части разных бэкапов, добавлять лишний ZIP или выбирать неполный комплект. Админка заранее проверяет список и размеры файлов; сервер дополнительно проверяет SHA-256. Повреждённый комплект не публикует архив; временные файлы удаляются также при ошибке или разрыве загрузки. Общий размер исходного ZIP ограничен 2 ГиБ. Одиночный ZIP загружается как прежде. Скачивание любого бэкапа из админки всегда возвращает один полный ZIP.
Если доставка Telegram не удалась при ручном создании, админка сохраняет успешный результат создания с предупреждением: полный ZIP доступен для скачивания и восстановления.
Для необязательной сборки через командную строку скачайте все части и manifest в одну папку:
Утилита проверяет каждый файл и SHA-256 исходного архива, затем атомарно создаёт ZIP рядом
с manifest. Существующий файл не перезаписывается; для другого пути используйте --output.
Отсутствующая или повреждённая часть не оставляет готовый ZIP. Загрузите собранный ZIP в
админке или передайте его стандартному scripts/restore-backup.sh. Отдельные .partNNNN
не являются самостоятельными ZIP и не подходят для прямого восстановления.
Для повторной доставки скачайте полный ZIP из админки. Его можно снова разделить с помощью
bot.services.backup_parts.split_backup: части одного ZIP имеют одинаковые имена и SHA-256.
Не соединяйте части разных архивов. При повторном запуске создания бэкапа получится новый
ZIP, и нужны все его части с соответствующим manifest.
Compose snapshot по умолчанию исключает каталоги plugin-store и themes, а также
настроенные пути хранилищ тем и плагинов внутри compose-папки. Выбранные версии установленных
плагинов и доверенные ключи издателей сохраняются отдельно в config/plugin-store,
установленные темы и их версии для отката — в config/themes. Удалённые темы и плагины,
временные импорты и осиротевшие пакеты в новый архив не попадают. Отключённые, но не удалённые
плагины сохраняются. Остальной data не исключается:
изображения сообщений, логотипы и другая пользовательская файловая конфигурация остаются
в бэкапе. Старые ZIP не уменьшаются автоматически. Для сохранения истории пакетов ради
операционных откатов используйте отдельное хранилище.
Настройка
Заголовок раздела «Настройка»Основные параметры доступны в админке: Система -> Настройки -> Бэкапы.
Минимальный .env, если LOG_CHAT_ID уже задан и подходит для бэкапов:
Если бэкапы нужно отправлять в отдельный чат или topic/thread, добавьте только нужные переменные:
Остальные backup-переменные обычно не нужны в .env: BACKUP_INTERVAL_SECONDS=3600 запускает бэкапы ровно на границе часа 12:00, 13:00 и т.д.; BACKUP_LOCAL_RETENTION=100 хранит 100 последних ZIP-архивов; BACKUP_COMPOSE_ENABLED=True, COMPOSE_BACKUP_SOURCE=. и COMPOSE_RESTORE_MODE=rw уже совпадают со стандартным compose-сценарием.
BACKUP_CHAT_ID задает чат Telegram для отправки архивов. Если он пустой, используется LOG_CHAT_ID. Для topic/thread можно указать BACKUP_THREAD_ID; если он пустой, используется LOG_THREAD_ID.
Каждый архив содержит manifest.json с SHA-256 и размером каждого файла. Это позволяет проверить, что архив не поврежден и его содержимое не отличается от manifest.
Архив не привязан к текущему инстансу, BOT_TOKEN или серверу. Его можно загрузить и восстановить на другом сервере, если формат архива поддерживается и проверки целостности проходят.
Mount compose-папки
Заголовок раздела «Mount compose-папки»В стандартных compose-файлах есть два mount:
worker:${COMPOSE_BACKUP_SOURCE:-.}:/app/compose-source:ro- только читает папку для создания snapshot;backend:${COMPOSE_BACKUP_SOURCE:-.}:/app/compose-source:${COMPOSE_RESTORE_MODE:-rw}- читает список архивов и может восстановить compose-папку из админки.
COMPOSE_BACKUP_SOURCE=. означает папку рядом с текущим docker-compose.yml. Если compose лежит в другом месте, укажите абсолютный host-путь.
Ручное создание бэкапа из админки выполняется в backend-контейнере, а автоматический backup по расписанию - в worker-контейнере. Оба контейнера должны видеть /app/compose-source. Если ручной backup содержит compose-папку, а автоматический нет, пересоздайте worker после обновления compose:
Контейнеры migrate, backend и worker также должны видеть один и тот же источник данных в
/app/data. Админка читает текущий compose-файл и показывает ошибку конфигурации
data_mount_mismatch, если source volume или bind mount у этих сервисов различается либо у одного
из них отсутствует. До исправления предупреждения не меняйте тарифы, переводы и другие файловые
настройки: разные процессы могут читать разные версии данных.
Если нужно запретить восстановление compose-файлов из контейнера, задайте:
В этом режиме восстановление БД останется доступным, а восстановление compose-папки вернет понятную ошибку о недоступной записи.
Восстановление из админки
Заголовок раздела «Восстановление из админки»Откройте Система -> Бэкапы. В разделе можно:
- создать новый backup вручную, не дожидаясь следующего запуска по расписанию;
- выбрать архив, уже лежащий в
data/backups; - скачать выбранный архив для переноса на другой сервер;
- загрузить ZIP-архив вручную;
- отметить, что восстанавливать:
БДилиcompose-папка(операции выполняются раздельно); - ввести точное имя выбранного архива и запустить восстановление после подтверждения.
Ручное создание использует тот же механизм, что и расписание: делает pg_dump, добавляет compose snapshot, сохраняет ZIP в BACKUP_DIR, отправляет архив в Telegram и применяет локальный retention. На время ручного запуска используется общий Redis lock, поэтому он не пересечется с плановым backup или restore.
При выборе БД админка ставит задачу восстановления и показывает её состояние. Управляющие
процессы останавливают backend и worker, проверяют архив и подписи плагинов, восстанавливают
данные в отдельную БД, переключают БД и автоматически запускают процессы снова. Во время
операции API может временно отвечать ошибкой; страница продолжит проверять статус. При ошибке
до переключения исходная БД и файлы плагинов сохраняются, приложение запускается снова.
Если переключение завершилось неопределённо, процессы остаются остановленными до ручной проверки
журнала. Для этой процедуры backend и worker должны использовать общий BACKUP_DIR и стандартный
plugin_launcher.py из образа Core. Внешние клиенты БД необходимо остановить отдельно.
Если адрес PANEL_API_URL на новом сервере отличается от записанного в архиве, админка
показывает оба адреса и требует выбрать способ обработки привязок пользователей. Можно сохранить
старые привязки для ручной проверки или подтвердить перепроверку на текущей панели. Во втором
случае при восстановлении сбрасываются только отметки о старом адресе панели; сохранённые ID
пользователей остаются в БД, а перед следующим подключением MiniShop сверяет личность аккаунта
с данными панели. Для старых архивов прежний адрес может быть неизвестен. Подтверждайте
перепроверку, только если целевая панель действительно содержит нужные аккаунты.
Ручные ограничения HWID, дополнительные устройства и другие настройки подписок хранятся в БД
и входят в pg_dump. Состояние внешней Remnawave-панели в ZIP не входит: если переносится сама
панель, её данные нужно перенести отдельно и затем сверить привязки и лимиты.
БД и compose-файлы восстанавливаются раздельно: конфигурация исходного сервера может содержать
другие домены, секреты, порты и пути volume. Возврат compose-папки не применяет изменённые
настройки к уже запущенным контейнерам; после проверки файлов требуется обновить контейнеры.
Для старых архивов без config/plugin-store/ установите нужные плагины на целевом сервере
до восстановления БД либо создайте новый архив на обновлённом исходном сервере.
Compose-файлы восстанавливаются поверх текущей папки. Перед заменой backend создает pre-restore snapshot текущего compose-каталога рядом с остальными архивами:
После восстановления compose-папки перезапустите нужные сервисы, чтобы изменения docker-compose.yml, .env, Caddyfile/Angie/Nginx-конфигов и других файлов реально применились:
Если менялись proxy-конфиги, перезапустите соответствующий сервис (caddy, angie, nginx, newt).
Проверка архива перед восстановлением
Заголовок раздела «Проверка архива перед восстановлением»Backend валидирует архив до восстановления:
- файл должен быть валидным ZIP;
manifest.jsonдолжен принадлежатьremnawave-minishopи иметь поддерживаемую версию формата;- SHA-256 и размер каждого файла должны совпадать с manifest;
- выбранный server-side файл должен лежать внутри
BACKUP_DIR, путь вида../backup.zipотклоняется; - пути внутри ZIP не могут быть абсолютными, содержать
..,\, пустые сегменты или дубли; - архивы с подозрительно большим числом файлов, размером или zip-bomb compression ratio отклоняются;
- для восстановления БД нужен
database/*.dumpилиdatabase/*.backup; - для восстановления compose нужны файлы внутри
compose/; - compose restore стартует только если целевая папка существует и доступна на запись;
- backup/restore защищены одним Redis lock, чтобы две операции не выполнялись одновременно.
- восстановление требует точного повторного ввода имени выбранного архива;
- БД восстанавливается только в пустую отдельную базу; текущая база сохраняется до и после переключения.
Это защищает от случайной загрузки мусорного файла, zip-slip-архивов и поврежденных ZIP. Проверка специально не привязана к секретам инстанса, чтобы архивы можно было использовать для переноса между серверами. Это не проверка доверенного источника: не восстанавливайте архивы, происхождение которых вы не контролируете.
Перенос на другой сервер
Заголовок раздела «Перенос на другой сервер»Для переноса БД между инстансами:
- Создайте backup на старом сервере и скачайте ZIP в админке или возьмите ZIP из Telegram.
- На новом сервере загрузите архив в Система -> Бэкапы.
- Выберите БД, введите точное имя архива и запустите восстановление. Админка покажет ход операции; после завершения процессы перезапустятся автоматически.
- Проверьте плагины, темы и healthcheck. Предыдущая БД и файлы плагинов остаются для отката.
- Если нужны
.envи proxy-конфиги, восстановите compose отдельно, проверьте настройки целевого сервера и обновите контейнеры.
Если переносите compose-папку, проверьте домены, токены, WEBHOOK_BASE_URL,
SUBSCRIPTION_MINI_APP_URL, bind-порты и volume/mount пути: на новом сервере они могут отличаться.
Не восстанавливайте старый compose автоматически вместе с БД: он может запустить старые образы
поверх уже обновлённой схемы.
Резервный вариант: восстановление БД командой обслуживания
Заголовок раздела «Резервный вариант: восстановление БД командой обслуживания»Используйте образы целевой версии и скрипт из того же релиза. Архив должен находиться в
BACKUP_DIR общего volume. Запускайте из каталога установки на Docker Compose хосте (нужны
Bash и flock). Если установка без Git checkout, сохраните scripts/restore-backup.sh из целевого
релиза в каталог установки под тем же путём.
Порядок действий:
- Проверить ZIP и контрольные суммы до остановки приложения.
- Остановить
backend,workerиmigrate. Убедиться, что к текущей БД больше нет подключений. - Запретить новые подключения к текущей БД и создать отдельную пустую БД из
template0. - Проверить дамп через
pg_restore --listи восстановить его с--single-transaction --exit-on-error --no-owner --no-privileges, без--cleanи без наложения на текущую схему. - Сверить миграционную историю с manifest, если она есть. Отклонить неизвестные миграции (включая миграции отсутствующих плагинов); downgrade не поддерживается. Выполнить только отсутствующие миграции Core и установленных плагинов.
- Проверить наличие таблиц и колонок моделей, индексы и ограничения PostgreSQL; нормализовать serial sequences. Данные восстанавливаются до создания новых таблиц и применения миграций.
- Подготовить каталог тарифов из архива; при его отсутствии сохранить текущий. Атомарно
переименовать обе БД в одной транзакции. Прежняя остаётся под
minishop_previous_<id>с запрещёнными подключениями. Обновлённая получает прежнее имя подключения. - Только после успеха запустить backend/worker из настроенных образов и дождаться healthcheck.
Нужны права владельца БД и CREATEDB (стандартный compose-пользователь ими обладает), доступ
к служебной БД postgres и место для двух полных БД. Внешние клиенты и отдельные реплики
приложения тоже должны быть остановлены. PgBouncer и нестандартные роли/права требуют отдельной
проверки конфигурации. Успех не означает проверку семантики всех данных сторонних плагинов.
При ошибке сервисы остаются остановленными. До переключения исходная БД не меняется;
неудачный кандидат сохраняется для диагностики. Команда пишет BACKUP_DIR/restore-<id>.json
с именами баз, состоянием операции и путями файлов. Прежний каталог тарифов сохраняется рядом.
При аварийном завершении процесса сверяйте журнал с pg_database: запись журнала и операции
PostgreSQL не образуют общую транзакцию. Не запускайте приложение, пока не проверены и БД,
и соответствующий ей каталог тарифов.
Для отката после успешного переключения остановите backend/worker/migrate, сохраните новую БД,
переименуйте её в свободное имя, а previous_database из журнала — в исходное имя. Делайте оба
переименования одной транзакцией из служебной БД postgres, без активных подключений;
разрешите подключения к возвращённой БД (ALTER DATABASE ... ALLOW_CONNECTIONS true).
Верните previous_tariffs (либо удалите каталог тарифов, если его прежде не было), выберите
соответствующие исходной БД образы и только затем запустите сервисы. Старую и неудачную БД
удаляйте вручную только после проверки результата — скрипт их не удаляет.
Переменные
Заголовок раздела «Переменные»Полный справочник лежит в переменных окружения. Основные ключи:
| Переменная | Назначение |
|---|---|
BACKUP_ENABLED |
Включает периодические бэкапы. |
BACKUP_CHAT_ID / BACKUP_THREAD_ID |
Куда отправлять архивы в Telegram. |
BACKUP_INTERVAL_SECONDS |
Периодичность, по умолчанию 3600. |
BACKUP_LOCAL_RETENTION |
Сколько последних архивов хранить на сервере. |
BACKUP_DIR |
Каталог ZIP-архивов. |
BACKUP_COMPOSE_ENABLED |
Добавлять compose snapshot. |
COMPOSE_BACKUP_SOURCE |
Host-путь compose-папки для mount в контейнеры. |
COMPOSE_RESTORE_MODE |
rw для восстановления compose из админки, ro для запрета записи. |
BACKUP_PG_DUMP_PATH / BACKUP_PG_RESTORE_PATH |
Пути к pg_dump и pg_restore внутри контейнеров. |
Пользовательские темы
Заголовок раздела «Пользовательские темы»Резервная копия включает WEBAPP_THEMES_DIR в config/themes/: каталог установленных тем,
текущие версии пакетов и версии для отката, настройки владельца и ручные темы.
Удалённые темы, осиротевшие пакеты, временные импорты и служебные снимки исключены.
Файлы удалённых тем могут временно оставаться на сервере для уже открытых страниц;
в новые бэкапы они не включаются. При восстановлении базы
темы восстанавливаются после проверки пакетов; старые архивы без этого раздела не меняют темы.
Подробнее: хранение тем.