Add a maintenance note: AGENTS.md is a living document and must be updated in the same commit whenever code/flags/structure/scripts change, and reconciled first whenever it diverges from the code.
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. Он делает всё сам и спрашивает только пароль:
run.bat
Что делает run.bat:
- Если
web-vnc.exeотсутствует — собирает его (нужен установленный Go). Если Go нет — подсказывает, что сделать. - Если noVNC-клиент ещё не встроен — пытается его скачать (нужен интернет). Без интернета продолжит работу, но в браузере будет страница-заглушка.
- Спрашивает пароль доступа.
- Генерирует из него хэш.
- Ищет VNC-сервер: если он не установлен — пытается скачать портативный
UltraVNC (
scripts\get-vnc.ps1) и запускать его. - Выводит список всех адресов для подключения (
http://localhost:8080иhttp://<каждый IPv4 машины>:8080) и запускает сервер с флагом--spawn.
После запуска откройте в браузере один из выведенных адресов, введите тот же пароль — и попадёте на рабочий стол.
Быстрый старт вручную (Windows)
# 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)
./scripts/get-novnc.sh
go build -o web-vnc ./cmd/web-vnc
hash=$(./web-vnc --gen-hash "ваш-пароль")
./web-vnc --password-hash "$hash" --spawn
Как это работает
- Пользователь открывает
http://хост:8080/и попадает на/login. - Вводит общий пароль. Он сверяется с солёным PBKDF2-HMAC-SHA256-хэшем (120 000 итераций). При успехе сервер ставит HMAC-подписанную, HttpOnly-куку сессии (по умолчанию 8 ч, без серверного хранилища).
- Браузер загружает
/vnc.html(только с валидной сессией). Клиент noVNC открывает WebSocket на/vnc. 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) |
Переопределить авто-поиск своей командой:
.\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-релея |
Сгенерировать хэш пароля
web-vnc --gen-hash "ваш-пароль"
# напечатает, например: pbkdf2-sha256$120000$<соль>$<ключ>
Формат самодокументируемый:
pbkdf2-sha256$<итерации>$<base64-соль>$<base64-ключ>.
Запуск одной строкой
.\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: установите UltraVNC или TightVNC, либо запустите
-
С другого компьютера страница не открывается (таймаут/недоступно). По умолчанию Windows Firewall блокирует входящие подключения. Один раз выполните от имени администратора:
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 запуск в один клик (спрашивает только пароль)
Кросс-компиляция под другую ОС
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.