Files
backup-master/docs/DESIGN.md
T
mrleo1nidandClaude Opus 5.5 1d44d067e9 backup-master: сервер бэкапов, агент и восстановление VPS
Один бинарник backupctl:
- server: API для агентов и restore, веб-морда (один админ), SQLite,
  ретеншн GFS, heavy-части, уведомления ntfy, раздача agent.sh/restore.sh;
- backup/plan: сбор по каталогу категорий (files/systemd/xui/compose),
  горячие дампы Postgres/Mongo/MySQL, снимок x-ui.db, docker-тома,
  digest образов, проверка crontab, потоковая отправка tar.zst;
- restore: провижининг на основе vps_installer с теми же версиями пакетов,
  recipes 3x-ui/nebula/sing-box нужных версий, восстановление compose
  с заливкой дампов и закреплением образов по digest.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 21:52:40 +03:00

71 lines
6.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Устройство backup-master
## Компоненты
```
Старый сервер Сервер бэкапов Новый сервер
backupctl backup ──PUT части──► backupctl server ◄── backupctl restore
(systemd timer) SQLite + файлы, веб-морда provision.sh → recipes → распаковка → сервисы
ретеншн, ntfy
```
| Пакет | Назначение |
|---|---|
| `internal/manifest` | формат манифеста бэкапа (общий для всех) |
| `internal/catalog` | категории бэкапа: встроенный `default.yaml` + переопределения клиента |
| `internal/archive` | tar (PAX) + zstd: запись, распаковка, исключения, владельцы по имени |
| `internal/api` | протокол и HTTP-клиент |
| `internal/agent` | сбор: files / systemd / xui / compose, дампы, проверка crontab, отправка |
| `internal/restore` | восстановление: provision.sh, recipes бинарников, compose, порядок категорий |
| `internal/server` | API, веб-морда, ретеншн, уведомления |
## Формат архива
Каждая часть — `tar.zst`. В main первой записью идёт `manifest.json`. Пути внутри архива:
- `<cat>/files/<абсолютный путь>` — восстанавливается в `/`;
- `<cat>/dumps/<файл>` — дампы БД и снимок x-ui.db;
- `<cat>/volumes/<том>/…` — именованные docker-тома;
- `<cat>/bin/<абсолютный путь>` — fallback-копии бинарников.
Heavy-часть называется именем категории и устроена так же. Main без неё самодостаточен.
## Протокол
| Метод | Токен | Назначение |
|---|---|---|
| `GET /api/v1/agent/config` | агент | домен, переопределения каталога, пора ли слать heavy |
| `POST /api/v1/backups` | агент | манифест → id |
| `PUT /api/v1/backups/{id}/parts/{name}` | агент | потоковая загрузка части |
| `POST /api/v1/backups/{id}/complete` | агент | sha256/размеры частей + предупреждения архивации |
| `POST /api/v1/backups/{id}/fail` | агент | ошибка |
| `GET /api/v1/restore/manifest[?backup=]` | restore | манифест и доступные части |
| `GET /api/v1/restore/{id}/parts/{name}` | restore | скачивание (Range — докачка) |
Агентский токен даёт только запись: если клиента взломают, злоумышленник не сможет прочитать или удалить его историю. Restore-токен выпускается в морде на 24 часа и даёт только чтение бэкапов одного клиента. В БД хранятся только sha256 токенов.
Агент архивирует часть прямо в тело PUT (`io.Pipe`), временный архив на диске не создаётся. Дампы БД снимаются **до** архивации. Поэтому в Stoat порядок «сначала mongodump, потом файлы MinIO» соблюдается сам собой: файлы, загруженные во время бэкапа, станут лишними объектами без ссылок, но ссылок на отсутствующие файлы не появится.
## Compose
- Проекты берутся из `docker compose ls -a`, к ним добавляются явные `dir` из каталога. Сервисы, bind-mounts и тома — из `docker compose config --format json`.
- БД определяются по образу. Если контейнер запущен, делается дамп через `docker exec`: учётные данные берутся из окружения контейнера, а каталог данных исключается. Если остановлен — каталог данных копируется как есть (он консистентен).
- Данные `rabbitmq` и сервисов из `skip_services` не бэкапятся.
- Записываются digest запущенных образов. При восстановлении создаётся `compose.restore.yml` с `image: repo@sha256:…`, потому что `latest` на новом сервере дал бы другую Mongo/MinIO.
- Отсутствующие external-сети создаются пустыми. Так stoat-mbot поднимается без psiphon.
- Порядок восстановления: `pull` → `build` → `create` → для каждой БД `up -d <db>` → ожидание TCP-готовности → заливка дампа → `up -d`.
## Версии
| Что | Как записывается | Как восстанавливается |
|---|---|---|
| apt-пакеты (caddy, telegraf, docker-ce, docker-compose-plugin) | `dpkg-query` | `provision.sh` ставит `pkg=version`, если версия есть в репозитории |
| 3x-ui, nebula, sing-box-extended | `version_cmd` | recipes в `internal/restore/recipes.go`: release-архивы нужного тега; при неудаче — копия из `bin/` |
| образы compose | digest | `compose.restore.yml` |
## Расширение
- Новая категория — запись в `default.yaml` или в YAML клиента в морде.
- Новый способ установки бинарника — функция в `recipes`, имя указывается в поле `install` категории.
- Новый тип БД в compose — `dbKind`/`dumpCmds` в `internal/agent/compose.go` и `dbReady`/`dbRestore` в `internal/restore/compose.go`.