Files
knowledge-base/decisions/2026-04-28-rustdesk-lejianwen-pro-migration.md
dttb da0b57e26c RustDesk LXC 116: миграция OSS → lejianwen-pro 1.1.14 (MUST_LOGIN=Y)
- Подмена hbbs/hbbr на pro-бинари из docker lejianwen/rustdesk-server-s6, apt-mark hold
- Systemd overrides: hbbs --must-login Y -k _ -r remot.dttb.ru:21117; hbbr -k _
- config.yaml: lang ru, домен remot.dttb.ru, ключ + jwt прописаны, swagger on
- NPM Proxy Host 14: forward 10.0.0.244, SSL force, http2, /ws/id /ws/relay locations
- NPM streams 21115-21119 пересозданы (id 38-43), Stream 30 удалён
- Admin pw сменён, бэкап + rollback-скрипт в /root/rustdesk-* на LXC 116
- Ключ id_ed25519 идентичен до/после, 13 peers продолжают работать

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 12:20:17 +03:00

134 lines
10 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
date: 2026-04-28
type: migration
tags: [rustdesk, lxc116, npm, lejianwen, must-login, isolation]
---
# RustDesk migration: OSS hbbs/hbbr → lejianwen-pro
## Цель
Закрыть дыру: техник Клиента-А не должен подключаться к машинам Клиента-Б, даже зная ID и пароль. Это задача `MUST_LOGIN=Y` на уровне `hbbs`.
## Что было
- LXC 116 `rustdeskserver` — Debian 12, 10.0.0.244 / 100.70.191.161 (NetBird)
- Установлено через ProxmoxVE community-script (нативно, не Docker):
- `hbbs` 1.1.14 — **OSS** Purslane (поддерживает только `--key`, `-r`, `--rendezvous-servers`, `ALWAYS_USE_RELAY`)
- `hbbr` 1.1.14 — OSS
- `rustdesk-api` 2.7 — **lejianwen** (это уже не OSS, но без настроек: lang=zh-CN, jwt пустой, домен 192.168.1.66 мусорный)
- Конфиг `/var/lib/rustdesk-api/conf/config.yaml` — почти дефолтный, никто не правил
- БД `rustdeskapi.db` 352K с 1 admin user + 13 peers (внутренние LAN)
- NPM Proxy Host 14 для `remot.dttb.ru` смотрел на **мёртвый 10.0.0.43:21114**, streams 30-35 на **мёртвый 10.0.0.44**, SSL force/HTTP/2/block_exploits всё off
- `https://remot.dttb.ru/_admin/` снаружи: **502 Bad Gateway** (никто никогда не пользовался web-админкой через домен)
- Peers всё равно работали: внутренние через LAN 10.0.0.244, внешние видимо через NetBird mesh / DNAT на роутере минуя NPM
## Найденная развилка
OSS `hbbs` не понимает `MUST_LOGIN`. Этот патч есть только в `lejianwen/rustdesk-server-pro` (тот же бинарь, что в docker-образе `lejianwen/rustdesk-server-s6`). Без него изоляция работает только на уровне `rustdesk-api` (адресные книги по группам), но любой клиент с правильным ключом всё равно может ходить по ID минуя API.
## Варианты
| Вариант | Действие | Плюс | Минус |
|---|---|---|---|
| A1 | Подменить только бинари hbbs/hbbr на pro, остальное оставить | Минимум потрясений, ключ/БД/api/NPM streams не трогаем | На LXC два разных способа управления (apt + override). apt-mark hold нужен |
| A2 | Оставить OSS, изоляция только через api | Ноль рисков ломки | Главное требование (изоляция по ID) не закрыто |
| A3 | Полная миграция в Docker s6 (как в исходном промте Олега) | Единый стек, проще будущие upgrades | Требует Docker, расширения rootfs LXC, миграции БД, больше точек отказа сейчас |
**Выбран: A1.** A3 — отдельной задачей через 2-4 недели когда дойдём до MySQL/HA/MCP-обёртки.
## Что сделано
### LXC 116
1. **Бэкап** `/root/rustdesk-backup-20260428-1134/` (ключи, db_v2.sqlite3, rustdeskapi.db, config.yaml.orig, systemd units, JWT, admin pw)
2. **Pro-бинари** извлечены из `lejianwen/rustdesk-server-s6:latest` через docker на Proxmox-host (на самом 10.0.0.250 docker есть, в LXC 116 — нет):
```
docker create --name rd-extract lejianwen/rustdesk-server-s6:latest
docker cp rd-extract:/usr/bin/hbbs /tmp/...
docker cp rd-extract:/usr/bin/hbbr /tmp/...
pct push 116 ...
```
3. **Подмена** через `mv`:
- `/usr/bin/hbbs.oss-1.1.14` ← старый
- `/usr/bin/hbbs` ← новый pro (поддерживает `--must-login Y`)
4. **`apt-mark hold rustdesk-server-hbbs rustdesk-server-hbbr`** — apt не перезапишет
5. **Systemd overrides:**
- `/etc/systemd/system/rustdesk-hbbs.service.d/override.conf`:
```
ExecStart=
ExecStart=/usr/bin/hbbs -k _ -r remot.dttb.ru:21117 --must-login Y
```
- `/etc/systemd/system/rustdesk-hbbr.service.d/override.conf`:
```
ExecStart=
ExecStart=/usr/bin/hbbr -k _
```
6. **`config.yaml`** правки (точечно, без пересборки):
- `lang: ru`
- `admin.title: "Remote Support Portal"`
- `app.show-swagger: 1`, `ban-threshold: 5`
- `rustdesk.id-server / relay-server: remot.dttb.ru`
- `rustdesk.api-server: https://remot.dttb.ru`
- `rustdesk.key: R0lA4r77hAGw6YRL1qG3JioVqQ0Q0fJfzkwlAGqR6jU=` (значение `id_ed25519.pub`)
- `rustdesk.key-file: /var/lib/rustdesk-server/id_ed25519.pub`
- `jwt.key: <openssl rand -base64 48>`
7. **Admin pw сменён** через CLI: `rustdesk-api reset-admin-pwd <pw>` (cd в `/var/lib/rustdesk-api/`)
### NPM (LXC 103 через API)
1. Proxy Host 14 (id 14): `forward_host: 10.0.0.244`, `ssl_forced/http2/block_exploits=true`, `caching_enabled=false`, `allow_websocket_upgrade=true`
2. **Custom Nginx Configuration** (advanced_config) добавлен с `location /ws/id` (→21118) и `/ws/relay` (→21119) — для будущей All-in-HTTPS архитектуры (клиенты за корпоративными firewall'ами через 443)
3. Stream 30 (TCP 21114) **удалён** — API не должен жить голым TCP
4. Streams 31-35 пересозданы (id 38-43) на 10.0.0.244 (PUT не работает на streams API — `additional properties` ошибка; делать DELETE+POST с минимальным body без `certificate_id`)
5. Добавлен Stream id 43: 21116/TCP (id-server) дополнительно к Stream id 39: 21116/UDP
## Подтверждения
- `sha256sum id_ed25519.pub` идентичен до/после миграции (`abfbebe9…a38c6b`) ✅
- `sha256sum id_ed25519` (приватный) идентичен ✅
- `MUST_LOGIN=Y` явно в `/var/log/rustdesk-server/hbbs.log` после рестарта
- `Key: R0lA4r77hAGw6YRL1qG3JioVqQ0Q0fJfzkwlAGqR6jU=` тот же
- `Private key comes from id_ed25519` — pro-hbbs нашёл существующий ключ, не перегенерировал
- Все 7 портов 21114-21119 слушают
- `https://remot.dttb.ru/_admin/` снаружи: **HTTP/2 200 OK** (раньше 502)
- 13 существующих peers продолжают подключаться (БД та же)
## Грабли
1. **community-script ставит OSS hbbs**, не pro. Бинарь от Purslane Ltd. Версия 1.1.14 у обоих идентична, но pro имеет дополнительный CLI-флаг `--must-login Y` и читает `MUST_LOGIN` env. Проверка через `grep -ao MUST_LOGIN /usr/bin/hbbs` (`strings` в LXC нет).
2. **Admin API не пускает через curl** даже с правильным admin-токеном из `/api/admin/login` — требует web-сессию. Юзеров и группы создавать через UI.
3. **NPM PUT на streams возвращает 400 `additional properties`** — даже если отправить только разрешённые поля. Решение: DELETE + POST с минимальным body (5 полей: incoming_port, forwarding_host, forwarding_port, tcp_forwarding, udp_forwarding). Без `certificate_id`.
4. **`ENCRYPTED_ONLY` env-переменная** не нашлась как строка в pro-бинаре hbbs. Возможно управляется через config или этого патча нет в публичном `lejianwen/rustdesk-server-s6`. MUST_LOGIN сам по себе закрывает изоляцию — шифрование RustDesk и так включено для key-серверов.
5. **NPM streams для портов 21115-21119 по факту не использовались** — peers подключались внутри LAN (10.0.0.244 напрямую) или через NetBird (100.70.191.161). Поэтому "поломанная" конфигурация NPM не мешала. Внешний DNAT на роутере dttb.ru вероятно идёт прямо на rustdesk-сервер минуя NPM (надо ещё разок проверить — или подтвердить что внешние клиенты ходят через NetBird).
## Rollback
`bash /root/rustdesk-rollback.sh` — за 30 секунд:
- mv бинари обратно (`/usr/bin/hbbs.oss-1.1.14` → `/usr/bin/hbbs`)
- удаляет systemd overrides
- восстанавливает `config.yaml.orig`
- снимает apt-mark hold
- рестартует сервисы
NPM-настройки **скриптом не откатываются** — ручной откат через UI или из `/data/database.sqlite` LXC 103.
## TODO (отдельные задачи)
- Создать клиентские группы и юзеров через web (Олег, в /_admin/)
- Протестировать изоляцию на тестовой клиентской машине
- Раскатать новый `RustDesk2.toml` на ~30-50 машин через GPO/скрипт (старые конфиги тоже работают — ключ тот же)
- Бэкап БД API + ключей по cron на ArtLeon через NetBird/rsync
- Через 2-4 недели — миграция в Docker rustdesk-server-s6 (Вариант A3), MySQL/HA, MCP-обёртка
## Связанные файлы
На LXC 116:
- `/root/rustdesk-backup-20260428-1134/` — бэкап и креды
- `/root/rustdesk-rollback.sh` — откат (chmod 700)
- `/root/RustDesk2.toml` — шаблон клиента
- `/root/rustdesk-migration-report.md` — расширенный отчёт
В kb:
- [[projects/dttb/rustdesk]] — справочник по серверу
- [[projects/dttb/credentials]] — креды (admin pw, JWT_KEY)
- [[projects/dttb/proxmox-inventory]] — LXC 116 запись обновлена