Files
web-vnc/README.md
T
Codex 02fefa1e4e fix(autostart): run from repo root + visible console at logon
autostart-run.bat did 'cd /d %~dp0' -> scripts/, but web-vnc.exe/webvnc.conf/
go.mod live in the repo root, so the binary was never found and web-vnc never
started after reboot. Now it cd's to %~dp0.. (repo root).

The task was ONSTART/RU SYSTEM (session 0) so it could not show a window, making
failures invisible. install-autostart.bat now registers ONLOGON /RL HIGHEST as the
current user -> a visible console opens at logon. autostart-run.bat sets a window
title, prints status, stays open while web-vnc serves, and pauses on fatal errors
(no binary / no webvnc.conf) so the reason is visible. Docs updated.
2026-08-06 01:09:47 +03:00

242 lines
16 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` задание (`ONLOGON`, `HIGHEST`,
от имени текущего пользователя), которое **при входе в систему открывает видимую
консоль** с `scripts\autostart-run.bat` — launcher, читающий `webvnc.conf`, ждущий
`127.0.0.1:5900` до ~30 c и затем запускающий `web-vnc.exe` (не качает ничего на старте).
Окно остаётся, пока web-vnc работает; при ошибке — пауза, чтобы было видно причину.
Запуск от `SYSTEM`/`ONSTART` не используется: он в session 0 и окна не показывает.
Запустить сразу без перезагрузки: `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 ONLOGON/HIGHEST, видимая консоль) — от админа
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 автостарта (видимая консоль): cd в корень репо, читает webvnc.conf, ждёт 5900 до ~30 c, запускает web-vnc (без --spawn, если VNC уже слушает); pause на ошибке
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`.