Debian.pro

Про Debian


Запускаем один NoVNC для доступа к нескольким VNC. Например, к консолям KVM-виртуалок.

Статью пишу «по памяти», воспроизвести вживую негде (да и лень).
Если найдете ошибки и что-то не заработает — обязательно пишите.
Я бы пока не рассматривал эту статью, как решение из разряда «copy-paste и работает».
Но если вы понимаете происходящее ниже — то никакой проблемы запустить эту штуку нет, там всё банально.
Ценность здесь, скорее, именно в самой идее использования novnc и том, что гуглить придётся на 20 минут меньше.



Думаю, все помнят, что KVM позволяет смотреть в «экран» виртуальной машины через VNC (ну и кнопочки в туда нажимать). На «вручную» поднятых libvirt+kvm все это делают через локально установленный virsh или проброс порта vnc на локальный хост по ssh.
Эти способы, мягко говоря, не очень удобны. А главное — нельзя дать доступ к «экрану» (буду в дальнейшем использовать именно эту формулировку, чтобы не путать аббревиатуры KVM — keyboard/video/mouse и kernel virtual machine) одной виртуалки отдельному пользователю, не позволяя ходить в экраны других виртуалок. Если быть совсем точным, то нет _простого_ способа сделать это (из говна, палок, баша и кастомного скрипта в качестве шелла — можно, в принципе).
Вот тут на помощь и приходит NoVNC. Вообще эта штука — «браузерный VNC-клиент». На сервере крутится написанная на питоне фигулина, которая одним концом ходит в VNC (в нашем случае от kvm-виртуалок), а другим концом показывает позволяет пользователю зайти по http(s) и посмотреть в эту консоль (ну и кнопки понажимать да мышку подвигать). Подойдет для этого любой современный браузер. Даже с мобильника получится посмотреть (хотя кнопки как раз понажимать уже, скорее всего, не выйдет).
Ну а доступом по https, по давно уже сложившейся здесь традиции, мы будем рулить через nginx, который будет проксировать весь трафик от пользователя к novnc.
В принципе, ничего сложного в запуске NoVNC нет. Счекаутил из гита (не, ну можно пакет поставить, но там совсем старая версия), запустил, иди в host:6080 браузером. Но просто это только в том случае, если нам нужна одна консоль одной виртуалки. Когда у нас несколько пользователей, много виртуалок (а тем более, когда они по разным dom0-хостам разнесены) — то всё уже не так тривиально. Поэтому и родилась идея оформить статью на эту тему.
Собственно, секрет простой — нужно долго и внимательно читать документацию, дойдя до информации про опцию target-config у бинарника websockify/run в репозитории novnc. Но читать придётся достаточно долго =) Да и знать нужно, что искать. Поэтому погнали.

Первым делом нужно «прибить гвоздями» порты VNC всех виртуалок. Если вы используете libvirt, то все виртуалки по умолчанию создаются без указания конкретного порта для VNC. Первая запустившаяся виртуалка забирает себе 127.0.0.1:5900, а дальше все инкрементят порт. Виртуалки запускаются в случайно порядке. А NoVNC рассчитан всё же на статические порты (он-то бедненький ничего про виртуалки не знает, а знает только про порты).
Смотрим название своей машины в virsh list. Допустим, vds1 для примера. Запускаем редактирование конфига (именно этой командой, иначе потом изменения потрутся — ну и на всякий случай напомни, что из вима выйти с сохранением можно написав :wq):

root@server:~# virsh edit vds1

В xml-ке находим такую строчку:

<graphics type='vnc' port='-1' autoport='yes'/>

Меняем на что-то такое:

<graphics type='vnc' port='5910' autoport='yes'/>

Порт лучше взять чуть выше, чем 5900 (мало ли libvrit-у снесёт голову). Я беру порт 5900+максимально возможное количество виртуалок на хосте+единица. Себе другую логику придумайте. Ну или вообще берите порты вида 15900, это на самом деле не так важно.
После редактирования конфига виртуалку нужно целиком потушить. Не ребутнуть, а именно потушить. Если она не отключится сама halt-ом — придется сказать ей virsh destroy; virsh start. Пытался я virsh-ем на лету сменить порт после смены конфига, оно меня проигнорировало. Но, в целом, удалось сделать это из virt-manager (удалив VNC и добавив новый с явным указанием порта).
Далее подготавливаем nginx с https — раз, два, три. Передавать через голые интернеты рутовый пароль в VNC-трафике по http — точно не самая разумная затея (при этом по локалхосту у нас тоже будет https на всякий случай).
А теперь переходим к запуску, собственно, novnc.
Создаём пользователя:

root@server:~# adduser novnc

Ставим пакеты, которые в дальнейшем понадобятся для запуска кода:

root@server:~# apt-get install git-core python-numpy

Создаём каталог, в котором будет лежать исходники novnc (можно в целом и сам novnc поставить пакетом, но очень уж старая версия в репозиториях. Да и питонячий код там без особых зависимостей):

root@server:~# mkdir /usr/share/novnc

Клонируем репозиторий:

root@server:~# git clone https://github.com/novnc/noVNC.git /usr/share/novnc

Чоуним (там будут какие-то временные файлы, так что чоуним под novnc целиком. Лучше, конечно, посидеть поразбираться, в какие именно каталоги/файлы нужен доступ на запись пользователю novnc).

root@server:~# chown -R novnc:root /usr/share/novnc

Заводим каталог, в котором будут лежать секретные файлы для novnc:

root@server:~# mkdir /etc/novnc

Копируем сертификат nginx-а в каталог novnc (в статьях про nginx мы его положили именно сюда):

root@server:~# cp /etc/nginx/ssl/cert.pem /etc/novnc/cert.pem

Создаём файл /etc/novnc/tokens.list (о том, что писать в файл, поговорим чуть позже):

root@server:~# touch /etc/novnc/tokens.list

Чоуним каталог /etc/novnc и его содержимое. На этот раз только root может редактировать файлы, читать может группа novnc, а все остальные туда доступа иметь не должны.

root@server:~# chown -R root:novnc /etc/novnc
root@server:~# chmod -R 750 /etc/novnc
root@server:~# chmod -R 640 /etc/novnc/*

Пишем Unit для systemd (например, в /etc/systemd/system/novnc.service)

[Unit]
Description=NoVNC
After=network.target

[Service]
Type=simple
User=novnc
WorkingDirectory=/usr/share/novnc
ExecStart=/usr/share/novnc/utils/websockify/run --web /usr/share/novnc/ --target-config /etc/novnc/tokens.list 127.0.0.1:6080 --cert=/etc/novnc/cert.pem
Restart=on-abort

[Install]
WantedBy=multi-user.target

Собственно, вся магия статья в том, что я написал в ExecStart этого юнита (даже зная что искать, все нужные параметры найти сразу не удалось, не говоря уже о том, что пришлось немного покопаться в скриптах, чтобы понять, параметры которого нужно искать).
Теперь о том, что нужно написать в файл /etc/novnc/tokens.list. У меня он выглядит примерно так:

# vds1:
IPJASFAKHFOIASFOIHAOISFHOIAHSFOIHAOIHFOIAHF: 127.0.0.1:5910

# vds2:
IAHFPOAHFSPHAFSIHAFSHIAHFSOIHAOSFOIAHSFOIHA: 127.0.0.1:5911

Комментарии — просто для моего удобства. Часть до двоеточия — это некий токен (лучше без спецсимволов, дабы не заниматься сексом с url-escaping в дальнейшем, чем длиннее — тем лучше), часть после первого двоеточия — хост и порт VNC (это может быть не только локалхост, но будьте осторожнее. Openstack, например, в свои молодые годы доинтегрировался до того, что гонял этот самый трафик до VNC-консолей на dom0-железках от novnc-сервера в открытом виде), куда novnc будет подключаться, получив этот токен в аргументах.
Теперь можно запустить novnc, если вы ничего не пропустили:

root@server:~# service novnc start

Если вот такая команда:

root@server:~# lsof -i :6080

Говорит, что порт занят процессом python под пользователем novnc, то, скорее всего, всё хорошо. Если нет — то по ссылке выше про systemd написано, как почитать лог юнита, чтобы подебажить, почему оно не запустилось.
Осталось только аккуратненько вывесить novnc наружу.
Возвращаясь к изначальной идеей — nginx должен обеспечивать минимальную защиту (пусть это будет хотя бы basic auth), потому что ссылку могут случайно пошарить (или гугл её насканит как-то, по логам браузера-шпиона, например). Ну и было бы неплохо, чтобы для каждого токена/порта novnc можно было сделать отдельный набор логинов-паролей. Ну.. Nginx так умеет (уж простите, люблю я его всей душой).
В /etc/nginx/sites-available/novnc.conf или куда-то туда (симлинк потом сделать в sites-enabled не забудьте) пишем конфиг ниже. server_name берите тот, для которого получали сертификат.

# мапим наши novnc-токены в аргументы novnc из tokens.list:
map $arg_token $passwd_file {
    IPJASFAKHFOIASFOIHAOISFHOIAHSFOIHAOIHFOIAHF /etc/novnc/vds1.passwd;
    IAHFPOAHFSPHAFSIHAFSHIAHFSOIHAOSFOIAHSFOIHA /etc/novnc/vds2.passwd;
    # дефолтный файл для остальных токенов:
    default /etc/novnc/default.passwd;
}

# ниже конфиг самого server{} с novnc внутри.
server {
    # допустим, dom0.example.com у нас есть в сертификате.
    server_name dom0.example.com;

    # параметры для https (редирект с http сами сделайте. Или вообще http не слушайте).
    listen 443 ssl;

    ssl_certificate /etc/nginx/ssl/cert.pem;
    ssl_certificate_key /etc/nginx/ssl/cert.pem;
    ssl_dhparam /etc/nginx/ssl/dhparam.pem;
    ssl_prefer_server_ciphers on;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers kEECDH+AES128:kEECDH:kEDH:-3DES:kRSA+AES128:kEDH+3DES:DES-CBC3-SHA:!RC4:!aNULL:!eNULL:!MD5:!EXPORT:!LOW:!SEED:!CAMELLIA:!IDEA:!PSK:!SRP:!SSLv2;
    ssl_session_cache shared:SSL:64m;
    ssl_session_timeout 28h;

    # Авторизация http-basic auth. Путь до htpasswd файла - через переменную
    auth_basic "VNC";
    auth_basic_user_file $passwd_file;

    # проксируем обычные файлы в novnc (2 следующих location):
    location /vnc_lite.html {
        proxy_pass https://127.0.0.1:6080;
    }
    # честно - не помню, нахрена тут mp3 =)
    location ~* ^.+\.(css|js|png|svg|ttf|woff|oga|mp3)$ {
        proxy_pass https://127.0.0.1:6080;
    }
    # проксируем websocket /wss в novnc. Если ExecStart не меняли - то вот этот кусок как раз советую скопипастить.
    location /wss {
        proxy_http_version 1.1;
        proxy_pass https://127.0.0.1:6080/?token=$arg_token;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";

        # VNC connection timeout
        proxy_read_timeout 14400;
        proxy_send_timeout 14400;

        # Disable cache
        proxy_buffering off;
    }
}

Когда конфиг положите в правильное место — рестартьте nginx.
Только проверьте конструкцию с авторизацией — я это писал по памяти, может навскидку и не заработать.
Из открытых вопросов — какой url дать пользователю, чтобы он зашел в консоль? Вот такой:

https://dom0.example.com/vnc_lite.html?path=wss&token=TOKEN

Если всё настроено правильно — у него там спросят логин-пароль для https, а потом он увидит экран виртуалки.

Ну и для тех, кто просто посмотреть зашел. Скриншотик открытой консоли какой-то виртуалки в браузере (фуллсайз по клику).
NoVNC

ЗЫ — я знаю про поддержку WSS в самом QEMU, но собрать из них готовое решение, которое поместилось бы в формате одной статьи без кода не вышло. Ни в 2010-м, ни в 2018-м. Насколько я успел понять, она нужна для SPICE, который ничем не удобнее VNC внутри virsh.

Новость одной строкой — 1.1.1.1, новый публичный резолвер.

На фоне клёвых первоапрельских новостей многие могли пропустить весьма важную новость. Компания Cloudflare совместно с APNIC запустила новый публичный резолвер на адресе 1.1.1.1 Что вдвойне приятно — с поддержкой dns over TLS (то бишь запросы до этого резолвера можно шифровать). Так же есть поддержка DNS over HTTPS, но его использовать может пока только FireFox в [...]

seedbox на коленке: deluged+deluge-web

Всем хороша связка rtorrent+rutorrent. Только настраивать её очень уж геморрно, да и уязвимость там нашли, помнится. Я давно уже использую deluge. Да и вообще мне интерфейс deluge-web больше нравится — выглядит посовременнее, сам он читаемый, да и вообще «не PHP и ладненько». Поэтому сегодня и расскажу, как настроить связку из deluged и родного вебинтерфейса к [...]

Пишем свой unit для SystemD

В некоторых следующих статьях помимо прочего придется запускать некоторые сервисы без «изкоробочного» init-скрипта или юнита. В 2018 году мне уже пришлось смириться с победой systemd и показывать в тех статьях init-скрипты я уже не буду. Но и рассказывать в каждой статье всю последовательность действий мне будет лень. Поэтому здесь я расскажу, что делать с unit-ом [...]

Скрипт для проверки локалхоста на spectre/meltdown

Сижу я в один прекрасный день, значит, смотрю на свою LTS-убунту на ноутбучке и понимаю, что несмотря на apt-get upgrade, сделанный полчаса назад, она всё ещё уязвима к spectre (не спрашивайте как, просто жопой почуял). Про сами уязвимости в процах, думаю, рассказывать в сотый раз не стоит, а вот про то, как linux-хост проверить на [...]

Unbound: локальный резолвер на сервере — честный, с форвардингом и с зашифрованным форвардингом.

Для начала поговорим о том, для чего нужен локальный dns-резолвер. Вообще, полезен он и на сервере, и на вашем ноутбучке (только для разного, пожалуй), а написать эту статью меня вынудил именно новый провайдер (самизнаетепочему). Локальный резолвер позволяет получать мгновенный ответ от dns (кроме случая, когда мы впервые спрашиваем определенную запись). Резолверы провайдера/хостера бывают перегружены, запрос [...]

Настраиваем FTP-сервер. Издание второе, улучшенное и дополненное: vsftpd.

Одной из первых статей в этом блоге была статья Debian, ftpd, vtpd, vsftpd. Very fast way. Восемь, мать его, лет назад! Собственно, по той статье некоторое время назад настроить vsftpd в дебиане стало невозможно. Поэтому я решил написать новую. Формально статья могла бы стать одной из частей Большого мануала, но я очень не хочу, чтобы [...]

Большой мануал: часть 24. Боремся с вирусней на сайтах.

Эта статья — часть Большого Мануала по настройке lamp-сервера на debian. Предыдущая часть цикла — Делаем бэкапы. Следующая часть цикла — Not yet published Дисклеймер: статья очень нужная, но мне пришлось буквально выдавливать её из себя, вышло совсем не интересно. У меня не очень много опыта в чистке от вирусни (обычно есть бэкапы/CVS или проще [...]

Новогоднее нытьё: Вавилонская башня дветысячидесятых.

Каждый новый год я пишу пост с каким-нибудь нытьём о том, что «раньше была трава зеленее». В этом году пост будет не очень длинным, но об очень заебавшем вотпрямщас. Когда-то давным давно какой-то умный человек написал первый instant messenger. Он сильно упростил общение в сети, сделал возможным «неформальное» общение (ведь в почте был свой этикет) [...]