# Журнал подключений и шифрованный бэкап

Задача: если инфраструктуру изымут, остаётся независимая копия того, кто,
когда и откуда подключался. Копия уходит в Telegram, но открыть её без
вашего офлайн-ключа нельзя.

## Что попадает в архив

На ноде:

- `/var/log/remnanode/*.jsonl` — Xray access log: время, IP клиента,
  назначение, inbound/outbound, `email` (ID пользователя). Байт и времени
  сессии там нет — это не биллинг, а факт соединения.
- ротированные `*.jsonl.*` за последние двое суток.

На панели:

- `panel.sql` — полный `pg_dump`;
- `usage_daily.csv` — трафик по пользователю, ноде и дню;
- `node_usage_hourly.csv` — upload/download по ноде по часам;
- `user_traffic.csv` — всего использовано, первый вход, последняя
  активность, последняя нода;
- `subscription_requests.csv` — когда и с какого IP запрашивали подписку;
- `hwid_devices.csv` — устройства, IP, user-agent;
- `torrent_reports.csv` — отчёты блокировщика.

CSV читаются человеком после расшифровки. Полный дамп содержит секреты,
поэтому и шифруется.

## Ключ: сервер не может расшифровать сам

Пароль на сервере бесполезен: при изъятии он уезжает вместе с архивом.
Поэтому асимметричное шифрование `age`:

1. На своём компьютере (не на VPS):

   ```sh
   age-keygen -o remnawave-backup.key
   ```

   Файл `remnawave-backup.key` — приватный. В нём же строка
   `# public key: age1...`. Приватный ключ храните офлайн, в двух местах.

2. На сервер попадает только публичный ключ `age1...`.

3. Ночью сервер делает `age -R age1...`. Без приватного ключа архив
   не открывается даже с root на сервере.

Восстановление:

```sh
cat remnawave-*.part-* > archive.tar.gz.age
age -d -i remnawave-backup.key archive.tar.gz.age > archive.tar.gz
tar -xzf archive.tar.gz
cd data && sha256sum -c MANIFEST.sha256
```

`sha256sum` рядом с частями (в `/var/lib/remnawave-backup/manifests/`)
проверяет сами загруженные части.

## Telegram

1. Создайте бота у `@BotFather`, получите токен.
2. Создайте приватный канал, добавьте бота администратором с правом
   публикации.
3. Узнайте `chat_id` канала (например, через `@userinfobot` или
   `getUpdates`). У канала он отрицательный, вида `-100...`.
4. Положите токен в файл с режимом 0600:

   ```sh
   install -m 600 /dev/null /etc/remnawave/telegram.token
   printf '%s\n' '123456:ABC...' > /etc/remnawave/telegram.token
   ```

Токен не передаётся в `argv`: `curl` читает его из временного конфига
0600, как и API панели.

## Установка

```sh
bash backup.sh --install \
  --age-recipient 'age1...' \
  --chat-id '-1001234567890' \
  --token-file /etc/remnawave/telegram.token
```

Ставится `/usr/local/sbin/remnawave-backup` и таймер
`remnawave-backup.timer` на 03:30 UTC с разбросом 30 минут. Повторный
запуск не создаёт второй архив: `flock`.

Проверка и ручной прогон:

```sh
remnawave-backup --check
remnawave-backup
```

`--check` вызывает `getMe`, проверяет токен и наличие `age`.

## Размер и нарезка

Telegram принимает документ до 50 МБ. Архив режется на части по 49 МБ
(`split -b 49M`), каждая уходит отдельным `sendDocument`. Если частей
много, Telegram может ограничить скорость — таймер и разброс это
сглаживают, но при сотнях мегабайт в сутки нужен свой Bot API server
или внешнее хранилище.

## Хранение и юридическая оговорка

- После успешной отправки части удаляются с сервера. Остаётся только
  `sha256`-манифест. `KEEP_LOCAL_DAYS=2` в `/etc/remnawave/backup.conf`
  оставляет локальную копию на два дня.
- Telegram — вторая копия, а не архив доказательств: доступ зависит от
  аккаунта, метаданные не контролируются. Для юридически значимого
  хранения нужен ещё один неизменяемый бэкап (S3 Object Lock, restic
  на своём сервере) и понятный срок хранения.
- IP-адреса и история подключений — персональные данные. Определите
  срок хранения и доступ до запуска, а не после запроса.
- Это не юридическая консультация.

## Ограничения

- На официальном образе `remnawave/node` структурированного
  `log.outputs` нет. `node_setup.sh` по умолчанию ставит форк
  `ghcr.io/legiz-ru/remnanode-smux`; если вы вернули официальный образ,
  логи в JSONL писать не будут.
- `copytruncate` в logrotate теряет строки в момент ротации. Для
  ежедневного журнала это приемлемо; для полной гарантии нужен
  перезапуск логгера, который рвёт соединения.
- `backpressure: drop_new` в профиле не тормозит трафик, но при
  переполнении очереди теряет записи. Смотрите предупреждения Xray.
