Files
web-vnc/README.md
T
Codex f315618bfc fix(autostart): wait for the VNC server before starting web-vnc
autostart-run.bat checked 5900 once at startup; at boot the UltraVNC service may
not be up yet, so web-vnc either spawned a 2nd VNC server (conflict) or started
serving on :8080 before the VNC server was ready, breaking browser connections.

Now autostart-run.bat polls 127.0.0.1:5900 for up to ~30s (one PowerShell loop:
TcpClient + Start-Sleep 1, exits on first accepted connection) and only then
launches web-vnc.exe -- without --spawn when 5900 already listens, or spawning a
local server (portable vnc\winvnc.exe / tvnserver.exe, else auto-detect) if it
never came up. Docs (AGENTS.md, README.md) updated.
2026-08-05 16:14:39 +03:00

239 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
```
Спросит пароль доступа, сгенерирует хэш и сохранит его вместе с паролем в
`webvnc.conf` (секрет, в git не коммитится), а затем синхронизирует им пароль
UltraVNC-сервиса (`scripts\ensure-vnc-password.ps1`, UAC только при смене).
Веб-пароль оказывается настроен, даже если синк UltraVNC упадёт или UAC отменят.
Используйте 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
install-autostart.bat :: один раз (от админа): плановое задание «web-vnc»
```
`install-autostart.bat` регистрирует через `schtasks` задание (`ONSTART`, `SYSTEM`,
`HIGHEST`), которое при загрузке запускает `scripts\autostart-run.bat` —
неинтерактивный launcher, читающий `webvnc.conf` и не качающий ничего на старте.
Запустить сразу без перезагрузки: `schtasks /Run /TN "web-vnc"`.
Снять автостарт: `uninstall-autostart.bat` (от админа).
**Смена пароля:** `web-vnc.exe` читает пароль из `webvnc.conf` только при старте и не
перечитывает его в runtime. Поэтому `set-password.bat` (если задание «web-vnc» установлено)
перезапускает его через `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
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)
Пользовательские точки входа — в корне репозитория:
run.bat интерактивный запуск: собирает бинарник/noVNC/VNC, читает пароль из webvnc.conf (не спрашивает)
set-password.bat разовая настройка пароля -> webvnc.conf (хэш + VNC-пароль); синхронизирует UltraVNC
install-autostart.bat автостарт при загрузке ОС (schtasks ONSTART/SYSTEM) — от админа
uninstall-autostart.bat снять автостарт — от админа
restart-autostart.bat перезапустить задание «web-vnc» (чтобы применить новый пароль) — от админа
open-firewall.bat открыть порт 8080 в Windows Firewall (один раз, от админа)
webvnc.conf секрет: HASH= + VNC_PASSWORD= (создаётся set-password.bat, gitignored)
Внутренние помощники — в scripts/ (вызываются другими скриптами):
scripts/autostart-run.bat неинтерактивный launcher для автостарта: читает webvnc.conf, ждёт 5900 до ~30 c, затем запускает web-vnc (без --spawn, если VNC уже слушает)
scripts/ensure-vnc-password.ps1 синхронизирует VNC-пароль UltraVNC (вызывается из set-password.bat)
scripts/get-novnc.{ps1,sh} скачать noVNC во встроенную статику
scripts/get-vnc.ps1 скачать портативный VNC-сервер (UltraVNC) в папку vnc/
scripts/list-ips.ps1 список IPv4 машины (используется run.bat)
```
## Кросс-компиляция под другую ОС
```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`.