> For the complete documentation index, see [llms.txt](https://docs.iexexchanger.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.iexexchanger.com/server-i-dannye/sozdanie-rezervnoi-kopii.md).

# Создание резервной копии

Эта инструкция описывает резервное копирование iEXExchanger после установки на чистый сервер без FASTPANEL и других панелей управления.

Все команды на сервере выполняются от пользователя `root` через SSH.

{% hint style="info" %}
Installer уже настраивает автоматическое резервное копирование. Не создавайте дополнительный CRON, не изменяйте `iex-backup.service`, `iex-backup.timer` и управляемую конфигурацию резервного копирования вручную.
{% endhint %}

## Какие варианты доступны

| Вариант                      | Что сохраняется                                                | Когда использовать                                          |
| ---------------------------- | -------------------------------------------------------------- | ----------------------------------------------------------- |
| Автоматический полный снимок | Обе базы PostgreSQL, постоянные файлы и системная конфигурация | Для ежедневной защиты сервера                               |
| Ручной полный снимок         | То же содержимое, что и в автоматическом снимке                | Перед важными ручными изменениями или для внеплановой копии |
| Ручной экспорт баз данных    | Основная база и база Laravel Pulse в отдельных файлах          | Для переноса, скачивания и дополнительной внешней копии баз |

{% hint style="warning" %}
Эти варианты решают разные задачи. Ручной экспорт баз данных не содержит загруженные пользователями файлы и системную конфигурацию, поэтому он не заменяет полный снимок.
{% endhint %}

Перед обновлением продукта Updater автоматически создаёт собственную контрольную точку. Не запускайте ручной backup одновременно с обновлением или откатом.

## Что входит в полный снимок

Зашифрованный полный снимок создаётся с помощью PostgreSQL и Restic.

В него входят:

* проверенный дамп основной базы PostgreSQL;
* проверенный дамп базы Laravel Pulse;
* постоянные файлы Backend;
* пользовательские загрузки;
* настраиваемые файлы публичного сайта;
* общие данные из `/var/www/iexexchanger/shared`;
* управляемая конфигурация из `/etc/iexexchanger`.

### Что необходимо сохранить отдельно

В полный снимок не входят:

* пароль шифрования Restic;
* установочный файл `install.yaml`;
* архивы Backend, Frontend и лицензии;
* файл с первоначальными доступами администратора;
* сертификаты из `/etc/letsencrypt`;
* ручные экспорты из `/var/backups/iexexchanger/operator-db`.

Сохраните эти данные в отдельном зашифрованном хранилище. Не отправляйте пароли, лицензионные файлы или `install.yaml` через открытые чаты, электронную почту либо публичные облачные ссылки.

{% hint style="danger" %}
Потеря пароля Restic означает потерю доступа к зашифрованному репозиторию. Пароль должен храниться отдельно от самого репозитория резервных копий.
{% endhint %}

## Готовый запрос для AI-агента

{% prompt description="Создать и безопасно проверить резервную копию iEXExchanger" icon="database" openInAIProviders="true" defaultExpanded="full" %}

```markdown
Ты — технический агент по резервному копированию iEXExchanger на чистом сервере без панели управления.

Используй предоставленные пользователем данные для SSH-подключения. Все действия выполняй от root.

Цель: создать и проверить резервную копию, не изменяя рабочие данные и не раскрывая секреты.

Правила:

1. Сначала выполни только проверки: свободное место, состояние `iex-backup.service`, `iex-backup.timer`, наличие Restic и `/usr/local/sbin/iex-db-backup-operator`.
2. Не запускай backup одновременно с обновлением, откатом, восстановлением или уже выполняющимся Restic-процессом.
3. Не открывай и не выводи содержимое `.env`, `install.yaml`, pgpass, файла пароля Restic или лицензионных файлов.
4. Не редактируй systemd unit-файлы, управляемый `db-backup.json`, конфигурацию приложения и рабочие базы.
5. Для полного снимка используй только `systemctl start iex-backup.service`.
6. Успех полного снимка подтверди по `Result=success`, `ExecMainStatus=0`, новому Restic Snapshot ID, отсутствию временных файлов в spool и проверке репозитория.
7. Путь к Restic repository и password file получи из `iex-backup.service`. Не передавай сам пароль в аргументах или переменных окружения.
8. Для переносимого экспорта сначала выполни `/usr/local/sbin/iex-db-backup-operator config-check`, затем `export` с уникальной UTC-меткой.
9. Убедись, что созданы две пары `SQL.gz + manifest.json`, и проверь каждый SQL командой `iex-db-backup inspect --file`. Не используй неподдерживаемый параметр `--require-manifest`.
10. Если выполняешь restore drill, восстанавливай снимок только во временный каталог и в заранее отсутствующие тестовые базы. Никогда не используй рабочие имена баз и `/` как target.
11. Удаляй только временный каталог и тестовые базы, созданные тобой в рамках текущей проверки. Перед удалением проверь их точные имена и пути.
12. При ошибке остановись, сохрани точное сообщение и журнал. Не применяй `restic unlock`, пока не подтверждено отсутствие всех процессов Restic и операций обновления.

В итоговом отчёте укажи:

- какой вариант backup выполнен;
- время начала и завершения;
- результат службы;
- появился ли новый Restic Snapshot ID без публикации полного ID;
- прошла ли проверка репозитория;
- созданы ли main и Pulse exports с manifest;
- прошёл ли `inspect`;
- выполнено ли контрольное восстановление;
- очищены ли временные тестовые данные;
- состояние сайта и основных служб после проверки;
- что владельцу нужно сохранить во внешнем защищённом хранилище.

Не включай в отчёт IP-адрес, SSH-пароль, содержимое секретных файлов, лицензионные данные, полные пути к пользовательским секретам или полные Snapshot ID.
```

{% endprompt %}

***

## Подготовка к созданию копии

{% content-ref url="/spaces/uyjsNtEAtO6Sby8CHWyD/pages/cCEoFDjTDIufy3NUEakd" %}
[Подключение к серверу по SSH](/help-center/upravlenie-serverom/podklyuchenie-k-serveru-po-ssh.md)
{% endcontent-ref %}

{% stepper %}
{% step %}

### Подключитесь к серверу

Подключитесь по SSH, используя IP-адрес своего сервера:

```bash
ssh root@IP_СЕРВЕРА
```

{% endstep %}

{% step %}

### Проверьте свободное место

```bash
df -h /
```

На диске должно быть достаточно свободного места для нового снимка и временных дампов обеих баз.
{% endstep %}

{% step %}

### Проверьте, не выполняется ли backup

```bash
systemctl is-active iex-backup.service
```

Нормальное состояние между запусками:

```
inactive
```

Если отображается `activating`, дождитесь завершения текущего запуска.

Если отображается `failed`, сначала изучите ошибку:

```bash
journalctl -u iex-backup.service -n 100 --no-pager
```

{% endstep %}
{% endstepper %}

***

## Вариант 1. Ручной полный снимок

Это основной способ создать внеплановую полную копию установленной системы.

Останавливать сайт для обычного снимка не требуется. Для особенно важных изменений создавайте копию в период минимальной активности и не изменяйте настройки до её завершения.

{% stepper %}
{% step %}

### Запустите полный backup

```bash
systemctl start iex-backup.service
```

Команда ожидает завершения всей операции. Система последовательно:

1. создаёт дамп основной базы;
2. проверяет его через PostgreSQL;
3. создаёт и проверяет дамп Laravel Pulse;
4. добавляет базы, постоянные файлы и конфигурацию в зашифрованный Restic-снимок;
5. проверяет репозиторий;
6. применяет установленную политику хранения;
7. удаляет временные незашифрованные дампы.
   {% endstep %}

{% step %}

### Проверьте результат службы

```bash
systemctl show iex-backup.service \
  -p Result \
  -p ExecMainStatus \
  -p ExecMainStartTimestamp \
  -p ExecMainExitTimestamp
```

Успешный результат содержит:

```
Result=success
ExecMainStatus=0
```

После успешного завершения `iex-backup.service` снова становится `inactive`. Для одноразовой службы это нормальное состояние.
{% endstep %}

{% step %}

### Проверьте журнал

```bash
journalctl -u iex-backup.service \
  --since '-30 minutes' \
  --no-pager
```

В конце журнала не должно быть `Failed` или ошибки Restic.
{% endstep %}

{% step %}

### Определите реальные пути backup

Не вводите пароль Restic в команду вручную. Получите путь к репозиторию и путь к файлу пароля из действующей службы:

```bash
IEX_BACKUP_REPOSITORY=$(systemctl cat iex-backup.service \
  | sed -n 's|.*--repo \([^ ]*\).*|\1|p' \
  | head -n 1)

IEX_BACKUP_PASSWORD_FILE=$(systemctl cat iex-backup.service \
  | sed -n 's|^LoadCredential=[^:]*:\(.*\)|\1|p' \
  | head -n 1)

if [ -d "$IEX_BACKUP_REPOSITORY" ] \
  && [ -s "$IEX_BACKUP_PASSWORD_FILE" ]
then
  echo "Пути резервного копирования определены"
else
  echo "Не удалось определить repository или password file"
  exit 1
fi
```

Команды определяют только пути и не выводят содержимое пароля.
{% endstep %}

{% step %}

### Убедитесь, что снимок появился

```bash
restic \
  --repo "$IEX_BACKUP_REPOSITORY" \
  --password-file "$IEX_BACKUP_PASSWORD_FILE" \
  --no-cache \
  snapshots \
  --tag iexexchanger-managed \
  --latest 3
```

Проверьте дату, время и идентификатор последнего снимка.
{% endstep %}
{% endstepper %}

{% hint style="success" %}
Полный снимок создан, если служба завершилась с `Result=success` и `ExecMainStatus=0`, а новый снимок отображается в списке Restic.
{% endhint %}

## Вариант 2. Автоматическое резервное копирование

Автоматический backup создаёт такой же полный снимок без ручного запуска.

Первый проверенный снимок создаётся ещё во время первичной установки. После успешного завершения установки новые снимки создаёт `iex-backup.timer`.

### Проверьте таймер

```bash
systemctl is-enabled iex-backup.timer
systemctl is-active iex-backup.timer
systemctl list-timers --all --no-pager iex-backup.timer
```

Ожидаемые состояния:

```
enabled
active
```

В стандартной конфигурации запуск выполняется ежедневно в `02:15 UTC` со случайной задержкой до 15 минут. Если сервер был выключен в установленное время, systemd сохраняет пропущенный запуск и выполняет его после включения.

### Политика хранения

В стандартной конфигурации сохраняются:

* минимум 3 последних снимка;
* 7 ежедневных снимков;
* 4 еженедельных снимка;
* 6 ежемесячных снимков.

При создании нового снимка Restic автоматически применяет эту политику. Поэтому ручной запуск полного backup также может удалить старые снимки, срок хранения которых завершился.

{% hint style="warning" %}
Не редактируйте `/etc/systemd/system/iex-backup.service` и `/etc/systemd/system/iex-backup.timer`. Эти файлы управляются iEXExchanger и могут быть заменены при обслуживании системы.
{% endhint %}

## Вариант 3. Ручной экспорт баз данных

Используйте этот вариант, если нужно получить переносимые копии основной базы и Laravel Pulse.

Экспорт создаётся в формате `SQL.gz`. Для каждого SQL-файла рядом создаётся `manifest.json` с размером, SHA-256 и описанием содержимого.

{% hint style="info" %}
Управляемый инструмент уже настроен Installer. Не создавайте новый `db-backup.json`, не копируйте старую конфигурацию из FASTPANEL и не указывайте реквизиты PostgreSQL вручную.
{% endhint %}

{% stepper %}
{% step %}

### Проверьте подключения

```bash
/usr/local/sbin/iex-db-backup-operator config-check
```

Успешная проверка заканчивается сообщением:

```
All selected profiles completed successfully.
```

{% endstep %}

{% step %}

### Создайте уникальную метку

```bash
IEX_BACKUP_TAG="manual-$(date -u +%Y%m%dT%H%M%SZ)"
echo "$IEX_BACKUP_TAG"
```

Метка помогает определить назначение и время создания копии.
{% endstep %}

{% step %}

### Запустите экспорт

```bash
/usr/local/sbin/iex-db-backup-operator export \
  --tag "$IEX_BACKUP_TAG"
```

Инструмент экспортирует обе базы:

* основную базу iEXExchanger;
* базу Laravel Pulse.

Команда `backup` является синонимом `export`, но в инструкции используется единый вариант `export`.
{% endstep %}

{% step %}

### Проверьте созданные файлы

```bash
find /var/backups/iexexchanger/operator-db \
  -maxdepth 1 \
  -type f \
  -name "*${IEX_BACKUP_TAG}*" \
  -printf '%f | %s bytes | mode %m\n' \
  | sort
```

Должны появиться четыре файла:

```
main-....sql.gz
main-....sql.gz.manifest.json
pulse-....sql.gz
pulse-....sql.gz.manifest.json
```

Файлы создаются с закрытыми правами `0600`.
{% endstep %}

{% step %}

### Проверьте SQL и manifest

```bash
for IEX_BACKUP_FILE in \
  /var/backups/iexexchanger/operator-db/*"${IEX_BACKUP_TAG}.sql.gz"
do
  test -f "${IEX_BACKUP_FILE}.manifest.json" || {
    echo "Manifest не найден: ${IEX_BACKUP_FILE}.manifest.json"
    exit 1
  }

  /var/www/iexexchanger/current/backend/tools/db-backup/iex-db-backup \
    inspect \
    --file "$IEX_BACKUP_FILE"
done
```

Успешная проверка каждого файла начинается с:

```
SQL artifact valid:
```

Команда `inspect` проверяет соседний manifest автоматически. Параметр `--require-manifest` в текущем инструменте не используется.
{% endstep %}

{% step %}

### Создайте общий файл контрольных сумм

```bash
cd /var/backups/iexexchanger/operator-db

sha256sum \
  *"${IEX_BACKUP_TAG}.sql.gz" \
  *"${IEX_BACKUP_TAG}.sql.gz.manifest.json" \
  > "SHA256SUMS-${IEX_BACKUP_TAG}.txt"

chmod 600 "SHA256SUMS-${IEX_BACKUP_TAG}.txt"
```

{% endstep %}
{% endstepper %}

### Где сохраняется ручной экспорт

```
/var/backups/iexexchanger/operator-db
```

Ручные экспорты не добавляются в автоматический Restic-снимок и не удаляются политикой хранения Restic.

Контролируйте размер каталога:

```bash
du -sh /var/backups/iexexchanger/operator-db
```

## Сохранение копии вне сервера

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

Минимум одна актуальная проверенная копия должна находиться вне основного сервера.

Для полной внешней копии используйте отдельный смонтированный диск или хранилище, подготовленное для Restic. Если текущий репозиторий уже находится на системном диске, не меняйте его путь непосредственно в systemd unit-файле: перенос выполняется по отдельному плану с проверкой репозитория и контрольным восстановлением.

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

{% stepper %}
{% step %}

### Скачивание ручного экспорта

На своём компьютере создайте каталог:

```bash
mkdir -p iexexchanger-backup
```

Скачайте SQL, manifest и файл контрольных сумм по SFTP или SCP. В команде замените IP-адрес и метку на свои значения:

```bash
scp \
  'root@IP_СЕРВЕРА:/var/backups/iexexchanger/operator-db/*manual-YYYYMMDDTHHMMSSZ*' \
  ./iexexchanger-backup/
```

На Windows можно использовать SFTP-клиент с теми же реквизитами SSH.
{% endstep %}

{% step %}

### Проверка скачанных файлов

Linux:

```bash
cd iexexchanger-backup
sha256sum --check SHA256SUMS-manual-YYYYMMDDTHHMMSSZ.txt
```

macOS:

```bash
cd iexexchanger-backup
shasum -a 256 -c SHA256SUMS-manual-YYYYMMDDTHHMMSSZ.txt
```

Не удаляйте файлы с сервера, пока внешняя копия не скачана и проверка не завершилась успешно.

{% hint style="danger" %}
Формат gzip уменьшает размер, но не шифрует SQL. Храните скачанные экспорты на зашифрованном диске или в защищённом хранилище с ограниченным доступом.
{% endhint %}
{% endstep %}
{% endstepper %}

## Сохранение пароля Restic

Для стандартной установки пароль находится в закрытом файле:

```
/etc/iexexchanger/secrets/backup-key
```

Фактический путь уже был получен в переменной `IEX_BACKUP_PASSWORD_FILE`. Не открывайте файл командой `cat` и не выводите пароль в терминал без необходимости.

Скопируйте файл в отдельное защищённое хранилище через SFTP или SCP. Для стандартного пути команда на вашем компьютере выглядит так:

```bash
scp \
  root@IP_СЕРВЕРА:/etc/iexexchanger/secrets/backup-key \
  ./iex-restic-password

chmod 600 ./iex-restic-password
```

Храните пароль отдельно от копии Restic. Не добавляйте его в Git, обычный ZIP, письмо или публичную ссылку.

## Полная проверка репозитория

Обычный ежедневный запуск проверяет часть данных и структуру репозитория. Периодически выполняйте полное чтение всех пакетов.

Если вы открыли новую SSH-сессию или начали с этого раздела, сначала повторно выполните шаг «Определите реальные пути backup».

```bash
restic \
  --repo "$IEX_BACKUP_REPOSITORY" \
  --password-file "$IEX_BACKUP_PASSWORD_FILE" \
  --no-cache \
  check \
  --read-data-subset=100%
```

Успешный результат заканчивается сообщением:

```
no errors were found
```

{% hint style="warning" %}
Полная проверка читает весь репозиторий и может создать заметную нагрузку на диск. Запускайте её в период минимальной активности.
{% endhint %}

## Контрольное восстановление

Наличие файла или снимка ещё не гарантирует возможность восстановления. Периодически проверяйте выбранный Restic-снимок во временном каталоге.

Все команды этого раздела выполняйте последовательно в одной SSH-сессии. Если переменные `IEX_BACKUP_REPOSITORY` и `IEX_BACKUP_PASSWORD_FILE` ещё не заданы, сначала выполните шаг «Определите реальные пути backup».

{% hint style="danger" %}
Не восстанавливайте проверочную копию поверх рабочей системы и не используйте названия рабочих баз данных. В качестве target запрещено указывать `/`.
{% endhint %}

{% stepper %}
{% step %}

### Выберите снимок

```bash
restic \
  --repo "$IEX_BACKUP_REPOSITORY" \
  --password-file "$IEX_BACKUP_PASSWORD_FILE" \
  --no-cache \
  snapshots \
  --tag iexexchanger-managed
```

Скопируйте полный ID нужного снимка:

```bash
IEX_RESTORE_SNAPSHOT='ПОЛНЫЙ_ID_СНИМКА'
```

Не выбирайте последний снимок автоматически, если проверка связана с инцидентом: ошибка уже могла попасть в новую копию.
{% endstep %}

{% step %}

### Создайте закрытый временный каталог

```bash
IEX_RESTORE_TEST=$(mktemp -d /var/tmp/iex-restore-check.XXXXXX)
chmod 700 "$IEX_RESTORE_TEST"
echo "$IEX_RESTORE_TEST"
```

{% endstep %}

{% step %}

### Восстановите снимок во временный каталог

```bash
restic \
  --repo "$IEX_BACKUP_REPOSITORY" \
  --password-file "$IEX_BACKUP_PASSWORD_FILE" \
  --no-cache \
  restore "$IEX_RESTORE_SNAPSHOT" \
  --target "$IEX_RESTORE_TEST"
```

{% endstep %}

{% step %}

### Проверьте дампы и постоянные файлы

```bash
IEX_RESTORE_MAIN_DUMP="$IEX_RESTORE_TEST/var/backups/iexexchanger/spool/main.dump"
IEX_RESTORE_PULSE_DUMP="$IEX_RESTORE_TEST/var/backups/iexexchanger/spool/pulse.dump"

if [ -s "$IEX_RESTORE_MAIN_DUMP" ] \
  && [ -s "$IEX_RESTORE_PULSE_DUMP" ] \
  && [ -d "$IEX_RESTORE_TEST/var/www/iexexchanger/shared" ] \
  && [ -d "$IEX_RESTORE_TEST/etc/iexexchanger" ]
then
  echo "Ожидаемые файлы найдены"
else
  echo "В восстановленном снимке отсутствуют обязательные данные"
  exit 1
fi

/usr/lib/postgresql/18/bin/pg_restore \
  --list "$IEX_RESTORE_MAIN_DUMP" \
  > /dev/null

/usr/lib/postgresql/18/bin/pg_restore \
  --list "$IEX_RESTORE_PULSE_DUMP" \
  > /dev/null

echo "Содержимое снимка и оба дампа читаются"
```

{% endstep %}
{% endstepper %}

<details>

<summary>Расширенная проверка с восстановлением в отдельные базы</summary>

Эта проверка предназначена для технического специалиста. Она создаёт две временные базы и не изменяет рабочие базы iEXExchanger.

Убедитесь, что тестовые базы ещё не существуют:

```bash
IEX_RESTORE_MAIN_DB=iex_backup_restore_main
IEX_RESTORE_PULSE_DB=iex_backup_restore_pulse

for IEX_RESTORE_DB in "$IEX_RESTORE_MAIN_DB" "$IEX_RESTORE_PULSE_DB"
do
  if [ -n "$(runuser --user postgres -- \
    psql --tuples-only --no-align --dbname=postgres \
    --command="SELECT 1 FROM pg_database WHERE datname='${IEX_RESTORE_DB}'")" ]
  then
    echo "База уже существует: $IEX_RESTORE_DB"
    exit 1
  fi
done
```

Создайте пустые базы:

```bash
runuser --user postgres -- \
  createdb --template=template0 "$IEX_RESTORE_MAIN_DB"

runuser --user postgres -- \
  createdb --template=template0 "$IEX_RESTORE_PULSE_DB"
```

Восстановите оба дампа:

```bash
runuser --user postgres -- \
  /usr/lib/postgresql/18/bin/pg_restore \
  --exit-on-error \
  --single-transaction \
  --no-owner \
  --no-acl \
  --dbname="$IEX_RESTORE_MAIN_DB" \
  < "$IEX_RESTORE_MAIN_DUMP"

runuser --user postgres -- \
  /usr/lib/postgresql/18/bin/pg_restore \
  --exit-on-error \
  --single-transaction \
  --no-owner \
  --no-acl \
  --dbname="$IEX_RESTORE_PULSE_DB" \
  < "$IEX_RESTORE_PULSE_DUMP"
```

Проверьте количество восстановленных таблиц:

```bash
runuser --user postgres -- \
  psql --dbname="$IEX_RESTORE_MAIN_DB" \
  --command="SELECT count(*) AS public_tables FROM information_schema.tables WHERE table_schema='public';"

runuser --user postgres -- \
  psql --dbname="$IEX_RESTORE_PULSE_DB" \
  --command="SELECT count(*) AS public_tables FROM information_schema.tables WHERE table_schema='public';"
```

После успешной проверки удалите только созданные тестовые базы:

```bash
runuser --user postgres -- dropdb "$IEX_RESTORE_MAIN_DB"
runuser --user postgres -- dropdb "$IEX_RESTORE_PULSE_DB"
```

</details>

### Удалите временный каталог проверки

Выполняйте очистку только в той же SSH-сессии, где была создана переменная `IEX_RESTORE_TEST`:

```bash
case "$IEX_RESTORE_TEST" in
  /var/tmp/iex-restore-check.*)
    rm -rf -- "$IEX_RESTORE_TEST"
    ;;
  *)
    echo "Очистка остановлена: неожиданный путь"
    exit 1
    ;;
esac
```

## Какой вариант выбрать

<table><thead><tr><th width="280.50390625">Ситуация</th><th>Рекомендуемое действие</th></tr></thead><tbody><tr><td>Ежедневная защита</td><td>Проверьте работу <code>iex-backup.timer</code></td></tr><tr><td>Перед важным ручным изменением</td><td>Создайте ручной полный снимок</td></tr><tr><td>Нужна копия баз на компьютере</td><td>Создайте ручной экспорт и скачайте SQL, manifest и SHA256SUMS</td></tr><tr><td>Перед обновлением продукта</td><td>Используйте backup, создаваемый Updater; при необходимости заранее сделайте дополнительный полный снимок</td></tr><tr><td>Проверка готовности к аварии</td><td>Выполните полную проверку Restic и контрольное восстановление</td></tr></tbody></table>

Для полноценной защиты от потери сервера используйте отдельный диск, внешний сервер или хранилище в другом контуре отказа. Снимок, который находится только на системном диске этого же сервера, не является полной внешней резервной копией.

## Частые проблемы

<details>

<summary>Служба завершилась с ошибкой</summary>

Проверьте состояние и журнал:

```bash
systemctl --no-pager --full status iex-backup.service
journalctl -u iex-backup.service -n 150 --no-pager
```

Не запускайте повторный backup, пока причина ошибки не установлена.

</details>

<details>

<summary>Restic сообщает, что репозиторий заблокирован</summary>

Сначала проверьте, нет ли действующего процесса:

```bash
systemctl is-active iex-backup.service
pgrep -a restic
```

Не удаляйте lock, если работает backup, обновление, откат или другой процесс Restic.

Если процессов Restic нет и предыдущая операция аварийно завершилась, проверьте lock:

```bash
restic \
  --repo "$IEX_BACKUP_REPOSITORY" \
  --password-file "$IEX_BACKUP_PASSWORD_FILE" \
  --no-cache \
  list locks
```

Только после подтверждения, что lock устарел:

```bash
restic \
  --repo "$IEX_BACKUP_REPOSITORY" \
  --password-file "$IEX_BACKUP_PASSWORD_FILE" \
  --no-cache \
  unlock
```

</details>

<details>

<summary>Недостаточно места на диске</summary>

```bash
df -h /
du -sh /var/backups/iexexchanger
du -sh /var/backups/iexexchanger/operator-db
```

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

</details>

<details>

<summary>Не найден iex-db-backup-operator</summary>

Проверьте файл:

```bash
stat /usr/local/sbin/iex-db-backup-operator
```

Не копируйте инструмент из другого проекта и не создавайте конфигурацию вручную. Проверьте целостность текущей установки или обратитесь в техническую поддержку.

</details>

<details>

<summary>Manifest отсутствует или inspect возвращает ошибку</summary>

Такая копия не считается проверенной.

Не исправляйте SQL или manifest вручную. Сохраните сообщение об ошибке и создайте новый экспорт с новой меткой.

</details>

<details>

<summary>Таймер не активен</summary>

```bash
systemctl --no-pager --full status iex-backup.timer
systemctl list-timers --all --no-pager iex-backup.timer
```

Не создавайте отдельный CRON и не изменяйте unit-файлы. Если таймер отсутствует или остаётся неактивным, проверьте состояние установки и обратитесь в техническую поддержку.

</details>

## Правила безопасности

* Выполняйте команды только от `root` через защищённое SSH-соединение.
* Не выводите содержимое файлов `.env`, `install.yaml`, PostgreSQL pgpass или пароля Restic.
* Не используйте `chmod 777` для каталогов и файлов backup.
* Не изменяйте управляемые systemd unit-файлы и конфигурацию `db-backup.json`.
* Не храните единственную копию на том же диске, где работает iEXExchanger.
* Не запускайте backup одновременно с обновлением, откатом или восстановлением.
* Не проверяйте восстановление на рабочих базах.
* Не удаляйте предыдущую копию, пока новая не создана, не проверена и не сохранена вне сервера.
