feat: публикация портов не-HTTP сервисами, проверка портов до деплоя, пример RustDesk

serverus: app_ports.py проверяет опубликованные порты приложения до
изменений - по docker compose config (переменные из .env подставлены)
против слушающих сокетов сервера и портов контейнеров других приложений.
Занятый порт больше не роняет up после замены файлов. Конвенция: только
мост; не-HTTP сервисы публикуют свои порты, 80 и 443 - у caddy;
bind-mount только своих файлов из data/<сервис>/ с :ro. Описано, что
упавший up после синхронизации файлы не откатывает.

App: uploads.check предупреждает о 80/443 вместо любых портов и о
bind-mount из папки приложения вне data/ или без :ro.

docs/apps/rustdesk: приложение (hbbs, hbbr, ключ генерируем сами),
genkey.py и check.py - проверка сервера по протоколу RustDesk снаружи.
Проверено на стенде Debian 13: деплой, повторный деплой, отказ второго
приложения на тех же портах до изменений, перезагрузка сервера.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
protokeyandClaude Opus 5.5 committed 2026-09-30 10:31:38 +04:00
1 parent a8d1f286d1
commit fd4b05097a
16 files changed
+526 -13

No files matched your search

+58
View File
@@ -0,0 +1,58 @@
# RustDesk на docker-сервере
Свой сервер для [RustDesk](https://rustdesk.com) - удаленного доступа к компьютерам. Пример приложения по конвенции `serverus.DockerHost` (см. `src/serverus/README.md`): не-HTTP сервис, который публикует свои порты через мост.
## Что внутри
Сервер RustDesk - две программы из образа `rustdesk/rustdesk-server`:
- `hbbs` - сервер ID. Клиенты регистрируются в нем под своим ID; при подключении hbbs сводит двух клиентов и помогает им соединиться напрямую (пробивает NAT). Трафик сеанса через него не идет. Порты: 21116/tcp+udp, 21115/tcp (NAT-тест).
- `hbbr` - relay. Если напрямую соединиться не вышло, весь трафик сеанса идет через него. Порт 21117/tcp.
hbbs сообщает клиентам адрес relay (`-r ${RELAY_HOST}:21117`). Оба запущены с `-k _`: работают только клиенты с нашим ключом. Websocket-порты (21118, 21119) не публикуются: они нужны только веб-клиенту.
Ключ генерируем мы и кладем в `data/<сервис>/` (bind-mount `:ro`): он хранится в версии приложения и переживает переустановку ОС. Сгенерированный hbbs ключ жил бы в volume и пропал бы вместе с ним, а клиентов пришлось бы перенастраивать. База hbbs (`db_v2.sqlite3`) - в named volume.
## Файлы
```
app/docker-compose.yaml приложение
app/.env RELAY_HOST, из env_example
app/data/hbbs|hbbr/ ключ, из genkey.py
genkey.py ключ в формате hbbs/hbbr
check.py проверка сервера по протоколу RustDesk
```
`app/.env` и `app/data/` в git не попадают.
## Развернуть
```bash
cd docs/apps/rustdesk
cp env_example app/.env # RELAY_HOST - ip или домен сервера
../../../.venv/bin/python genkey.py # печатает публичный ключ
make -C ../../.. serverus_app ip=<ip> action=deploy name=rustdesk dir=docs/apps/rustdesk/app
```
Через бота - архив содержимого `app/` (вместе с `.env` и `data/`).
## Проверить
```bash
python3 check.py <ip> "$(cat app/data/hbbs/id_ed25519.pub)"
```
Статус `running` и открытый порт ничего не доказывают: docker-proxy принимает tcp, даже когда контейнер лежит. `check.py` говорит с сервером по его протоколу снаружи, как клиент:
1. UDP 21116: регистрация клиента - ответ `RegisterPeerResponse`: udp доходит до hbbs и обратно.
2. TCP 21115: NAT-тест - hbbs возвращает порт, с которого мы пришли. Совпадает с нашим - hbbs видит настоящий адрес клиента, прямые соединения возможны.
3. TCP 21116: запрос соединения с несуществующим ID - с нашим ключом `ID_NOT_EXIST`, с чужим `LICENSE_MISMATCH`: сервер работает с нашим ключом.
4. TCP 21117: два соединения с одним uuid - hbbr сводит их, байты идут в обе стороны. С чужим ключом соединение закрывается.
Выход 0 - все прошло. В логах hbbs (`make serverus_app ... action=logs name=rustdesk`) должно быть `Private key comes from id_ed25519` и `Key:` с нашим публичным ключом.
Проверено на стенде (Debian 13): деплой, повторный деплой без изменений, отказ второго приложения на тех же портах до изменений, перезагрузка сервера.
## Клиент
Настройки - Сеть - ID-сервер: адрес сервера, Key: публичный ключ. Relay клиент получит от hbbs.