Резервное копирование с Borg + UI

Домашний сервер
  •  20 апр 2026
  •  135

Мы уже подняли VMware, пара поднимать первые виртуальные машины. И начать я предлагаю с бекапа, иначе мы его никогда не поднимем :)

Как ставить Debian 13, я рассказывать не буду, если будет время, сделаю отдельную страничку в WiKi. Сегодня пойдёт речь только о софте.

В качестве средства резервного копирования я предлагаю использовать Borg Backup. Это отличное Open Source решение с поддержкой работы по ssh, выполнению скриптов до и после бекапа, шифрования и много другого. Но это консольная утилита, графического интерфейса нет — что может стать ключевым недостатком для многих, включая меня. Я не хочу выполнять 33 команды, чтобы быстро увидеть сделаны бекапы или нет.

Но этот минус легко решается проектом Borg Web UI. А для таких ленивых, как я, — даже есть готовый докер образ ainullcode/borg-ui:latest. Именно его мы и будем использовать. Да, у него есть много проблем, особенно с безопасностью (ищите на Reddit), но для домашнего применения более чем подходит. Платная версия особого смысла не имеет; всё нам необходимое доступно в Community лицензии. Альтернативно можно использовать Borg Backup Server, но мне он показался более сложным.

Есть сообщения о проблемах безопасности в Borg-UI. Код писался с использованием ИИ. Для домашнего использования образ подходит, но не размещайте его в публичной сети без фаервола. Используйте VPN или SSH-туннель для доступа к веб-интерфейсу.

Любая установка начинается с обновления ОС:

apt update
apt dist-upgrade

Теперь установим Docker. Полная инструкция есть на сайте Docker, я же укажу её довольно кратко. Подключим ключи:

apt install ca-certificates curl
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc
chmod a+r /etc/apt/keyrings/docker.asc

Подключим репозиторий:

tee /etc/apt/sources.list.d/docker.sources <<EOF
Types: deb
URIs: https://download.docker.com/linux/debian
Suites: $(. /etc/os-release && echo "$VERSION_CODENAME")
Components: stable
Architectures: $(dpkg --print-architecture)
Signed-By: /etc/apt/keyrings/docker.asc
EOF

Обновим кэш и установим нужные нам пакеты:

apt update
apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

Теперь можем поставить Borg. В образе borg-ui он уже есть, поэтому наш docker-compose.yml будет очень простым. Создадим /opt/docker-compose.yml

services:

  borg-ui:
    image: ainullcode/borg-ui:latest
    container_name: borg-ui
    restart: unless-stopped
    ports:
      - "8081:8081"
    volumes:
      - /opt/borg_data:/data
      - /opt/borg_cache:/home/borg/.cache/borg
      - /opt/backups:/local/home:rw
    environment:
      - ENABLE_STARTUP_LICENSE_SYNC=false
      - ACTIVATION_SERVICE_URL=http://127.0.0.1:1/
      - TZ=Europe/Moscow
      - PUID=1000
      - PGID=1000
      - LOG_LEVEL=INFO
    cap_add:
      - SYS_ADMIN
    devices:
      - /dev/fuse
    security_opt:
      - apparmor:unconfined

ENABLE_STARTUP_LICENSE_SYNC и ACTIVATION_SERVICE_URL нужны, чтобы наш UI не пытался проверять лицензию, получать 60-дневнюю расширенную и т.д. Меня вполне устраивает тариф Community, но если Вы хотите попробовать или купить — уберите эти 2 параметра.

Теперь создадим все необходимые папки:

mkdir -p /opt/borg_data
mkdir -p /opt/borg_cache
mkdir -p /opt/backups

Обязательно меняем владельца папок:

chown -R 1000:1000 /opt/borg_data
chown -R 1000:1000 /opt/borg_cache
chown -R 1000:1000 /opt/backups

Конечно, хранить бекапы в папке /opt/backups идея плохая и в дальнейшем я переделаю это на внешнюю NFS, но это уже немного за пределами данной статьи.

Пробуем запустить:

cd /opt && docker compose up -d

Открываем панель администратора на порту 8081 и смотрим, что у нас получилось. При первом запуске Вам нужно будет авторизоваться под admin / admin123 и сменить пароль. Также нам предложат настроить вход по отпечатку, Face ID и прочему — это опционально. Я пропущу. Ещё нам предложат отправлять анонимные сведенья — это на Ваше усмотрение.

Первым делом нам необходимо сгенерировать ключи для работы с SSH. Перейдём на вкладку Remote Machines. Нажимаем кнопку Generate System SSH Key. В новом окне можем оставить ED25519 (но если Вам нужно бекапить старые устройства — выбирайте поддерживаемый ими алгоритм), нажимаем Generate Key.

Теперь можем подключить первый сервер. По кнопке Deploy to Server, указав параметры, логин и пароль — Borg может сам закинуть ключ SSH. Я предпочитаю сделать это руками, затем нажать Add Manual Connection, указать параметры сервер. Теперь у нас подключён доступ к серверу, с которого будет делать резервные копии. Кстати, при редактировании (не знаю, почему при добавлении сразу нельзя) можно указать отображаемое имя.

Отлично, теперь создадим репозиторий. По сути, это и есть задание на резервное копирование — что бекапить, куда и с какими параметрами. Переходим во вкладку Repositories, нажимаем Create Repository. Нам предложат указать имя (я называю по имени сайта или hostname VDS), далее указать, где будут храниться бекапы — у нас это папка /local/home/ и в ней нужно создать папку репозитория. На кладке Source нас просят указать, что будем бекапить — я буду сохранять папку своего сайта на Laravel, укажу Remote Client и путь /opt/web/sites/test.gorbushka.name, у вас он будет свой.

Security предлагает нам зашифровать репозиторий, но мне это не нужно. Config позволяет настроить сжатие, исключить определённые файлы и настроить скрипты (о них позже) — я всё это отключаю. Preview показывает нам сводку по создаваемому заданию. Сохраняем.

Проверим, что всё работает. Нажмём Backup Now, затем Start Backup. Нам покажут в online-режиме, как делается резервная копия, а затем статус — Completed. Если Вы получили ошибку — на этом этапе стоит разобраться, прежде чем идти дальше. Логи ошибки можно посмотреть, нажав на иконку глаза.

Отлично, но что сделал Borg? Перейдём во вкладку Archives. Наверху выберем наш репозиторий. У нас отобразится список созданных резервных копий с возможностью их восстановить, просмотреть и т.д., а также статистика по занимаемому месту.

Теперь вернёмся на вкладку Repository и выполним два важных действия. Нажмём логотип щита и выполним проверку репозитория. В новом окне нажмём Run Check. Теперь выполним сжатие. Это позволит сэкономить занимаемое место на HDD — нажмём символ коробки, затем в новом окне Compact. Теперь в репозитории отображается дата последней проверки и сжатия, а на главном экране всё горит зелёным — значит с нашим бекапом всё хорошо. Кстати, имейте в виду, что данные обновляются не сразу — так и у меня на скриншоте дата сжатия не обновилась.

Мы сделали бекап, проверили целостность репозитория и работу сжатия, но не будем мы это делать каждый раз руками? Правильно, перейдём в раздел Schedule и нажмём Create Backup Schedule — это позволит настроить резервное копирование по расписанию.

Укажем название расписания и укажем репозиторий для бекапа. На вкладке Schedule укажем, как часто запускать и какое имя давать архивам. Scripts позволит запускать скрипты перед и после бекапа (об этом позже) — просто включите Run repository-level scripts. Это запустит те скрипты, что указаны при создании репозитория. Maintenance позволит удалять старые архивы и выполнять сжатие после бекапа автоматически. Включаем. Review, как обычно, даёт нам ознакомиться с тем, что мы тут настроили. Нажимаем Create Schedule.

Ничего не забыли? А проверка? В Borg-UI проверка реализуется отдельным расписанием. Перейдём на вкладку Repository Checks и нажжём Add Check Schedule. Тут всё намного проще, указываем только время запуска. Ставьте время так, чтобы бекап точно уже закончился и репозиторий не был заблокирован другими операциями.

Давайте наконец поговорим о скриптах, что это и зачем нужно. В самом начале для примера я настроил резервную копию файлов сайта. Но ведь у сайта есть ещё и база данных, S3 хранилище и много чего ещё. Всё это тоже необходимо бекапить. А ещё на время резервного копирования нужно запретить изменения, сохраняя бекап консистентным. Для этой цели и нужны скрипты.

Предлагаю добавить 2 скрипта. Первый будет отключать сайт и делать дамп базы данных, а второй — этот дамп удалять и включать сайт обратно. Бекап занимает около 1 минуты. Я готов пожертвовать доступностью сайта на это время, а позже реализую режим только чтения и отложенной записью в базу. Тут важно добавить #!/bin/bash, чтобы скрипт запустился в Bash, а set -euo pipefail заставит остановиться при ошибке в любой части скрипта и вернуть не-нулевой код (ошибку). Сами скрипты объяснять не буду — это не тема статьи, но смысл я уже описал. Конечно, для промышленного решения всё будет намного сложнее.

Скрипт до:

#!/bin/bash

set -euo pipefail
 
ssh "-o StrictHostKeyChecking=accept-new" "root@192.168.2.112" \
  "cd /opt && docker compose exec -T php sh -c 'cd test.gorbushka.name && php artisan down --retry=60'"

ssh "-o StrictHostKeyChecking=accept-new" "root@192.168.2.112" \
  "cd /opt && docker exec postgres pg_dump -U postgres -d gorbushka --format=custom --compress=9 > gorbushka.dump"

Скрипт после:

#!/bin/bash

set -euo pipefail

ssh "-o StrictHostKeyChecking=accept-new" "root@192.168.2.112" \
  "rm /opt/gorbushka.dump"

ssh "-o StrictHostKeyChecking=accept-new" "root@192.168.2.112" \
  "cd /opt && docker compose exec -T php sh -c 'cd test.gorbushka.name && php artisan up'"

Во вкладке Management откроем вкладку Scripts, нажмём New Script. Поочерёдно добавим два скрипта, первый как before, а второй — after.

Теперь необходимо добавить наши скрипты в план резервной копии. Перейдём на вкладку Repositories, отредактируем наш репозиторий. Нас интересует вкладка Source — добавим в бекап файл /opt/gorbushka.dump. Теперь вкладка Config — добавим внизу наши 2 скрипта, как показано на скриншоте ниже. Сохраним изменения в репозитории. При следующем запуске скрипт отключит сайт, сделает дамп базы данных, а Borg его заберёт. После бекапа сайт включится, а дамп удалится.

Конечно, это не полноценное резервное копирование для PostgreSQL и я бы советовал Вам использовать pgBackRest или pg_probackup с копированием WAL-архивов, но в рамках этой статьи пойдёт и такое.

Ну и оставлять резервные копии без присмотра идея совсем плохая. Давайте настроим оповещения. Вкладка PersonalNotifications. Для примера добавлю Discord, нажимаем New Service, указываем название Discord, в качестве URL указываем WebHook (он создаётся в настройках канала в Discord). Обязательно укажите что-нибудь в поле Title Prefix, иначе работать не будет — я укажу :bell: — смайлик колокольчика. Расставляем галочки как нам нравится — я ставлю все. Теперь мы будем получать уведомления в Discord по нашим резервным копиям.

Да, в теории Borg-UI поддерживает специальные URL, типа discord://webhook_id/webhook_token или tgram://bot_token/chat_id, но у меня они не заработали.

И последнее на сегодня — а как сделать резервную копию самого Borg и Borg-UI, ведь потеряем мы виртуализацию — репозитории будут бесполезны без специального софта. Первое, что нам нужно сделать, это перейти на вкладку ManagementExport/Import и выгрузить все настройки. Теперь идём на ssh: мы должны сохранить 2 папки: /opt/backups/ (содержит наши репозитории) и /opt/borg_data/ssh_keys/ — это ключи SSH, чтобы заново не раскидывать по хостам.

Насколько я понимаю, /opt/backups/ нужно хранить на внешнем отказоустойчивом хранилище, например, NAS, а вот остальное постоянно скачивать не требуется (если вы не меняете настройки), достаточно сохранить после каждой правки настроек. Неудобно, согласен. Разработчику об этом уже сказано, ждём улучшений.

Предположим, что сервер всё же умер. Установим чистую Borg-UI, подложим нашу папку /opt/backups/, ключи положим в папку /opt/borg_data/. Зайдём в интерфейс и импортируем ключи из папки /data (да, Docker монтирует /opt/borg_data/ хоста в /data контейнера).

К сожалению, подключённые сервера придётся добавлять также вручную. Ключи на них уже есть, поэтому используем ручное добавление.

Осталось импортировать настройки и Borg восстановлен. Можно восстанавливать резервные копии остальной инфраструктуры.

Статья получилась огромной, но, надеюсь, подробной. Резервные копии действительно крайне важная тема, поэтому ей уделено столько времени.

Комментарии (0)

Пока нет комментариев. Будьте первым!

Добавить комментарий

Войдите, чтобы оставлять комментарии.