Files
web-vnc/README.md
T
Codex 754f77a8d0 feat: autostart as a service + separate password setup (set-password.bat)
- set-password.bat: one-time password setup -> writes webvnc.conf (HASH + VNC_PASSWORD), syncs UltraVNC via ensure-vnc-password.ps1; if the 'web-vnc' task is installed, restarts it (elevated) to reload the new password, skipping restart when the password is unchanged.
- run.bat: no longer prompts for the password; reads it from webvnc.conf (asks to run set-password.bat first if absent). Also clears --spawn-command (not just --spawn) when 5900 is already listening, to avoid spawning a 2nd VNC server.
- scripts/autostart-run.bat: non-interactive launcher for the scheduled task (reads webvnc.conf, finds only a LOCAL VNC server, never downloads at boot).
- scripts/install-autostart.bat / uninstall-autostart.bat: register/remove a 'web-vnc' scheduled task (ONSTART, SYSTEM, HIGHEST) via schtasks.
- scripts/restart-autostart.bat: restart the task to apply a new password; checks whether web-vnc.exe is running (stop+start, or just start).
- .gitignore: ignore webvnc.conf (secret).
- AGENTS.md / README.md: document the autostart flow, set-password.bat, the new scripts, and that the running gateway must be restarted to apply a password change.
2026-08-05 15:23:58 +03:00

233 lines
15 KiB
Markdown
Raw 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.
# web-vnc
Один бинарник, который открывает доступ к рабочему столу (VNC) через браузер
(noVNC) с защитой по **паролю**. Программа `web-vnc`:
- раздаёт HTML5-клиент noVNC,
- пускает зрителя по общему паролю,
- прокидывает WebSocket браузера к локальному VNC-серверу (RFB поверх WS),
- и (по желанию) сама запускает VNC-сервер.
Написано на чистом Go, **только стандартная библиотека** — никаких внешних
Go-модулей, собирается офлайн.
```
Браузер (noVNC) ──ws──▶ web-vnc (один бинарник) ──tcp RFB──▶ VNC-сервер (127.0.0.1:5900)
├─ вход по паролю (PBKDF2-HMAC-SHA256)
├─ HMAC session-cookie
└─ прозрачный релей WS↔TCP
```
## Самый простой запуск (Windows)
Запуск состоит из двух шагов: один раз задаётся пароль, затем `run.bat` поднимает
gateway без запросов.
1. **Один раз** задайте пароль:
```bat
set-password.bat
```
Спросит пароль доступа, синхронизирует им пароль UltraVNC-сервиса
(`scripts\ensure-vnc-password.ps1`, UAC только при смене), сгенерирует хэш и
сохранит его вместе с паролем в `webvnc.conf` (секрет, в git не коммитится).
Используйте ASCII-пароль длиной до 8 символов (VNC-пароль = первые 8 байт).
2. **Запустите gateway**:
```bat
run.bat
```
`run.bat` собирает `web-vnc.exe` (нужен Go, если бинарника нет), встраивает
noVNC-клиент (качает при наличии интернета), находит/докачивает VNC-сервер,
читает пароль из `webvnc.conf` (больше не спрашивает), печатает адреса
(`http://localhost:8080` и `http://<каждый IPv4 машины>:8080`) и запускает
сервер с флагом `--spawn`. Если `127.0.0.1:5900` уже слушает (сервис UltraVNC) —
запускается без `--spawn`, подключаясь к существующему серверу.
После запуска откройте в браузере один из выведенных адресов,
введите тот же пароль — и попадёте на рабочий стол.
### Автостарт при загрузке ОС (вместо ручного `run.bat`)
```bat
set-password.bat :: один раз: пароль -> webvnc.conf
scripts\install-autostart.bat :: один раз (от админа): плановое задание «web-vnc»
```
`install-autostart.bat` регистрирует через `schtasks` задание (`ONSTART`, `SYSTEM`,
`HIGHEST`), которое при загрузке запускает `scripts\autostart-run.bat` —
неинтерактивный launcher, читающий `webvnc.conf` и не качающий ничего на старте.
Запустить сразу без перезагрузки: `schtasks /Run /TN "web-vnc"`.
Снять автостарт: `scripts\uninstall-autostart.bat` (от админа).
**Смена пароля:** `web-vnc.exe` читает пароль из `webvnc.conf` только при старте и не
перечитывает его в runtime. Поэтому `set-password.bat` (если задание «web-vnc» установлено)
перезапускает его через `scripts\restart-autostart.bat` (с elevation) — тот проверяет,
запущен ли `web-vnc.exe` (если да — стоп + старт, если нет — только старт). Рестарт
пропускается, если пароль не изменился. Для интерактивного `run.bat` просто перезапустите
его вручную.
## Быстрый старт вручную (Windows)
```powershell
# 1. Подтянуть noVNC-клиент во встроенную статику (один раз)
.\scripts\get-novnc.ps1
# 2. Собрать бинарник
go build -o web-vnc.exe .\cmd\web-vnc
# 3. Сгенерировать хэш пароля
$hash = .\web-vnc.exe --gen-hash "ваш-пароль"
# 4. Запустить (сам найдёт/запустит VNC-сервер и поднимется на :8080)
.\web-vnc.exe --password-hash $hash --spawn
```
## Быстрый старт (Linux / macOS)
```bash
./scripts/get-novnc.sh
go build -o web-vnc ./cmd/web-vnc
hash=$(./web-vnc --gen-hash "ваш-пароль")
./web-vnc --password-hash "$hash" --spawn
```
## Как это работает
1. Пользователь открывает `http://хост:8080/` и попадает на `/login`.
2. Вводит общий пароль. Он сверяется с **солёным PBKDF2-HMAC-SHA256**-хэшем
(120 000 итераций). При успехе сервер ставит **HMAC-подписанную,
HttpOnly**-куку сессии (по умолчанию 8 ч, без серверного хранилища).
3. Браузер загружает `/vnc.html` (только с валидной сессией). Клиент noVNC
открывает WebSocket на `/vnc`.
4. `web-vnc` проверяет сессию **до** апгрейда WebSocket и затем прозрачно
релеит байты между WebSocket и локальным VNC-сервером
(`127.0.0.1:5900` по умолчанию). RFB-протокол проходит нетронутым,
как у `websockify`.
> VNC-сервер должен слушать на **loopback (127.0.0.1)** и может работать
> **без VNC-пароля** — защита по паролю теперь на веб-гейтвее. Если же ваш
> VNC-сервер требует свой пароль, noVNC спросит и его.
## Авто-запуск VNC-сервера (`--spawn`)
С `--spawn` программа ищет установленный VNC-сервер и запускает его как
дочерний процесс (отдельно, без окна на Windows), после чего подключается к нему.
| ОС | Что ищет |
|---------|-------------------------------------------------------|
| Windows | UltraVNC (`winvnc.exe`), TightVNC (`tvnserver.exe`) |
| Linux | `x11vnc`, `tigervncserver` / `Xvnc` |
| macOS | встроенный Screen Sharing (`kickstart`) |
Переопределить авто-поиск своей командой:
```powershell
.\web-vnc.exe --password-hash $hash --spawn-command "C:\Path\To\winvnc.exe -run"
```
Без `--spawn` убедитесь, что VNC-сервер уже слушает по адресу из `--vnc`.
## Настройка
Все флаги дублируются переменными окружения (`WEBVNC_*`).
| Флаг | Env | По умолчанию | Описание |
|--------------------|---------------------------|--------------------|------------------------------------------------|
| `--listen` | `WEBVNC_LISTEN` | `:8080` | адрес HTTP/WS |
| `--vnc` | `WEBVNC_VNC` | `127.0.0.1:5900` | адрес вышестоящего VNC-сервера |
| `--password-hash` | `WEBVNC_PASSWORD_HASH` | (обязателен) | хэш PBKDF2 из `--gen-hash` |
| `--session-secret` | `WEBVNC_SESSION_SECRET` | случайный при старте | HMAC-ключ для подписи куки сессии |
| `--session-ttl` | `WEBVNC_SESSION_TTL` | `8h` | время жизни куки сессии |
| `--spawn` | `WEBVNC_SPAWN` | false | авто-запуск найденного VNC-сервера |
| `--spawn-command` | `WEBVNC_SPAWN_COMMAND` | (нет) | явная команда запуска VNC-сервера |
| `--web-root` | `WEBVNC_WEB_ROOT` | (встроенные) | раздавать статику с диска вместо embed |
| `--novnc-path` | | `/vnc.html` | путь страницы noVNC-клиента |
| `--relay-path` | | `/vnc` | endpoint WebSocket-релея |
### Сгенерировать хэш пароля
```bash
web-vnc --gen-hash "ваш-пароль"
# напечатает, например: pbkdf2-sha256$120000$<соль>$<ключ>
```
Формат самодокументируемый:
`pbkdf2-sha256$<итерации>$<base64-соль>$<base64-ключ>`.
### Запуск одной строкой
```powershell
.\web-vnc.exe --password-hash (. \web-vnc.exe --gen-hash "secret") --spawn
```
## Безопасность
- **Без TLS**: рассчитано на **приватную сеть**. Если выставляете наружу —
поставьте перед ним reverse-proxy с TLS (nginx/caddy).
- Логин с лимитом попыток (5 в минуту на IP, в памяти).
- Кука сессии подписана `--session-secret`. Задайте фиксированный
`--session-secret`, чтобы сессии переживали перезапуск (иначе секрет
меняется при каждом старте, и старые сессии инвалидируются).
- VNC-сервер держите на `127.0.0.1`, чтобы до него нельзя было достучаться
в обход гейтвея.
## Устранение неполадок
- **После ввода пароля — ошибка / нет картинки.**
Значит, веб-гейтвей не смог подключиться к VNC-серверу (по адресу `--vnc`,
по умолчанию `127.0.0.1:5900`). На странице теперь показывается понятное
сообщение вместо криптографической ошибки noVNC.
Решение: должен работать VNC-сервер, который отдаёт рабочий стол:
- Windows: установите **UltraVNC** или **TightVNC**, либо запустите
`scripts\get-vnc.ps1` (скачает портативный UltraVNC в папку `vnc\`, и
`run.bat` сам его запустит).
- Linux: `x11vnc` или `TigerVNC`.
- macOS: встроенный Screen Sharing.
Важно: VNC-сервер должен слушать на `127.0.0.1:5900`. На Windows для захвата
экрана может потребоваться запуск от имени администратора (UAC).
- **С другого компьютера страница не открывается (таймаут/недоступно).**
По умолчанию Windows Firewall блокирует входящие подключения. Один раз
выполните от имени администратора:
```bat
scripts\open-firewall.bat
```
Это откроет входящий TCP-порт 8080. (`run.bat` выводит адреса и подсказку.)
- **noVNC-клиент не встроен (страница-заглушка).**
Запустите `scripts\get-novnc.ps1` (нужен интернет), пересоберите и перезапустите.
## Структура проекта
```
cmd/web-vnc/main.go точка входа CLI: флаги, спавн VNC, запуск сервера
internal/config конфигурация (флаги + env)
internal/auth хэш пароля PBKDF2, HMAC-куки сессии, rate-limit
internal/relay WebSocket на stdlib (RFC 6455) + мост WS↔TCP
internal/vncspawner кросс-ОС поиск и запуск VNC-сервера
internal/server HTTP-роуты, middleware сессии, встроенная статика
internal/server/static встроенные веб-ассеты (vnc.html + core/app/vendor noVNC)
scripts/get-novnc.{ps1,sh} скачать noVNC во встроенную статику
scripts/get-vnc.ps1 скачать портативный VNC-сервер (UltraVNC) в папку vnc/
scripts/list-ips.ps1 список IPv4 машины (используется run.bat)
scripts/open-firewall.bat открыть порт 8080 в Windows Firewall (один раз, от админа)
run.bat интерактивный запуск: собирает бинарник/noVNC/VNC, читает пароль из webvnc.conf (не спрашивает)
set-password.bat разовая настройка пароля -> webvnc.conf (хэш + VNC-пароль); синхронизирует UltraVNC
webvnc.conf секрет: HASH= + VNC_PASSWORD= (создаётся set-password.bat, gitignored)
scripts/autostart-run.bat неинтерактивный launcher для автостарта (читает webvnc.conf)
scripts/install-autostart.bat автостарт при загрузке ОС (schtasks ONSTART/SYSTEM) — от админа
scripts/uninstall-autostart.bat снять автостарт — от админа
scripts/restart-autostart.bat перезапустить задание «web-vnc» (чтобы применить новый пароль) — от админа
```
## Кросс-компиляция под другую ОС
```bash
GOOS=linux GOARCH=amd64 go build -o web-vnc-linux ./cmd/web-vnc
GOOS=windows GOARCH=amd64 go build -o web-vnc.exe ./cmd/web-vnc
GOOS=darwin GOARCH=arm64 go build -o web-vnc-macos ./cmd/web-vnc
```
## Лицензия
MIT. Встроенные ассеты noVNC сохраняют свою лицензию (MPL-2.0) —
см. `internal/server/static/LICENSE` после запуска `get-novnc`.