REDZ RPM repository

Пакеты REDZ для AlmaLinux, RHEL, Rocky и Fedora 8/9/10, x86_64.

Сначала выберите свой случай.
Купили подписку на бэкапы? Вам нужны только три шага в разделе «Установка по подписке». Хранилище, ключи и пароль репозитория настраиваются сами.
Своё хранилище, настраиваете сами? Вам нужны десять шагов ниже.

1. Установка по подписке: 3 шага

Этот раздел — для тех, кто купил бэкапы как услугу. Всё, что в разделах ниже занимает десять шагов, здесь делает сервер подписки: он выделяет вам место в хранилище, придумывает пароль репозитория и раскладывает ключи. От вас — одна строка, выданная при покупке.

ЧтоКак выглядитОткуда взять
Лицензионный ключrz-c00042-s01:8f2c…письмо о покупке или личный кабинет

Больше ничего готовить не нужно: ни пароля хранилища, ни ssh-ключа, ни пароля репозитория.

Шаг 1. Подключить репозиторий и поставить агента

dnf install -y https://rpm.redz.tech/redz-release-latest.noarch.rpm
REDZ_Licence set rz-c00042-s01:8f2c…
dnf install -y redz-backup redz-borg

Тот же ключ открывает и репозиторий пакетов, и подписку — он один на сервер.

Шаг 2. Включить управляемый режим и забрать настройки

Создайте config.local ровно с одной строкой:

cd /redz/prog/backup
printf 'MANAGED=1\n' > config.local
chmod 600 config.local
REDZ_Backup enroll

Ожидаемый ответ:

создан ключ доступа к хранилищу: /redz/prog/backup/id_managed
настройки записаны: /redz/prog/backup/config.managed

Что произошло: агент создал на этом сервере свой ssh-ключ, отправил его открытую часть нам вместе с лицензией и получил обратно подписанный набор настроек — адрес хранилища, имя раздела хранения, пароль репозитория, сроки хранения. Всё это легло в config.managed.

Закрытая часть ключа никогда не покидает ваш сервер. Мы получаем только открытую — ту, что кладётся в хранилище, чтобы оно вас впустило.

Если ответ — место в хранилище ещё не выделено, значит оплата ещё не разнесена; подождите и повторите. Если лицензия уже активирована на другом-сервере — ключ выдаётся на один сервер, для второго нужен второй ключ.

Шаг 3. Проверить и включить по расписанию

REDZ_Backup doctor
REDZ_Backup selftest
systemctl enable --now redz-backup-db.timer redz-backup-files.timer redz-backup-maint.timer

В doctor должны быть строки ok managed: on и ok подписка активна. Если ключ доступа к хранилищу отмечен как проблема — подождите минуту и повторите: ключ раскладывается по хранилищу не мгновенно.

Что дальше происходит само

СобытиеЧто делает агент
Мы поменяли вам хранилище или разделподхватит сам при ближайшей сверке (не реже раза в 12 часов), от вас ничего не требуется
Наш сервер подписки недоступенбэкап всё равно делается — на последних полученных настройках. Мы не можем сломать ваш бэкап тем, что у нас упал сайт
Подписка закончиласьновые бэкапы не создаются, восстановление и просмотр архивов работают по-прежнему
Вы хотите что-то поменять у себявсё, что вы напишете в config.local, сильнее присланного нами: список сайтов, исключения, сроки. См. раздел «Справочник»
Пароль репозитория в управляемом режиме знаем и мы. Иначе восстановить за вас было бы технически невозможно. Обратная сторона названа прямо: сотрудник с доступом к нашей базе может прочитать содержимое ваших бэкапов, и каждое такое обращение пишется в журнал. Если это неприемлемо — берите режим со своим хранилищем из раздела ниже, тогда пароль не покидает вас, но и мы вам ничем не поможем, если вы его потеряете.

Свой пароль репозитория можно посмотреть в любой момент: grep REPO_PASSPHRASE /redz/prog/backup/config.managed. Сохраните его вне сервера — это ускорит восстановление, если наш сервис окажется недоступен в неудачный момент.

2. Что нужно приготовить до начала

Разделы 2–4 — для тех, у кого своё хранилище и кто настраивает всё сам. Если у вас подписка, вам достаточно раздела 1, а сюда можно не заходить.

Четыре вещи. Три из них выдаёт администратор репозитория, четвёртую вы придумываете сами.

ЧтоКак выглядитОткуда взять
Ключ доступа к репозиториюВАШ-ЛОГИН:ВАШ-ПАРОЛЬу администратора
Секрет уведомленийrz-server-2026-xxxxxxxxxxxxxxxxxxxxу администратора
Доступ к хранилищухост, пользователь, порт и пароль раздела храненияу администратора
Пароль репозитория бэкапов48 символов, сгенерируете на шаге 3придумываете сами

Дальше идут десять шагов подряд. Каждый показывает команду, ожидаемый ответ и точную строку, которую надо вписать. Ничего додумывать не нужно.

3. Установка с нуля: 10 шагов

Шаг 1. Подключить репозиторий

dnf install -y https://rpm.redz.tech/redz-release-latest.noarch.rpm

Ожидаемый ответ: Installed: redz-release-1.0-2.noarch

Шаг 2. Задать ключ доступа

Подставьте ключ, полученный от администратора:

REDZ_Licence set ВАШ-ЛОГИН:ВАШ-ПАРОЛЬ

Ожидаемый ответ — три строки ok:

ключ записан: /etc/redz/licence
  ok    ключ принят (el10/x86_64)
  ok    ключ подписи добавлен в базу rpm
  ok    метаданные загружены, ключ подписи принят dnf

Если увидели FAIL 401 — ключ не принят, значит ключ неверный или отозван. Дальше идти бессмысленно, запросите правильный.

Шаг 3. Установить агента

dnf install -y redz-backup redz-borg

Ожидаемый ответ: Installed: redz-backup-… redz-borg-… redz-filesystem-…

redz-borg на AlmaLinux 8 обязателен, на 9 и 10 желателен — ставьте везде, хуже не будет.

Шаг 4. Придумать пароль репозитория и сохранить его

Выполните:

openssl rand -hex 24

Ответ будет вроде такого:

7f3a91c4be05d2ea6c18470b9d3fa25e8c07b1449de6a03f

Немедленно скопируйте эту строку в менеджер паролей — 1Password, Bitwarden, KeePass, любой, лишь бы не на этом сервере. Запись сделайте такую:

Название:  REDZ_Backup — имя-вашего-сервера
Пароль:    7f3a91c4be05d2ea6c18470b9d3fa25e8c07b1449de6a03f
Заметка:   Пароль репозитория бэкапов. Без него архивы этого сервера
           нечитаемы навсегда, сброса нет. Восстановление: этот пароль
           + файл RESTORE.md рядом с репозиторием в хранилище.

И распечатайте на бумаге, положите туда же, где документы.

Это единственный пароль, потеря которого необратима. Всё остальное можно перевыпустить. Сценарий, ради которого вы делаете бэкап, — «сервера больше нет»; в этот момент пароль должен быть у вас в руках, а не на нём.

Пароль понадобится на шаге 7. Пока держите его открытым в менеджере паролей.

Шаг 5. Создать SSH-ключ для хранилища

ssh-keygen -t ed25519 -N "" -f /root/.ssh/id_sbox -C "rzbackup@$(hostname -f)"

Создаст два файла: /root/.ssh/id_sbox (закрытый) и /root/.ssh/id_sbox.pub (открытый). Пароль на ключ не ставится намеренно — агент работает без человека.

Шаг 6. Положить ключ в хранилище

Подставьте пользователя и хост, выданные администратором:

ssh-copy-id -p 23 -s -i /root/.ssh/id_sbox.pub ВАШ_ЛОГИН@eu1.node.redz.tech

Спросит пароль раздела хранения — тот, что выдал администратор. Флаг -s обязателен: на узле ключи кладутся через SFTP, без него не сработает.

Проверьте, что ключ принят:

ssh -p 23 -i /root/.ssh/id_sbox ВАШ_ЛОГИН@eu1.node.redz.tech pwd

Ожидаемый ответ — путь вроде /home, и пароль спрашивать не должно. Если спрашивает — ключ не принят, повторите предыдущую команду.

Шаг 7. Создать config.local

Это главный шаг. Выполните:

cd /redz/prog/backup
cp config.local.example config.local
chmod 600 config.local
vi config.local

В открывшемся файле должны получиться ровно эти четыре строки (остальное можно удалить или оставить закомментированным):

REPO_PASSPHRASE="7f3a91c4be05d2ea6c18470b9d3fa25e8c07b1449de6a03f"
RELAY_SECRET="rz-server-2026-xxxxxxxxxxxxxxxxxxxx"
SBOX_KEY="/root/.ssh/id_sbox"
SBOX_USER="uXXXXXX"

Что куда:

СтрокаЧто в неё вписать
REPO_PASSPHRASEпароль из шага 4
RELAY_SECRETсекрет уведомлений от администратора
SBOX_KEYпуть к ключу из шага 5, обычно ровно /root/.ssh/id_sbox
SBOX_USERпользователь хранилища от администратора, вида uXXXXXX или uXXXXXX-subN
SBOX_HOSTхост хранилища от администратора, обычно eu1.node.redz.tech

Кавычки обязательны. Пробелов вокруг = быть не должно.

Если MySQL на сервере не пускает root без пароля — сделайте ещё один файл:
vi /redz/prog/backup/mysql.cnf
chmod 600 /redz/prog/backup/mysql.cnf
Содержимое:
[client]
user=root
password=ВАШ_ПАРОЛЬ_MYSQL
И добавьте в config.local пятую строку:
MYSQL_DEFAULTS_FILE="/redz/prog/backup/mysql.cnf"
Проверить, нужно ли это: выполните mysql -e 'SELECT 1'. Если ответило без пароля — не нужно.

⚠️ Отдельному пользователю нужны полные права на все базы, а не только чтение. Тот же ключ восстанавливает: создаёт базу, кладёт схему, данные, процедуры и триггеры — а дампы несут DEFINER=, которого read-only учётной записи не хватит. Ограниченный ключ проходит все ночные прогоны и отказывает ровно в день, ради которого заводился. Права раздаются одной строкой, GRANT OPTION намеренно не даётся:

CREATE USER 'rzbackup'@'localhost' IDENTIFIED BY 'ПАРОЛЬ';
GRANT ALL PRIVILEGES ON *.* TO 'rzbackup'@'localhost';

REDZ_Backup doctor проверяет это делом — заводит и сносит служебную базу, а не читает SHOW GRANTS: роли и подстановки пишут одни и те же права по-разному.

Шаг 8. Проверить, что всё сошлось

REDZ_Backup doctor --send

Ожидаемый ответ заканчивается строкой:

all checks passed, 0 warnings

И в Telegram приходит сообщение [TEST].

Если есть строки FAIL — дальше не идите, найдите их в разборе ошибок внизу страницы. Строки WARN обычно не мешают.

Теперь проверьте, что хранилище реально работает — запись, чтение и сверка байтов:

REDZ_Backup selftest

Ожидаемый ответ заканчивается строкой:

this client and this storage work together

Шаг 9. Описать сайты

Базы данных и системные конфиги агент найдёт сам, а вот про сайты ему надо рассказать. Пусть предложит сам:

REDZ_Backup discover

Посмотрит работающий nginx и базы и напишет файлы-предложения:

shop → /redz/prog/backup/sites.d/shop.conf.suggested
blog → /redz/prog/backup/sites.d/blog.conf.suggested
review the .suggested files, then rename them to .conf

Посмотрите каждый, поправьте при необходимости и переименуйте — пока файл называется .suggested, он не работает:

cd /redz/prog/backup/sites.d
cat shop.conf.suggested
mv shop.conf.suggested shop.conf

Если сайт не нашёлся или его надо описать иначе — формат в справочнике по конфигу сайта. Минимальный рабочий файл — три строки:

ROOT="/var/www/shop"
DB=("shop_main")
PROFILE="bitrix"

Шаг 10. Первый прогон и включение по расписанию

Сначала руками, чтобы видеть глазами:

REDZ_Backup run all

Идёт несколько минут. Ожидаемый ответ — строки вида job db: ok in 34s, job system: ok in 12s, job site-shop: ok in 2m.

REDZ_Backup status

Покажет таблицу наборов с возрастом последнего прогона.

Убедились, что прошло — включайте расписание:

systemctl enable --now redz-backup-db.timer redz-backup-files.timer redz-backup-maint.timer
systemctl list-timers 'redz-backup*' --no-pager
redz-backup-db.timerбазы, каждый час
redz-backup-files.timerсистема и сайты, ночью в 03:20
redz-backup-maint.timerчистка старого и проверка целостности, воскресенье 05:00
Готово. Дальше агент работает сам и молчит, пока всё в порядке. При сбое пришлёт сообщение в Telegram, при возврате в норму — ещё одно.

4. Готовый пример config.local целиком

Так выглядит рабочий файл на сервере с MySQL под паролем. Скопируйте, замените значения на свои:

#!/usr/bin/env bash
# /redz/prog/backup/config.local — права 0600, пакетом не заменяется.

# --- обязательное -----------------------------------------------------------
REPO_PASSPHRASE="7f3a91c4be05d2ea6c18470b9d3fa25e8c07b1449de6a03f"
RELAY_SECRET="rz-server-2026-xxxxxxxxxxxxxxxxxxxx"
SBOX_KEY="/root/.ssh/id_sbox"

# --- хранилище, если отличается от умолчаний ---------------------------------
SBOX_USER="uXXXXXX"
SBOX_HOST="eu1.node.redz.tech"

# --- MySQL, если root без пароля не пускает ----------------------------------
MYSQL_DEFAULTS_FILE="/redz/prog/backup/mysql.cnf"

# --- необязательное ----------------------------------------------------------
# Свои каталоги в бэкап системы, вдобавок к штатному списку:
EXTRA_PATHS=( "/opt/scripts" "/etc/haproxy" )

# Подпись в уведомлениях. Пусто = имя хоста:
RELAY_FROM="shop-prod"

# Сколько дней хранить логи агента:
LOG_KEEP_DAYS=30

Полный список того, что можно писать в этот файл, — в следующем разделе. Всё, чего вы не написали, берётся из /redz/prog/backup/config.

5. Справочник: все настройки config.local

Два файла. config — умолчания, приезжают с пакетом и заменяются при обновлении. config.local — ваши значения и секреты; пакет его не создаёт, не меняет и не удаляет. Правьте только его.

Оба — фрагменты bash. Формат строк: ИМЯ="значение", без пробелов вокруг =. Массивы: ИМЯ=( "первое" "второе" ).

Управляемый режим (подписка)

НастройкаУмолчаниеЧто делает
MANAGED01 — настройки хранилища приходят с сервера подписки. При 0 агент не обращается наружу вообще
ENROLL_URLhttps://api.redz.tech/backup/configАдрес сервера подписки
ENROLL_KEY_FILE/etc/redz/licenceФайл с лицензией. Тот же, что открывает репозиторий пакетов
ENROLL_PUBKEYпустоПусто = enroll.pub из пакета. Ключ, которым проверяется подпись присланных настроек
ENROLL_SSH_KEYпустоПусто = id_managed рядом с программой. Закрытая часть не покидает сервер
ENROLL_REFRESH_H12Через сколько часов перед прогоном сверяться с сервером подписки
ENROLL_TIMEOUT20Таймаут запроса, секунды
REPORT_URLhttps://api.redz.tech/backup/reportКуда агент сообщает исход каждого набора: удача или провал с текстом ошибки, число архивов и их объём. Пусто — отчёты выключены. Отдельный адрес от ENROLL_URL: тот отдаёт пароль репозитория, и учащать его ради телеметрии значило бы гонять секрет по сети в разы чаще
REPORT_TIMEOUT10Таймаут отчёта, секунды. Отчёт никогда не роняет и не задерживает прогон: не ушёл — строка в лог, и всё

Присланное сервером лежит в config.managed — это генерируемый файл, правки в нём затираются при ближайшей сверке. Порядок чтения: config → config.managed → config.local, то есть ваши строки сильнее наших. Если вы задали в config.local то, что присылаем мы, doctor об этом предупредит — иначе смена хранилища с нашей стороны молча не доедет.

Хранилище

НастройкаУмолчаниеЧто делает
REPO_PASSPHRASEпустоОбязательно. Пароль шифрования репозитория
PROVIDERssh-storessh-store (узел хранения по ssh) или local (каталог на диске — для проверок)
ENGINEautoauto берёт первый установленный. Либо borg, либо restic явно
SBOX_HOSTпустоХост хранилища. Пусто намеренно: у каждого сервера свой
SBOX_USERпустоПользователь хранилища
SBOX_PORT23SSH-порт хранилища
SBOX_KEYпустоПуть к закрытому ключу. Пусто = ssh-agent или ключи по умолчанию
SBOX_BASEREDZ_BackupКаталог внутри хранилища. Внутри него агент сам создаёт <имя-хоста>/<набор>
LOCAL_BASEпустоКаталог, когда PROVIDER="local"
BORG_COMPRESSIONzstd,10Передаётся borg как есть. zstd,1 быстрее и хуже жмёт, lz4 почти без нагрузки на процессор
BORG_BINпустоПусто = искать: сначала bin/borg из пакета redz-borg, потом PATH
RESTIC_BINпустоТо же для restic
MOUNT_POINT/mnt/rzbackupКуда монтирует mount

Сколько хранить

Значения передаются borg prune дословно.

RETENTION_DB--keep-hourly 48 --keep-daily 14 --keep-weekly 8 --keep-monthly 12
RETENTION_FILES--keep-daily 14 --keep-weekly 8 --keep-monthly 12
RETENTION_SYSTEM--keep-daily 30 --keep-monthly 12

Когда считать бэкап просроченным

В часах. doctor сообщит, если набор не обновлялся дольше.

STALE_H_DB6
STALE_H_FILES48
STALE_H_SYSTEM48

Что попадает в бэкап системы

SYSTEM_PATHSмассивПолный список путей набора system. Переопределять целиком обычно не нужно
EXTRA_PATHS()Ваши дополнительные пути к тому же набору. Обычно правят именно это

Штатно в набор system входят: конфигурация nginx, php, MySQL, letsencrypt, sshd, sysconfig, systemd, кроны, hosts/resolv.conf/fstab, /etc/redz, /redz/bin, /redz/prog, /redz/service, /redz/build. Несуществующие пути пропускаются, поэтому один список работает на всех серверах.

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

MySQL

MYSQL_DEFAULTS_FILEпустоФайл с учётными данными (права 0600). Пусто = ~/.my.cnf или доступ через сокет
MYSQL_EXCLUDE_DBinformation_schema performance_schema sysБазы, которые не дампить. Через пробел
MYSQL_DUMP_OPTSсм. нижеОпции mysqldump
BORG_CHUNKER_DBbuzhash,10,23,16,4095Разбиение дампов на куски

Умолчание опций: --single-transaction --quick --hex-blob --no-tablespaces --set-gtid-purged=OFF --skip-dump-date. Набор автоматически сверяется с --help самого бинарника: MariaDB не знает --set-gtid-purged, и он молча отбрасывается. --skip-dump-date убирать нельзя — без него каждый дамп отличается от вчерашнего строкой с датой, и дедупликация перестаёт работать.

Дампы кладутся несжатыми: движок дедуплицирует их против вчерашних, поэтому 30 почасовых дампов одной базы стоят немногим больше одного. Предварительное сжатие это уничтожит. Замерено: повторный дамп неизменной базы занимает 116 байт.

Отдельно сохраняются пользователи и права (_grants.sql) — без них восстановление половинчатое. Таблицы MyISAM не покрываются --single-transaction, о таких прогон предупреждает отдельной строкой.

Состояние и логи

LOG_KEEP_DAYS30Сколько дней хранить логи агента. 0 = вечно
SPOOL_DIR/var/tmp/rzbackupКуда складываются дампы перед отправкой. Путь попадает в архив, поэтому после первого прогона менять его нежелательно
RESTORE_DIR/var/tmp/rzbackup-restoreКуда извлекается восстановленное

Уведомления

NOTIFYrelayrelay · telegram · none
NOTIFY_REPEAT_H6Часов тишины, прежде чем повторить сообщение о том же продолжающемся сбое
NOTIFY_MAX_ATTEMPTS24Сколько раз пытаться отправить, прежде чем выбросить сообщение
HEARTBEAT_URLпустоURL, который дёргается после успешного прогона — для внешнего сторожа вроде healthchecks.io

Через реле (по умолчанию) — токен бота остаётся на стороне реле, на сервере его нет:

RELAY_SECRETпустоОбязательно при NOTIFY="relay"
RELAY_URLhttps://relay.redz.tech/telegram/
RELAY_TARGETserverВ какой чат реле отправит
RELAY_FROMпустоПодпись отправителя в сообщении. Пусто = имя хоста
RELAY_TIMEOUT8Секунд

Напрямую своим ботом — если реле не используется, поставьте NOTIFY="telegram":

TG_TOKENпустоТокен бота от @BotFather
TG_CHATпустоИдентификатор чата
TG_APIhttps://api.telegram.org
TG_TIMEOUT8Секунд
Не реализованы. NOTIFY_LEVEL и NOTIFY_DIGEST_AT присутствуют в файле config, но ни на что не влияют. Фактическое поведение соответствует NOTIFY_LEVEL="fail": уходят падения и возвраты в норму, успешные прогоны молчат.

Как ведут себя уведомления

Сообщение сначала попадает в очередь на диске, потом отправляется. Повторяемая ошибка оставляет его там до следующего запуска. Всё, что не 2xx и не 4xx, считается повторяемым: потерять сообщение о сбое из-за неузнанного ответа хуже, чем прислать его дважды.

Первое падение уходит сразу, повторы молчат до NOTIFY_REPEAT_H, возврат в норму присылается один раз.

6. Справочник: конфиг сайта

По файлу на приложение: /redz/prog/backup/sites.d/<имя>.conf. Имя файла становится именем набора: shop.conf → набор site-shop со своим репозиторием, своей ретенцией и своей командой восстановления.

Пакет эти файлы не создаёт и при удалении не уносит.

#!/usr/bin/env bash
ROOT="/var/www/shop"          # обязательно, каталог должен существовать
OWNER="nginx:nginx"           # владелец, восстанавливается вместе с файлами
DB=("shop_main" "shop_stat")  # какие базы относятся к этому приложению
PROFILE="bitrix"              # готовый набор исключений, см. ниже
EXCLUDE=(
	"**/upload/tmp/**"        # свои исключения, добавляются к профилю
)
PRE_HOOK="/usr/local/bin/shop-maintenance on"    # необязательно
POST_HOOK="/usr/local/bin/shop-maintenance off"  # необязательно

Других полей нет. Обязательное только одно — ROOT. Шаблоны исключений пишутся в форме **/каталог/**: эта форма одинаково понятна и borg, и restic.

DB влияет только на удобство восстановления: набор db дампит все базы сервера независимо от этих списков. Список нужен, чтобы restore site <имя> --with-db знал, что поднимать вместе с файлами. Ошибка здесь не теряет данные.

Хуки

PRE_HOOK выполняется до снятия копии, POST_HOOK — после. Нужны, когда для согласованного снимка приложение надо перевести в режим обслуживания или сбросить очередь на диск. Если не нужны — не пишите их вовсе.

Сайты с общим ядром

Если несколько доменов используют одно ядро через симлинки и одну базу — делайте один набор с ROOT на общий родительский каталог. Восстановить один домен отдельно всё равно нельзя: без ядра и базы он ничего не значит. borg хранит симлинки симлинками, поэтому общая часть попадёт в архив один раз, а не по разу на домен.

7. Профили исключений

Лежат в /redz/prog/backup/profiles/, подставляются полем PROFILE.

bitrixbitrix/cache, managed_cache, stack_cache, tmp, backup, html_pages (композитный кэш, обычно самый крупный), updates, upload/resize_cache, upload/tmp, *.log
wordpresswp-content/cache, wp-content/upgrade, wp-content/uploads/cache, *.log
laravelstorage/framework/{cache,sessions,views}, storage/logs, node_modules, *.log
plain*.log, tmp/
systemслужебный, применяется к набору system автоматически

Свой профиль — новый файл profiles/<имя>.excl, по шаблону на строку. Называйте его иначе, чем штатные: обновление пакета заменяет файлы профилей.

8. Все команды

doctor [--send]Самопроверка. --send дополнительно отправляет живое тестовое сообщение
selftestСоздаёт временный репозиторий, пишет, читает, сверяет байты, проверяет целостность, удаляет за собой
statusНаборы, число снапшотов, возраст последнего прогона, активные сообщения о сбоях
discoverПредложить конфиги сайтов по работающему nginx и базам
enrollЗабрать настройки с сервера подписки (только при MANAGED=1). Выполняется само перед прогонами, вручную нужно один раз при установке
run allВсё перечисленное ниже
run dbДамп всех баз
run systemСлепок ОС и SYSTEM_PATHS
run sitesВсе sites.d/*.conf
run site:<имя>Один сайт
run filessystem + sites
snapshots [набор]Что лежит в репозиториях
verify [--deep] [набор]Целостность. --deep перечитывает сами данные, а не только структуру — долго
prune [набор]Применить ретенцию
unlock [набор]Снять замок, оставшийся после оборванного прогона или забытого монтирования
freeСвободное место в хранилище
repo <набор>Напечатать URL репозитория, чтобы запустить borg вручную
docОпубликовать RESTORE.md рядом с репозиториями
mount <набор> [--archive N]Снапшоты как каталог
mount --rawСамо хранилище, а не снапшоты
umountОтмонтировать
notify test [текст]Поставить в очередь тестовое сообщение и отправить
notify flushПопробовать отправить всё, что застряло в очереди
notify statusГлубина очереди и состояние по ключам
notify raise <fail|ok> <ключ> <заголовок> [текст]Поднять или снять сообщение из своего скрипта — с той же защитой от повторов
notify clear <ключ>Забыть состояние по ключу
version · help

Код возврата: 0 — успех, 1 — ошибка. Годится для собственного мониторинга.

9. Восстановление

Всё по умолчанию выбирает безопасный вариант: перезапись рабочих данных должна быть решением, а не побочным эффектом.

База

REDZ_Backup restore db shop_main

Поднимет базу под новым именем shop_main_restore_20260817_1430, исходную не тронет. Дальше сравниваете и переключаетесь сами.

REDZ_Backup restore db shop_main --at "2026-08-15 03:00"   # состояние на момент
REDZ_Backup restore db shop_main --to shop_test            # под своим именем
REDZ_Backup restore db shop_main --force                   # перезаписать исходную

--force перед перезаписью снимает дамп текущего состояния в run/pre-restore/. Если снять не удалось — восстановление отменяется.

Сайт

REDZ_Backup restore site shop

По умолчанию ничего не пишет — печатает, что было бы сделано. Посмотрели, согласились:

REDZ_Backup restore site shop --yes                    # на место
REDZ_Backup restore site shop --target /tmp/check      # в другой каталог
REDZ_Backup restore site shop --yes --with-db          # вместе с базами из DB=()

Отдельные файлы

REDZ_Backup restore path /etc/nginx/nginx.conf --set system

Всегда извлекает рядом (в RESTORE_DIR), никогда на место: вслепую восстановленный /etc запирает снаружи. Посмотрите результат и скопируйте руками.

Момент времени

--at берёт ближайший снапшот не позже указанного момента. Форматы: 2026-08-15, "2026-08-15 03:00". Если такого снапшота нет — отказ с ненулевым кодом, а не молчаливый откат на свежий: смысл --at в том, чтобы взять состояние «до поломки».

Если сервера больше нет

Рядом с репозиториями в хранилище лежит RESTORE.md — открытым текстом, обновляется при каждом прогоне. В нём движок, адреса репозиториев, доступ и готовые команды. Пароля в нём нет. Нужны только он, ваш пароль и любой компьютер с borg:

borg list 'ssh://ВАШ_ЛОГИН@eu1.node.redz.tech:23/./REDZ_Backup/system'
borg extract --dry-run --list 'ssh://…/system::имя-архива'
borg extract 'ssh://…/system::имя-архива' etc/nginx

10. Монтирование

Две разные команды, и разница существенная.

mount <набор>Репозиторий через borg: он расшифровывает на лету, видны настоящие файлы и каталоги. Это то, что нужно почти всегда
mount --rawСамо хранилище через sshfs: служебные файлы borg, шифротекст, читать нечего. Годится посмотреть, что вообще легло, сколько занимает, и прочитать RESTORE.md
REDZ_Backup mount system
ls -la /mnt/rzbackup/
cp /mnt/rzbackup/system-20260817T032000Z/etc/nginx/nginx.conf /root/
REDZ_Backup umount

Данные в хранилище зашифрованы, но при монтировании расшифровываются на лету — пароль берётся из config.local, вводить ничего не надо. Монтируется только на чтение, испортить архив нельзя.

REDZ_Backup umount обязателен. Пока смонтировано, borg держит репозиторий заблокированным, и очередной прогон по расписанию не пройдёт.

Нужен FUSE. Обычно уже стоит; если нет — dnf install -y fuse-libs fuse-sshfs.

11. Что где лежит на сервере

/redz/prog/backup/Программа, права 0750
/redz/prog/backup/configУмолчания. Заменяется обновлением, править бесполезно
/redz/prog/backup/config.localВаш файл, 0600. Пакет не трогает
/redz/prog/backup/sites.d/Конфиги сайтов. Пакет не трогает
/redz/prog/backup/profiles/Профили исключений. Заменяются обновлением
/redz/prog/backup/bin/borgИз пакета redz-borg
/redz/prog/backup/log/По файлу на день, чистятся сами
/redz/prog/backup/run/pre-restore/Страховочные дампы перед --force. Переживают удаление пакета
/redz/prog/backup/run/Прочее состояние: очередь сообщений, время прогонов, временный каталог движка
/usr/bin/REDZ_BackupСимлинк, чтобы команда работала по имени из любого каталога
/usr/lib/systemd/system/redz-backup*Юниты. Свои правки — через systemctl edit, тогда обновление их не тронет
/etc/redz/licenceКлюч доступа к репозиторию пакетов, 0600
/etc/yum.repos.d/redz.repo0600. Обновление его не заменит

dnf remove redz-backup уносит программу, юниты и симлинк, но оставляет config.local, конфиги сайтов, логи и страховочные дампы.

12. Ошибки и что они значат

enroll: подпись конфигурации неверна — ответ отброшен

Ответ пришёл не от нас или испорчен по дороге. Настройки при этом не тронуты — агент продолжает работать на прежних. Проверьте, что ENROLL_URL не подменён, и что /redz/prog/backup/enroll.pub на месте; если файла нет — dnf reinstall redz-backup.

enroll: конфигурация выписана на «другой-сервер»

Настройки привязаны к имени сервера и на чужом не применятся. Так и задумано. Бывает после переименования хоста или переезда на новую машину — напишите в поддержку, лицензию перепривяжут.

enroll: ключ отброшен (не разрешён серверу)

Сервер прислал настройку, которую агент не обязан принимать. Остальные применены, работать можно. Сообщите нам — это наша ошибка, не ваша.

enroll: место в хранилище ещё не выделено (HTTP 409)

Лицензия верна, но раздел хранения под ваш сервер пока не создан. Обычно вопрос минут после оплаты. Повторите позже — ничего перенастраивать не нужно.

run: сервер подписки недоступен, работаем на прежних настройках

Это предупреждение, а не ошибка: бэкап сделан. Так и задумано — наш сервис не должен уметь останавливать ваши бэкапы. Если строка держится сутками, напишите нам.

run: подписка истекла или отозвана

Новые бэкапы не создаются. Уже созданные никуда не делись и читаются: snapshots, mount и restore работают как обычно. Возобновите подписку — агент подхватит сам в течение ENROLL_REFRESH_H часов, либо ускорьте это командой REDZ_Backup enroll.

doctor: config.local перекрывает присланное сервером: SBOX_HOST …

В config.local лежит строка, которая сильнее присланной нами. Пока она там, смена хранилища с нашей стороны до этого сервера не доедет. Если вы её ставили осознанно — всё в порядке, предупреждение можно не трогать. Если нет — удалите строку.

REDZ_Licence set отвечает FAIL 401 — ключ не принят

Ключ неверный или отозван. Проверьте, что скопировали целиком, вместе с частью до двоеточия. Запросите новый у администратора.

dnf: Failed to download metadata … Signing key not found

Подпись метаданных проверяется по отдельному хранилищу ключей dnf, которое стирает dnf clean all. Заполнить его можно только неинтерактивно:

dnf -y makecache --repo=redz

Проще: REDZ_Licence set <тот же ключ> — он делает это сам.

dnf показывает 0 пакетов и ничего не сообщает

В redz.repo стоит skip_if_unavailable=True, чтобы недоступный репозиторий не ронял общесистемный dnf update. Плата: неверный ключ ничего не говорит. Проверьте явно:

REDZ_Licence check

dnf не видит только что вышедшую версию

Кэш метаданных живёт час:

dnf upgrade --refresh redz-backup

doctor: REPO_PASSPHRASE is empty — set it in …/config.local

Не выполнен шаг 7: в config.local нет строки REPO_PASSPHRASE="…". До этого агент работать не будет и не должен: архив, который потом никто не прочтёт, хуже отсутствующего.

doctor: RELAY_SECRET is empty

Нет строки RELAY_SECRET="…". Возьмите секрет у администратора. Если уведомления не нужны вовсе — впишите NOTIFY="none", но тогда о сбоях вы не узнаете.

doctor: ssh to … failed — key not installed?

Хранилище не приняло ключ. Проверьте вручную:

ssh -p 23 -i /root/.ssh/id_sbox ВАШ_ЛОГИН@eu1.node.redz.tech pwd

Спрашивает пароль — вернитесь к шагу 6. Не находит файл ключа — проверьте путь в строке SBOX_KEY.

doctor: … forbids execution или движок не стартует

Каталог /redz/prog/backup/run/tmp лежит на разделе, смонтированном с noexec. Встроенный borg распаковывает свои библиотеки во временный каталог при каждом запуске, и на noexec это невозможно. Раздел с /redz должен допускать исполнение.

doctor: run/tmp is a symlink

Агент отказывается работать с символьной ссылкой в служебном каталоге. Удалите ссылку — он создаст обычный каталог сам.

doctor: borg … is older than 1.2.5

Дистрибутивный borg слишком стар. Поставьте пакет — агент возьмёт его автоматически, править конфигурацию не нужно:

dnf install -y redz-borg

doctor: clock: … off the relay

Часы сервера разъехались. При расхождении больше суток реле отвергнет каждое сообщение как устаревшее, и выглядеть это будет как «уведомления не приходят». Включите синхронизацию времени: timedatectl set-ntp true.

doctor: spool holds N unsent message(s)

Сообщения копятся и не уходят. Причину покажет:

REDZ_Backup notify flush

doctor: предупреждение про юниты в /etc/systemd/system

Там лежат копии юнитов, перекрывающие пакетные, и обновления до них не дойдут. Остались от установки до появления пакета — удалите копии и выполните systemctl daemon-reload.

Прогон: MyISAM tables are not covered by --single-transaction

Предупреждение, не ошибка: перечисленные таблицы могли попасть в дамп в несогласованном состоянии. Лечится переводом их в InnoDB.

Прогон: mysqldump …: dump incomplete

Дамп оборвался — агент проверяет наличие завершающей строки, которую mysqldump пишет в конце. Что именно ответил mysqldump, смотрите в /redz/prog/backup/log/.

Прогон: Failed to create/acquire the lock … (timeout)

Репозиторий заблокирован: либо осталось смонтированное, либо оборвался предыдущий прогон.

systemctl list-units 'redz-backup*'   # убедиться, что прогон правда не идёт
REDZ_Backup umount                    # если монтировали
REDZ_Backup unlock                    # снять оставшийся замок

Снятый замок при работающем прогоне даст двух писателей в одном репозитории — сначала убедитесь, что прогон не идёт.

set 'X' has no snapshot at or before …

На запрошенный момент снапшота нет. Посмотрите, какие есть:

REDZ_Backup snapshots X

Молча взять более свежий агент не станет — это противоречило бы смыслу --at.

Сайт не попал в бэкап

Проверьте, что файл называется .conf, а не .conf.suggested, и что путь в ROOT существует. Список того, что агент видит:

REDZ_Backup status

13. Состав репозитория

redz-releaseНастройка репозитория, ключ подписи, команда REDZ_Licence
redz-filesystemВладеет каталогами /redz и /etc/redz
redz-backupАгент резервного копирования
redz-borgBorgBackup, закреплённый по серии, независимо от дистрибутива

Ключ подписи

Первый пакет ставится по прямой ссылке и подтверждён только TLS — с чего-то надо начать. Сверьте отпечаток один раз, дальше подписи проверяет dnf сам:

C401 C72E 277D B92F CB13  CCD3 AABA 7A0C F951 55EF

RPM-GPG-KEY-redz · проверить: gpg --show-keys RPM-GPG-KEY-redz

Пока установлен redz-backup, dnf откажется ставить borgbackup версии 2 и выше. Это намеренно: у borg 2.x другой формат репозитория, и обычное обновление сделало бы все существующие архивы нечитаемыми. Переход на borg 2 — это миграция, а не обновление.

Программы REDZ ставятся не в /usr и /etc, как принято, а в /redz/prog/; исполняемые файлы симлинкуются в /usr/bin, чтобы команда работала по имени.