Перейти до змісту

Резервне копіювання та відновлення

Три незалежні шляхи захищають вашу інсталяцію: on-demand ZIP з UI, scheduled job на локальний диск, що тримає N останніх знімків, і Git-пуш, що архівує профілі принтерів у GitHub або GitLab.


Що всередині Backup ZIP

On-demand і scheduled локальні бекапи продукують ту саму структуру ZIP. Записи верхнього рівня:

Запис Вміст
bamdude.db Повна база у переносимому форматі SQLite разом з історією міграцій. Відновлюється на SQLite та PostgreSQL.
archive/ Файли друку й мініатюри, тека на прогін, плюс стейджинг завантаження 3MF.
library/ Сховище менеджера файлів: файли, мініатюри, обкладинки MakerWorld.
virtual_printer/ Робочі файли віртуальних принтерів.
queue-sources/ Перевірені незмінні копії, якими володіють готові завдання черги. ZIP містить рівно файли, названі його знімком БД; незавершені файли staging/ виключені.
plate_calibration/ Еталонні кадри перевірки столу.
icons/ Власні іконки.
projects/ Вкладення замовлень.
products/ Вкладення виробів.
certs/ TLS-сертифікати та ключі віртуальних принтерів.
.mfa_encryption_key Ключ шифрування, якщо на вихідній інсталяції він зберігається у файлі.
zigbee/zigbee.db База драйвера Zigbee зі станом мережі, якщо вона існує.
.install_id Наявний анонімний ідентифікатор телеметрії.
backup-manifest.json Розміри файлів, SHA-256 та повний перелік каталогів, включно з порожніми.

ZIP містить конфіденційні дані БД та файли ключів. Фільтрація відповідей API не видаляє секрети з резервної копії бази. Зберігайте її приватно. Якщо ключ шифрування задано лише через MFA_ENCRYPTION_KEY, налаштуйте той самий ключ на цільовій інсталяції: ключ лише зі змінної середовища не додається до ZIP.

Експорт PostgreSQL читає один узгоджений знімок БД і зберігає типи колонок, значення за замовчуванням, обмеження, індекси та історію міграцій. Пошук архівів перебудовується для цільового бекенда. Бекап SQLite включає підтверджені записи, які ще містяться у WAL. Помилка експорту чи запису ZIP не підміняє наявний бекап недописаним файлом.

Знімок БД не заморожує супутні каталоги. Щоб отримати повну копію файлів, призупиніть завантаження, видалення та інші зміни файлів на час бекапу. Журнали, робочі кеші, тимчасові файли й сам застосунок не включаються. Недоступний файл, виявлена зміна джерела чи помилка копіювання зупиняє бекап: успіху з пропущеними файлами немає. Це стосується й наявної, але недоступної бази Zigbee. В обох напрямках використовуються налаштовані шляхи архівів та еталонів столу. Символічні посилання, Windows junctions і спеціальні файли відхиляються, а не обходяться.


Ручний бекап

  1. Налаштування → Система → Backup & Restore
  2. Натисніть Create Backup
  3. Браузер качає bamdude-backup-YYYYMMDD-HHMMSS.zip

ZIP стримиться з тимчасового файлу, а не буферизується в пам'яті, тож multi-gigabyte бекапи не OOM-ять процес. Тимчасовий файл видаляється автоматично, як тільки response завершується.

API: GET /api/v1/settings/backup (потрібно settings:backup).


Заплановані локальні бекапи

Налаштовуються в Налаштування → Система → Local Backup Schedule. Шедулер тікає раз на хвилину і запускає due-jobs у той самий ZIP-builder, що використовує ручна кнопка, потім обрізає старіші бекапи понад retention limit.

Налаштування За замовчуванням Примітки
local_backup_enabled false Master switch.
local_backup_schedule daily hourly, daily або weekly.
local_backup_time 03:00 HH:MM для daily/weekly запусків (server-local time). Hourly це поле ігнорує.
local_backup_retention 5 Тримати N останніх бекапів; старіші автоматично обрізаються. Діапазон 1–100.
local_backup_path порожньо Output-директорія. Порожньо = data/backups/.

Сторінка налаштувань показує last-run timestamp + outcome (success / failed), наступний запланований запуск і список наявних retention-бекапів з розмірами файлів. Ручні запуски "Create Backup" зберігаються в тій самій директорії і враховуються в retention.

Старі назви файлів бекапів BamDude залишаються підтримуваними. Це не є способом міграції з окремого застосунку Bambuddy.

Коли тека виводу недоступна для запису

BamDude перевіряє теку реальним записом у момент збереження шляху і при відкритті картки бекапів, тож непридатний шлях виявляється одразу, а не о 03:00 протягом тижня. Картка називає причину і дає команду для виправлення з уже підставленим вашим шляхом.

Найчастіше людей ловить systemd-пісочниця. Юніт служби постачається з ProtectSystem=strict, який монтує все поза ReadWritePaths=<install> <data> <logs> лише для читання всередині власного mount-namespace служби. NAS-шара, яку ви змонтували самі й у яку пишете зі своєї оболонки, до цих трьох не належить, тож запис падає з EROFS («Read-only file system») — що виглядає як проблема прав, але нею не є. На читання це не впливає, тож UI спокійно показує наявні копії з шари, не маючи змоги записати нову.

Надайте службі доступ через drop-in — він до того ж переживає перевстановлення:

sudo systemctl edit bamdude
[Service]
ReadWritePaths=/mnt/your-nas-share
sudo systemctl restart bamdude

Перевстановлення робить резервну копію старого юніта як bamdude.service.bak-<timestamp> і переносить додаткові ReadWritePaths далі, тож доданий вручну виняток більше не зникає при наступному оновленні.

У Docker збій тихіший: хостовий шлях, який ніколи не був bind-mount'нутий, усе одно доступний для запису — запис потрапляє в ефемерний шар контейнера і зникає при наступному docker compose up. BamDude порівнює пристрій теки з кореневим і попереджає, показуючи compose-сніпет, який монтує її правильно.


Git-бекап (профілі в GitHub / GitLab)

Окремий від ZIP-флоу. Налаштування → Система → Git Backup пушить вибрані дані профілів принтерів у GitHub або GitLab репозиторій — корисно для off-site синку профілів, координації multi-host ферми і PR-based історії змін у налаштуваннях принтера.

Конфігурація

Налаштування Примітки
Provider github, gitlab, gitea або forgejo.
Repository URL Повний clone URL (HTTPS-форма).
Access Token Personal Access Token. Зберігається зашифрованим at rest.
Гілка Цільова гілка (за замовчуванням main).
API base URL Тільки для self-hosted GitLab.
Schedule hourly / daily / weekly або off.

Покрокові гайди по провайдерах

  1. Створи GitHub-репозиторій (private підходить).
  2. Згенеруй Personal Access Token (PAT):
    • Зайди в GitHub Personal Access Tokens.
    • Натисни Generate new token → Generate new token (classic).
    • Обери expiration (No expiration рекомендується для unattended scheduled-бекапів).
    • У Select scopes відмітьте repo (потрібно для репо-доступу і коммітів).
  3. Налаштуй у BamDude:
    • Settings → Backup & Restore → Git Backup.
    • Provider: github.
    • Repository URL: наприклад https://github.com/username/bamdude-backup.
    • Введи PAT.
    • Натисни Test Connection.

Fine-grained tokens

Замість classic токенів можна fine-grained. Дай Read access to Metadata — Read and Write access to code додасться автоматично при створенні.

  1. Створи GitLab-репозиторій (private OK).
  2. Згенеруй PAT:
    • Зайди в GitLab Personal Access Tokens.
    • Натисни Add new token (Legacy / classic).
    • У scopes відмітьте api (потрібно для репо-доступу і коммітів).
  3. Налаштуй у BamDude:
    • Provider: gitlab.
    • Для self-hosted GitLab заповни API base URL.
    • Repository URL: наприклад https://gitlab.com/username/bamdude-backup.
    • Введи PAT.
    • Натисни Test Connection.

Project Access Tokens

Project Access Tokens теж працюють — дай scope api і write_repository, інакше комміти впадуть з access errors.

  1. Створи репо (private OK).
  2. Згенеруй PAT:
    • Settings → Applications у профілі Gitea.
    • Під Access Tokens дай ім'я.
    • Scope All (public, private, and limited).
    • У repository permissions постав Read and write.
    • Натисни Generate token.
  3. Налаштуй у BamDude:
    • Provider: gitea.
    • Repository URL: наприклад https://gitea.example.com/username/bamdude-backup (URL-валідатор приймає http:// теж — для self-hosted локальних інстансів на тій же формі).
    • Вкажи правильну Branch (main, master, тощо).
    • Введи PAT.
    • Натисни Test Connection.

Інстанси під префіксом шляху

Якщо твоя Gitea живе під ROOT_URL-префіксом, а не в корені сервера — https://твій-сервер/gitea — встав адресу репозиторію рівно так, як її показує браузер: https://твій-сервер/gitea/username/bamdude-backup. Останні два сегменти читаються як owner і repository, усе перед ними зберігається, тож API адресується за https://твій-сервер/gitea/api/v1. Префікс може бути будь-якої глибини. Кореневі інстанси працюють як раніше.

Кроки шляху . та .. відхиляються — вони вказали б бекап туди, куди ти не показував.

Розбіжності API Gitea від GitHub (обробляються внутрішньо)

GiteaBackend BamDude перекриває три GitHub-несумісні форми відповідей, які Gitea ввела з часом: list-shape GET /git/refs/heads/{branch} (один матч все одно повертає масив), refusal Git Data API на пустий репо (кожен blob POST 404 поки немає коміта — bootstrap йде через Contents API в одній транзакції), і wrapped Commit schema у Gitea 1.24+ (commit.tree.sha замість плоского tree.sha GitHub'а). Все прозоро для оператора — згадано тут лише як референс для self-hosted деплоїв з зазначенням сумісних версій (1.18+ і 1.24+ перевірені).

  1. Створи репо (private OK).
  2. Згенеруй PAT:
    • Settings → Applications у профілі Forgejo.
    • Під Manage Access Tokens дай ім'я токена.
    • Натисни Generate Token.
  3. Налаштуй у BamDude:
    • Provider: forgejo.
    • Repository URL: наприклад https://forgejo.example.com/username/bamdude-backup (плоска http:// теж приймається для локальних інстансів на тій же формі).
    • Введи PAT.
    • Натисни Test Connection.

API-сумісний з Gitea

API Forgejo наразі /api/v1-сумісний з Gitea, і ForgejoBackend BamDude успадковує всю поведінку GiteaBackend — включно з обробкою префікса шляху, описаною вище під Gitea, тож https://твій-сервер/forge/username/bamdude-backup працює так само. Якщо два проєкти розійдуться у майбутніх релізах Forgejo, override-by-override патчі в forgejo.py з'являться тут.

Bambu Cloud login обов'язковий для K-profiles + Cloud profiles

Для бекапу Cloud profiles і K-profiles потрібен активний Bambu Cloud login. Авторизуйся через Profiles → Cloud Profiles перед тим, як планувати Git-бекап з цими категоріями — інакше відповідні директорії будуть пусті в репо.

Що пушиться

Перемикається незалежно. Дефолти налаштовані так, щоб "бекапити те, що більшості потрібно, шумне/велике лишити вимкненим":

Категорія Опис Дефолт
K-profiles Per-printer pressure-advance профілі (за серійниками). On
Cloud profiles Filament, printer, process профілі з Bambu Cloud. On
Spools Повний дамп інвентаря (ряди + usage history). On
Archives (метадані) Метадані історії друку — філамент, температури, час, вартість, енергія (без 3MF / без мініатюр). On
App settings Таблиця application settings (sensitive поля виключені). Off
Archives (3MF + мініатюри) Bulk 3MF + thumbnail-вміст — додає ~50–500 МБ репо на 100 друків. Off

Тільки змінені файли генерують комміти — no-op запуск пишеться як skipped.

:material-folder-tree: Структура репозиторію

Після успішного запуску репо має такий вигляд:

repo/
├── backup_metadata.json
├── kprofiles/
│   └── {serial_number}/
│       ├── 0.2.json
│       ├── 0.4.json
│       └── ...
├── cloud_profiles/
│   ├── filament.json
│   ├── printer.json
│   └── process.json
├── settings/
│   └── app_settings.json
├── spools/
│   ├── inventory.json
│   └── usage_history.json
└── archives/
    └── print_history.json

Плоска структура робить partial restore однозначним — можна витягнути лише kprofiles/{serial}/ для одного принтера або лише spools/inventory.json для відновлення інвентаря, не чіпаючи решти.

Панель статусу

Сторінка налаштувань показує live-статус:

  • Last backup — timestamp, статус (success / failed / skipped), commit SHA і повідомлення.
  • Next scheduled run — коли шедулер фаєрне далі.
  • Log table — історичні запуски з тригером (manual / scheduled), тривалістю і будь-яким error message.
  • Run Now — кнопка миттєвого пушу незалежно від розкладу.

Frequency пушу, content-чекбокси і креденшали редагуються наживо без рестарту BamDude.


Відновлення з Backup ZIP

  1. Збережіть бекап поточної інсталяції, якщо може знадобитися повернутися до неї. Використовуйте ту саму або новішу версію BamDude, ніж версія, яка створила бекап.
  2. У запущеному BamDude відкрийте Налаштування → Система → Restore та завантажте ZIP. Саме розміщення ZIP у каталозі даних не запускає відновлення автоматично.
  3. До зупинки фонових сервісів BamDude перевіряє шляхи ZIP, CRC, маніфест за його наявності, базу застосунку та включену базу Zigbee. Небезпечні записи, пошкоджені чи відсутні файли, відсутні основні таблиці та невідомі версії міграцій відхиляються до зміни робочих даних.
  4. Відновлення готує й перевіряє всі вхідні файли на цільових файлових системах. Старий вміст зберігається для відкату, потім замінюються файли та БД. Корені каталогів і Docker mount points залишаються на місці. Після заміни виконуються лише нові міграції; записані в бекапі не запускаються повторно.
  5. Перезапустіть BamDude після відновлення, потім перевірте принтери, пошук архівів, файли в менеджері та вхід в обліковий запис. Якщо відновлення впало після призупинення сервісів, перед поверненням до роботи також потрібен перезапуск.

Помилка підготовки чи заміни файлів перериває операцію до заміни БД. Якщо заміна БД не вдалася, відкочуються всі замінені каталоги, ключ MFA, ідентифікатор телеметрії та база Zigbee з її sidecar-файлами. Схема, рядки, лічильники ID та зовнішні ключі PostgreSQL, як і раніше, змінюються однією транзакцією БД. Перед заміною бази Zigbee драйвер зупиняється; невдала зупинка перериває відновлення.

Нові бекапи зберігають порожні каталоги: їх відновлення прибирає старий вміст у цих каталогах. Старі ZIP без маніфесту підтримуються; відсутній у старому ZIP каталог чи необов’язковий файл залишає ціль без змін. Ручний бекап, плановий бекап і відновлення не можуть виконуватись одночасно в одному процесі BamDude (другий API-запит отримує HTTP 409).

Потрібне місце для розпакованого ZIP у системному тимчасовому каталозі та для вхідних файлів поряд із наявними на кожному цільовому томі. Старий вміст зберігається до успішної заміни БД. Якщо блокування файла чи зовнішній запис перешкоджає також відкату, BamDude повертає помилку й залишає копії для відновлення в каталогах .bamdude-restore-*, названих у журналі сервера: збережіть їх для відновлення. Невдала очистка staging після успішного відновлення записується в журнал і не заважає користуватися відновленими файлами.

Виконуйте відновлення під час технічної перерви, без завантажень та інших змін файлів. Це заміна файлів із можливістю відкату, а не знімок операційної системи чи розподілена транзакція: вимкнення живлення, зовнішні записи й обрив зв’язку з БД під час commit можуть вимагати ручного відновлення. Помилка подальшої міграції залишає разом нову БД та відповідні їй файли.

API: POST /api/v1/settings/restore (multipart file=…, потрібно settings:restore).

Cross-backend restore

Portable SQLite-дамп означає, що ви можете:

  • Зробити бекап з SQLite інсталяції → відновити на PostgreSQL (loader мігрує рядки).
  • Зробити бекап з PostgreSQL інсталяції → відновити на SQLite (БД уже експортовано як SQLite).
  • Зробити бекап з PG → відновити на свіжий PG (loader реімпортує SQLite у PG).

Відновлення замінює дані цільової БД: бази не об’єднуються, конфліктні рядки не пропускаються мовчки. Невідповідність схеми під час експорту дає явну помилку замість втрати невідомих даних. Старі SQLite-бекапи BamDude імпортуються в PostgreSQL зі своєю схемою та своїм рівнем міграцій.


Bulk archive export

Backup ZIP вже включає файли з archive/. Щоб експортувати лише вибрані архіви друку без бази всієї інсталяції:

  1. Зайди в Archives.
  2. Натисни Export.
  3. У модалі експорту відмітьте Include 3MF files.
  4. Опційно звузьте по даті, принтеру або статусу.
  5. Завантаж результуючий ZIP.

Корисно для hand-off на іншу ферму, archival у cold storage або одноразової міграції без перетягування повної бази.


Ручний бекап SQLite / PostgreSQL

Якщо хочеш CLI / scripted-бекап поза UI BamDude — наприклад, для включення в системний бекап ширше або PostgreSQL-specific point-in-time recovery — йди прямо в DB-движок:

Спершу зупини BamDude для consistent-снімку, далі:

# Plain copy (найшвидше)
cp /path/to/bamdude.db bamdude_$(date +%Y%m%d).db

# SQL-дамп (portable між версіями)
sqlite3 /path/to/bamdude.db ".dump" > bamdude.sql

# Restore з SQL-дампа
sqlite3 new_bamdude.db < bamdude.sql

Підключайся через свій DATABASE_URL:

# Custom-format dump (рекомендую — підтримує parallel restore + selective restore)
pg_dump -Fc bamdude > bamdude.backup
# або з explicit DSN:
pg_dump -Fc "postgresql://user:pass@host:5432/bamdude" > bamdude.backup

# Restore (drop + recreate об'єктів при імпорті)
pg_restore -d bamdude bamdude.backup
# або з explicit DSN:
pg_restore --clean --if-exists \
    -d "postgresql://user:pass@host:5432/bamdude" bamdude.backup

Built-in бекап BamDude простіше

Сторінка Settings → Backup продукує portable-бекапи, що працюють і на SQLite, і на PostgreSQL. Ручний pg_dump потрібен лише коли хочеш PG-specific фічі типу point-in-time recovery, logical-replication snapshotting або інтеграцію з існуючим PG backup pipeline.

Зупини BamDude перед raw file copy

Прямий cp bamdude.db під час роботи BamDude може схопити inconsistent WAL-стан. Portable Settings → Backup безпечно це обробляє — ручний копіпейст потребує зупиненого процесу.


Сценарії відновлення

Три типові форми, що приймає recovery-flow:

Втрачена база

DB пошкоджена, видалена, не recoverable:

  1. Зупини BamDude.
  2. Видали пошкоджений bamdude.db (або drop PostgreSQL базу).
  3. Стартуй BamDude — він створить свіжу пусту DB при першому boot.
  4. Settings → System → Restore → завантаж останній backup ZIP.
  5. BamDude замінить пусту DB відновленою і запустить pending міграції.

Нова інсталяція

Переїзд на новий сервер / новий Docker-хост:

  1. Інсталюй BamDude на новому хості (Docker compose, bare metal, як заведено).
  2. Бутни раз, щоб data-директорія створилася і setup-gate висів на setup_required.
  3. Скопіюй backup ZIP на новий хост.
  4. Settings → System → Restore → завантаж ZIP — зауваж, що setup-gate whitelist'ить /restore-style flow коли ще нема адміна, але на практиці найпростіший шлях — завершити setup placeholder-адміном, потім restore (який замінить placeholder-а реальними юзерами).

Міграція даних

Міграція між DB-backend-ами, OS-хостами або переїзд Docker-volume-ів:

  1. Зніми бекап на старій інсталяції (Settings → Backup → Create Backup).
  2. Підніми BamDude на новому хості.
  3. Restore з backup ZIP — portable SQLite-шар BamDude автоматично транслює SQLite ↔ PostgreSQL (див. "Cross-backend restore" вище).
  4. Перевір: принтери реконнектяться, профілі на місці, архіви відкриваються. Тоді demolition старого хоста.

Орієнтири розміру бекапу

Грубе sizing, щоб планувати сховище:

Профіль Приблизний розмір Вміст
Малий < 50 МБ DB only — без архівів, без 3MF, без library-файлів.
Середній 100–500 МБ DB + метадані архівів + мініатюри (без 3MF).
Великий 1–50 ГБ DB + повний 3MF + мініатюри + library-файли + timelapse.

Якщо у тебе багато timelapse-відео — це "великий" профіль; періодичне чищення старих timelapse (або виключення archive/ з окремого full-data бекапу) — найпростіший шлях тримати ZIP керованим.


Best practices

  • Daily для prod — комбінуй Заплановані локальні бекапи з daily (наприклад, 03:00) і retention=7 для роллінг-тижня.
  • Off-site хоча б один — тримай один знімок не на BamDude-хості: NAS-share, хмарне сховище (Dropbox / Google Drive / S3 через rclone) або зовнішній USB, який ротуєш щотижня. Hardware loss б'є тебе тільки коли обидві копії на одному залізі.
  • Періодичний restore-drill — раз на кілька місяців бери backup ZIP і пробуй відновити на throwaway-інсталяції BamDude. Бекап, який ти ніколи не відновлював — бекап, що може не працювати.
  • Backup перед апгрейдом — протокол UPDATING.md рекомендує свіжий ручний бекап перед кожним minor-апгрейдом. Міграції ідемпотентні і one-shot, але автоматичного шляху downgrade немає.
  • Date-suffix у назвах ручних бекапів — коли робиш ручний бекап перед ризиковою зміною, назви по тригеру (bamdude-pre-0.5.0-upgrade.zip), щоб знайти потім.

Docker volume bind-mount приклад

Для Docker-користувачів — змонтуй output-директорію бекапу як volume, щоб бекапи переживали контейнер, а ідеально — на NAS-share для off-site.

Шлях фіксований — ручка це монтування

Бекапи завжди пишуться в backups/ усередині директорії даних. Змінної оточення, яка їх переносить, не існує: наводь volume на /app/data/backups, а з боку хоста монтуй що завгодно.

services:
  bamdude:
    image: ghcr.io/kainpl/bamdude:latest
    container_name: bamdude
    network_mode: host
    volumes:
      - bamdude_data:/app/data
      - bamdude_logs:/app/logs
      - ./backups:/app/data/backups          # local relative path
      # або
      - /mnt/nas/bamdude-backups:/app/data/backups   # NAS / network share
    environment:
      - TZ=Europe/Kyiv
    restart: unless-stopped

volumes:
  bamdude_data:
  bamdude_logs:

Або через docker run:

docker run -d \
  --network host \
  -v bamdude_data:/app/data \
  -v bamdude_logs:/app/logs \
  -v /mnt/nas/bamdude-backups:/app/data/backups \
  -e TZ=Europe/Kyiv \
  --name bamdude \
  --restart unless-stopped \
  ghcr.io/kainpl/bamdude:latest

NAS / Samba / NFS

Направ bind-mount на NAS-share, Samba-mount чи NFS-шлях для автоматичних off-site бекапів без додаткових скриптів. У парі з retention-rotation — hands-off off-site backup pipeline.


Поради

Off-site покриття

Скомбінуйте Заплановані локальні бекапи (повні дані, on-disk) з Git-бекапом (профілі, off-site) — локальний переживе software wipe, git — переживе hardware loss.

Бекап перед оновленням

UPDATING.md рекомендує свіжий ручний бекап перед кожним minor-апгрейдом. Міграції ідемпотентні і one-shot, але автоматичного шляху для downgrade немає.

Початково базується на документації Bambuddy.