255 lines
18 KiB
Markdown
255 lines
18 KiB
Markdown
---
|
||
date: 2026-04-28
|
||
type: claude-session
|
||
session_id: 6936f7cb-387a-4118-a3da-49367030abce
|
||
started: 2026-04-28T08:27:41.560Z
|
||
ended: 2026-04-28T08:38:33.580Z
|
||
messages: 3
|
||
tools: [Bash, TodoWrite, ToolSearch]
|
||
tags: [claude, session]
|
||
---
|
||
|
||
# # Промт для Claude Code: развёртывание RustDesk API Server (lejianwen)
|
||
|
||
## Запрос
|
||
|
||
# Промт для Claude Code: развёртывание RustDesk API Server (lejianwen)
|
||
|
||
## Контекст
|
||
|
||
Я системный администратор. У меня уже работает Proxmox VE на домене [dttb.ru](http://dttb.ru) с следующей инфраструктурой:
|
||
|
||
- **LXC-контейнер с RustDesk OSS Server** (hbbs + hbbr) — текущая рабочая инсталляция, `id_ed25519` и `id_[ed25519.pub](http://ed25519.pub)` в `/data/rustdesk/server/` (примерно, путь уточни через ls)
|
||
- **LXC с Nginx Proxy Manager** на [dttb.ru](http://dttb.ru) — управляет всеми reverse-proxy и Let's Encrypt сертификатами
|
||
- **Домен**: `[remot.dttb.ru](http://remot.dttb.ru)` уже настроен и работает (проброс TCP/UDP стримами на hbbs/hbbr)
|
||
- **NetBird VPN-mesh** между площадками для админ-доступа
|
||
- **DNS** управляется через Cloudflare
|
||
- Клиенты RustDesk развёрнуты на ~30-50 машинах (НИИКН + несколько клиентских организаций)
|
||
|
||
## Цель
|
||
|
||
Мигрировать с базового RustDesk OSS Server на **stack от lejianwen** (https://github.com/lejianwen/rustdesk-api + парный rustdesk-server-s6) для получения:
|
||
|
||
1. **Жёсткой изоляции клиентов** через `MUST_LOGIN=Y` — техник Клиента-А не должен иметь возможности подключиться к машинам Клиента-Б даже зная ID и пароль
|
||
2. **Адресных книг и групп** — каждый техник видит только свои устройства
|
||
3. **Аудит-логов** (login, connection, file_transfer)
|
||
4. **All-In-HTTPS+WebSocket** архитектуры — весь трафик через 443/HTTPS, чтобы работать из-за корпоративных фаерволов клиентов
|
||
5. **REST API + Swagger** для автоматизации через Claude Code и потенциальную MCP-интеграцию
|
||
|
||
**Критическое требование**: миграция должна сохранить существующий ключ сервера (`id_ed25519` / `id_[ed25519.pub](http://ed25519.pub)`), чтобы клиенты на местах продолжили работать без перенастройки. Это нужно проверить отдельно — НИ В КОЕМ СЛУЧАЕ не генерировать новый ключ, не удалять старый.
|
||
|
||
## Задачи
|
||
|
||
### Фаза 1: Аудит и подготовка
|
||
|
||
1. Подключись к Proxmox-хосту по SSH (узнай адрес у меня если нет в `~/.ssh/config`).
|
||
2. Найди LXC-контейнер с текущим RustDesk Server. Подскажи команду `pct list` и `pct config <id>` чтобы я понял какой именно.
|
||
3. **Проверь и зафиксируй**:
|
||
- Точный путь к `/data/rustdesk/server/` (где лежат `id_ed25519` и `id_[ed25519.pub](http://ed25519.pub)`)
|
||
- Содержимое текущего `compose.yml` или `docker run` параметров hbbs/hbbr
|
||
- Какие порты сейчас слушает hbbs (`ss -tulpn | grep -E '2111[4-9]'`)
|
||
- Версию текущего OSS-сервера
|
||
- Размер БД (если есть `db_v2.sqlite3`)
|
||
4. **Сделай полный бэкап** перед любыми изменениями:
|
||
- `tar` всей директории `/data/rustdesk/`
|
||
- Сохрани бэкап в `/root/rustdesk-backup-YYYYMMDD-HHMM.tar.gz`
|
||
- Дополнительно скопируй `id_ed25519*` отдельно в `/root/rustdesk-keys-backup/`
|
||
5. Покажи мне план действий и ЖДИ моего подтверждения перед фазой 2.
|
||
|
||
### Фаза 2: Развёртывание lejianwen stack
|
||
|
||
6. Останови текущий контейнер (`docker compose down` в текущей директории), но **не удаляй** ни том с ключами, ни саму директорию.
|
||
7. Создай новую директорию для нового стека: `/opt/rustdesk-lejianwen/` с подкаталогами `data/api/` и оставь существующий `/data/rustdesk/server/` нетронутым (новый стек будет смонтирован на него).
|
||
8. Сгенерируй случайный JWT-ключ длиной 32+ символов: `openssl rand -base64 48`. Сохрани его в файл `/opt/rustdesk-lejianwen/.env` с переменной `JWT_KEY=...`. Покажи мне, я сохраню его в свою password-store.
|
||
9. Создай `/opt/rustdesk-lejianwen/compose.yml` со следующим содержимым (проверь актуальный формат env-переменных в README — он мог обновиться):
|
||
|
||
```yaml
|
||
networks:
|
||
rustdesk-net:
|
||
external: false
|
||
|
||
services:
|
||
rustdesk:
|
||
image: lejianwen/rustdesk-server-s6:latest
|
||
container_name: rustdesk
|
||
environment:
|
||
- RELAY=remot.dttb.ru:21117
|
||
- ENCRYPTED_ONLY=1
|
||
- MUST_LOGIN=Y
|
||
- TZ=Europe/Moscow
|
||
- RUSTDESK_API_LANG=ru
|
||
- RUSTDESK_API_RUSTDESK_ID_SERVER=remot.dttb.ru:21116
|
||
- RUSTDESK_API_RUSTDESK_RELAY_SERVER=remot.dttb.ru:21117
|
||
- RUSTDESK_API_RUSTDESK_API_SERVER=https://remot.dttb.ru
|
||
- RUSTDESK_API_RUSTDESK_KEY_FILE=/data/id_[ed25519.pub](http://ed25519.pub)
|
||
- RUSTDESK_API_JWT_KEY=${JWT_KEY}
|
||
- RUSTDESK_API_APP_REGISTER=false
|
||
- RUSTDESK_API_APP_DISABLE_PWD_LOGIN=false
|
||
- RUSTDESK_API_APP_CAPTCHA_THRESHOLD=3
|
||
- RUSTDESK_API_APP_BAN_THRESHOLD=5
|
||
- RUSTDESK_API_ADMIN_TITLE=Remote Support Portal
|
||
volumes:
|
||
- /data/rustdesk/server:/data
|
||
- /opt/rustdesk-lejianwen/data/api:/app/data
|
||
networks:
|
||
- rustdesk-net
|
||
ports:
|
||
- "21114:21114"
|
||
- "21115:21115"
|
||
- "21116:21116"
|
||
- "21116:21116/udp"
|
||
- "21117:21117"
|
||
- "21118:21118"
|
||
- "21119:21119"
|
||
restart: unless-stopped
|
||
```
|
||
|
||
10. **Перед запуском убедись**:
|
||
- Файлы `/data/rustdesk/server/id_ed25519` и `id_[ed25519.pub](http://ed25519.pub)` существуют и не пустые
|
||
- Контейнер не будет генерировать новый ключ (если в логах после старта появится "generating new key" — это критическая ошибка, останавливай немедленно)
|
||
11. Запусти `docker compose up -d`, отслеживай логи: `docker compose logs -f rustdesk`. В логах должен появиться сгенерированный пароль `admin` — поймай его и сохрани в `/root/rustdesk-admin-initial-password.txt` с правами 600.
|
||
12. **Проверь работоспособность**:
|
||
- `curl -I http://localhost:21114/_admin/` — должен вернуть 200 или 301
|
||
- `curl http://localhost:21114/api/heartbeat` (если такой endpoint есть, иначе пропусти)
|
||
- `ss -tulpn | grep -E '2111[4-9]'` — все порты должны слушаться
|
||
- **Сравни `/data/rustdesk/server/id_[ed25519.pub](http://ed25519.pub)` с бэкапом** — должен быть идентичен. Если отличается — стоп, ключ перегенерировался, нужен rollback.
|
||
|
||
### Фаза 3: Настройка Nginx Proxy Manager
|
||
|
||
13. Подключись к LXC с NPM (или используй его API). Найди существующий Proxy Host для `[remot.dttb.ru](http://remot.dttb.ru)` (или Stream-секции).
|
||
14. **Текущая конфигурация со Stream'ами для портов 21115-21119 должна остаться** — это для совместимости со старыми клиентами без WebSocket.
|
||
15. **Обнови** Proxy Host для `[remot.dttb.ru](http://remot.dttb.ru)`:
|
||
- Forward Hostname: IP нового LXC с lejianwen-stack
|
||
- Forward Port: `21114`
|
||
- WebSocket Support: включить
|
||
- Block Common Exploits: включить
|
||
- SSL: уже должен быть Let's Encrypt, проверь что Force SSL и HTTP/2 включены
|
||
16. В **Advanced → Custom Nginx Configuration** добавь:
|
||
|
||
```nginx
|
||
location /ws/id {
|
||
proxy_pass http://IP_LXC:21118;
|
||
proxy_http_version 1.1;
|
||
proxy_set_header Upgrade $http_upgrade;
|
||
proxy_set_header Connection "Upgrade";
|
||
proxy_set_header Host $host;
|
||
proxy_set_header X-Real-IP $remote_addr;
|
||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||
proxy_set_header X-Forwarded-Proto $scheme;
|
||
proxy_read_timeout 86400s;
|
||
proxy_send_timeout 86400s;
|
||
}
|
||
|
||
location /ws/relay {
|
||
proxy_pass http://IP_LXC:21119;
|
||
proxy_http_version 1.1;
|
||
proxy_set_header Upgrade $http_upgrade;
|
||
proxy_set_header Connection "Upgrade";
|
||
proxy_set_header Host $host;
|
||
proxy_set_header X-Real-IP $remote_addr;
|
||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||
proxy_set_header X-Forwarded-Proto $scheme;
|
||
proxy_read_timeout 86400s;
|
||
proxy_send_timeout 86400s;
|
||
}
|
||
```
|
||
|
||
(подставь реальный IP LXC вместо IP_LXC)
|
||
|
||
17. Проверь `nginx -t` внутри контейнера NPM, перезагрузи если ОК.
|
||
18. С внешней машины (попроси меня проверить или используй curl с другого хоста через NetBird):
|
||
- `curl -I https://remot.dttb.ru/_admin/` — должно отвечать 200/301
|
||
- `curl -I https://remot.dttb.ru/swagger/index.html` — Swagger доступен
|
||
|
||
### Фаза 4: Первичная настройка через web-консоль
|
||
|
||
19. Открой `https://remot.dttb.ru/_admin/`, залогинься admin / `<пароль из /root/rustdesk-admin-initial-password.txt>`.
|
||
20. Помоги мне сменить пароль admin'а (через `docker exec rustdesk ./apimain reset-admin-pwd <новый_пароль>` или через UI).
|
||
21. Создай начальную структуру (если возможно через API/CLI — сделай скриптом):
|
||
|
||
**Группы (shared):**
|
||
- `НИИКН-парк`
|
||
- `Клиент-template` (как образец, потом дублировать)
|
||
|
||
**Тестовые пользователи:**
|
||
- `niikn-admin` (полные права на группу НИИКН)
|
||
- `niikn-tech1` (только подключение)
|
||
- `test-client` (для проверки изоляции)
|
||
|
||
22. Создай шаблон `RustDesk2.toml` для клиентов:
|
||
|
||
```toml
|
||
rendezvous_server = 'remot.dttb.ru:21116'
|
||
nat_type = 1
|
||
serial = 1
|
||
|
||
[options]
|
||
custom-rendezvous-server = '[remot.dttb.ru](http://remot.dttb.ru)'
|
||
relay-server = '[remot.dttb.ru](http://remot.dttb.ru)'
|
||
api-server = 'https://remot.dttb.ru'
|
||
key = '<СЮДА_ПОДСТАВЬ_СОДЕРЖИМОЕ_id_[ed25519.pub](http://ed25519.pub)>'
|
||
allow-websocket = 'Y'
|
||
verification-method = 'use-permanent-password'
|
||
approve-mode = 'password'
|
||
```
|
||
|
||
Прочитай актуальный публичный ключ из `/data/rustdesk/server/id_[ed25519.pub](http://ed25519.pub)`, подставь в шаблон. Сохрани готовый файл в `/root/RustDesk2.toml.template`.
|
||
|
||
### Фаза 5: Тестирование и rollback-план
|
||
|
||
23. Подними тестовый клиент (можешь использовать docker `rustdesk/rustdesk` или попросить меня запустить на тестовой машине). Проверь:
|
||
- Подключение к серверу проходит
|
||
- Без логина соединение **не устанавливается** (это ключевая проверка MUST_LOGIN)
|
||
- С логином `niikn-tech1` доступны только машины из его адресной книги
|
||
- С логином `test-client` машины НИИКН не видны и подключение к ним по ID отклоняется
|
||
|
||
24. **Подготовь rollback-скрипт** на случай провала: `/root/[rustdesk-rollback.sh](http://rustdesk-rollback.sh)`, который:
|
||
- Останавливает новый стек: `cd /opt/rustdesk-lejianwen && docker compose down`
|
||
- Восстанавливает из бэкапа `/root/rustdesk-backup-*.tar.gz`
|
||
- Поднимает старый OSS: возвращается в его директорию и `docker compose up -d`
|
||
- В NPM возвращает старую конфигурацию (тут лучше через бэкап настроек NPM `/data/database.sqlite` если NPM запущен в Docker)
|
||
|
||
25. Сделай финальный отчёт в `/root/[rustdesk-migration-report.md](http://rustdesk-migration-report.md)` со всем что сделано: пути, IP, пароли (хеши), команды для дальнейшего обслуживания, известные проблемы.
|
||
|
||
## Что важно соблюдать
|
||
|
||
- **Действуй пошагово**, после каждой фазы дожидайся моего подтверждения. Не уходи в Фазу 3 без ОК на Фазу 2.
|
||
- **Не удаляй ничего** до успешного теста новой системы. Старый OSS-стек должен оставаться на диске минимум 7 дней.
|
||
- **При любой ошибке с ключом сервера** (`id_[ed25519.pub](http://ed25519.pub)` изменился, hbbs его перегенерировал, не подхватил из volume) — немедленный stop и rollback. Это самый критичный риск всей миграции.
|
||
- Если что-то непонятно в моей инфраструктуре — спрашивай, не предполагай. Например, точный IP контейнеров, реальные пути в моём compose, версии Docker.
|
||
- Команды, требующие sudo, обязательно объясни перед запуском.
|
||
- **Не выкладывай в логи и не сохраняй в git** значения `JWT_KEY`, паролей и публичный домен в открытом виде в файлах, которые могут быть закоммичены.
|
||
- Всё, что меняется в системе, должно быть idempotent или иметь rollback. Никаких `rm -rf` без бэкапа на соседнем диске или площадке.
|
||
|
||
## Что НЕ делать
|
||
|
||
- НЕ переходить сразу на MySQL-схему с репликацией — это будет отдельная задача после стабилизации базового стека на SQLite
|
||
- НЕ настраивать LDAP/OIDC до того, как обычный логин/пароль протестирован и работает
|
||
- НЕ обновлять клиенты RustDesk на местах (это я делаю отдельно через свои существующие GPO/скрипты)
|
||
- НЕ трогать существующие VPN-конфигурации (NetBird, AmneziaVPN и прочее)
|
||
- НЕ менять DNS-записи в Cloudflare без моего явного согласия
|
||
- НЕ публиковать `_admin` интерфейс без аутентификации, не открывать его из публичного интернета без проверки fail2ban / bantreshold
|
||
|
||
## После завершения
|
||
|
||
Когда всё работает и протестировано, отдельной задачей мы:
|
||
1. Раскатаем новый `RustDesk2.toml` на парк через GPO/скрипт
|
||
2. Заведём полную структуру клиентских групп
|
||
3. Настроим бэкапы БД API + ключей на ArtLeon (cron + rsync через NetBird)
|
||
4. Поднимем второй экземпляр на НИИКН Proxmox с общей MySQL для отказоустойчивости
|
||
5. Напишем MCP-обёртку поверх Swagger API для работы из Claude Code
|
||
|
||
Начинай с Фазы 1, фиксируй всё в `/root/[rustdesk-migration-report.md](http://rustdesk-migration-report.md)` по ходу.
|
||
|
||
## Итог (последний ответ Claude, до 500 симв.)
|
||
|
||
**A1.**
|
||
|
||
Почему именно A1:
|
||
- A2 не закрывает твою главную задачу из промта (изоляция Клиента-А от Клиента-Б). Тогда вся миграция теряет смысл.
|
||
- A3 (Docker s6) технически правильнее, но *сейчас* — overkill: LXC 2G диск, Docker не стоит, надо расширять rootfs, ставить Docker, делать compose, переносить БД, тестировать миграцию схемы. Это половина дня работы и больше точек отказа ради того же результата.
|
||
- A1 — три команды (`systemctl stop`, `cp` двух бинарей, `systemctl start`) поверх работающей
|
||
|
||
---
|
||
*Автосохранено из session [`6936f7cb`](file:///Users/ai/.claude/projects/-Users-ai-knowledge-base/6936f7cb-387a-4118-a3da-49367030abce.jsonl) — 3 сообщ., тулы: Bash, TodoWrite, ToolSearch*
|