tuna ❤️ JetKVM
JetKVM — это компактное IP-KVM устройство на базе Rockchip RV1106 (ARM Cortex-A7). Оно позволяет удалённо управлять компьютером: видеть экран, управлять клавиатурой и мышью, монтировать образы дисков — всё через веб-интерфейс в браузере.
По умолчанию JetKVM доступен только в локальной сети. С помощью Tuna вы можете открыть доступ к нему через интернет — без «белого» IP, без VPN, без проброса портов на роутере.
Данная инструкция протестирована на JetKVM с системной версией v0.2.7 и выше. На более ранних версиях /userdata/init.d/ не поддерживается — обновите JetKVM через веб-интерфейс (Settings → Device → Check for updates).
Подготовка
Помимо установки инструкция по настройке разделена на 2 типа, в зависимости от наличия платной подписки Tuna.
Что потребуется
- JetKVM с системной версией v0.2.7 или новее
- Developer Mode включен в веб-интерфейсе JetKVM (Settings → Advanced → Developer Mode)
- SSH-ключ добавлен через веб-интерфейс JetKVM
- Аккаунт на tuna.am (бесплатный или с подпиской)
- Токен авторизации со страницы токена
Особенности системы JetKVM
JetKVM работает на кастомной embedded Linux (Buildroot + Rockchip SDK). Важные отличия от обычного Linux:
| Особенность | Значение |
|---|---|
| Оболочка | /bin/sh (BusyBox ash). bash отсутствует |
| SSH-сервер | Dropbear (нет scp, sftp, rsync) |
| Init-система | BusyBox init + скрипты в /userdata/init.d/ |
| Persistent-раздел | /userdata/ — сохраняется при OTA-обновлениях |
Структура хранилища:
| Путь | Назначение | Сохраняется при OTA |
|---|---|---|
/ | Корневая ФС | Нет |
/userdata/ | Пользовательские данные | Да |
Мы будем хранить tuna в /userdata/tuna/, чтобы бинарник и конфигурация сохранялись при обновлениях.
Подключение по SSH
Включите Developer Mode в веб-интерфейсе JetKVM и добавьте публичный RSA-ключ (Settings → Advanced → Developer Mode). Затем подключитесь:
ssh root@<IP-адрес-JetKVM>
Или откройте терминал в веб интерфейсе:
IP-адрес можно найти на встроенном экране JetKVM или в DHCP-таблице роутера.
Установка tuna на JetKVM
Подключитесь к JetKVM по SSH и установите бинарник:
mkdir -p /userdata/tuna
INSECURE=true INSTALL_DIR=/userdata/tuna sh -c "$(wget -qO- http://releases.tuna.am/tuna/get.sh)"
INSECURE=true?На JetKVM отсутствуют корневые CA-сертификаты, поэтому wget не может проверить SSL-сертификат сервера. Флаг INSECURE=true переключает скрипт на загрузку по HTTP. Это безопасно, так как бинарник tuna после загрузки можно проверить по контрольной сумме.
Раздел /userdata сохраняется при OTA-обновлениях, поэтому tuna не придётся переустанавливать после обновления прошивки.
Сохраните токен авторизации:
/userdata/tuna/tuna --config=/userdata/tuna/.tuna.yml config save-token <ВАШ_ТОКЕН>
Рекомендуем создать дополнительный токен для устройства.
Система автозапуска JetKVM
В отличие от NanoKVM, где автозапуск настраивается через /etc/inittab с директивой respawn, на JetKVM используются init-скрипты в директории /userdata/init.d/, каталог нужно создать.
mkdir -p /userdata/init.d
При загрузке init-система JetKVM выполняет все скрипты из /userdata/init.d/, чьи имена соответствуют паттерну S??* (например, S99tuna-http). Скрипты вызываются с аргументом start, при остановке — с аргументом stop.
Несоблюдение этих правил может привести к тому, что устройство перестанет загружаться:
- Используйте
#!/bin/sh— на JetKVM нет/bin/bash. Шебанг#!/bin/bashприведёт к ошибке и может заблокировать загрузку. - Не используйте расширение
.sh— файлы с расширением.shвключаются черезsource(а не вызываются как отдельный процесс). Командаexitв таком скрипте завершит весь init-процесс. - Не блокируйте загрузку — все долгоживущие процессы должны запускаться в фоне с
&. Если ск рипт не возвращает управление, загрузка зависнет. - Обрабатывайте аргумент
start— init-система вызывает скрипт какS99tuna-http start. Безcase "$1"скрипт может выполниться некорректно.
В отличие от NanoKVM (где inittab respawn автоматически перезапускает упавший процесс), на JetKVM /etc/inittab перезаписывается при OTA-обновлениях. Поэтому мы используем цикл while true внутри init-скрипта для автоперезапуска при падении.
Всегда запускайте скрипт вручную (/userdata/init.d/S99tuna-http start) и убедитесь, что промпт вернулся. Если после запуска консоль «зависла» — скрипт заблокирует загрузку при перезагрузке.
Тип 1. Бесплатный тариф — HTTP-туннель
На бесплатном тарифе доступен HTTP-туннель с динамическим адресом. Этого достаточно, чтобы открыть веб-интерфейс JetKVM в интернет и управлять компьютером через браузер.
- Адрес туннеля меняется каждые 30 минут
- Нельзя задать фиксированный поддомен
- Текущий адрес всегда можно посмотреть в личном кабинете
Создание init-скрипта
cat << 'INITEOF' > /userdata/init.d/S99tuna-http
#!/bin/sh
PIDFILE=/tmp/tuna-http.pid
LOGFILE=/tmp/tuna-http.log
wait_network() {
i=0
while ! ip route | grep -q default; do
sleep 1
i=$((i + 1))
if [ "$i" -ge 60 ]; then
echo "$(date): network timeout" >> "$LOGFILE"
return 1
fi
done
return 0
}
start() {
echo "$(date): starting tuna-http" >> "$LOGFILE"
(
wait_network || exit 1
while true; do
/userdata/tuna/tuna \
--config=/userdata/tuna/.tuna.yml \
--log="$LOGFILE" \
http \
--inspect=false \
--basic-auth=tuna:SecurePasswd \
--https-redirect \
80 >> "$LOGFILE" 2>&1
echo "$(date): tuna-http exited, restarting in 5s" >> "$LOGFILE"
sleep 5
done
) &
echo $! > "$PIDFILE"
}
stop() {
if [ -f "$PIDFILE" ]; then
kill "$(cat "$PIDFILE")" 2>/dev/null
pkill -f "/userdata/tuna/tuna.*http" 2>/dev/null
rm -f "$PIDFILE"
fi
}
case "$1" in
start) start ;;
stop) stop ;;
restart) stop; sleep 1; start ;;
*) echo "Usage: $0 {start|stop|restart}" ;;
esac
INITEOF
chmod +x /userdata/init.d/S99tuna-http
Пояснение init-скрипта
| Элемент | Описание |
|---|---|
S99tuna-http | Имя без .sh — init вызывает скрипт с аргументом start, а не включает через source |
wait_network() | Ожидает появления default route (максимум 60 секунд) |
( ... ) & | Субшелл запускается в фоне — не блокирует заг рузку |
while true | Автоматический перезапуск tuna при падении (пауза 5 секунд) |
echo $! > "$PIDFILE" | Сохраняет PID субшелла для корректной остановки |
pkill -f | При остановке убивает и обёртку, и дочерний процесс tuna |
Пояснение флагов tuna
| Флаг | Обязательный | Описание |
|---|---|---|
--inspect=false | Нет | Отключает инспектор трафика (не нужен для KVM), чтобы не расходовать RAM |
--basic-auth=admin:ВашПароль | Нет | Дополнительная HTTP-авторизация (подробнее) |
--https-redirect | Нет | Перенаправляет HTTP на HTTPS |
80 | Да | Порт веб-интерфейса JetKVM |
Также можно ограничить доступ по IP-подсетям.
Проверка
Запустите скрипт вручную:
/userdata/init.d/S99tuna-http start
Убедитесь, что промпт вернулся (скрипт не заблокировал консоль). Проверьте, что процесс запущен:
ps | grep tuna
В выводе должна быть строка с /userdata/tuna/tuna ... http .... Если процесса нет — смотрите раздел Диагностика неполадок.
В логах вы увидите URL вашего туннеля:
cat /tmp/tuna-http.log
Также текущий адрес доступен в личном кабинете.
Тип 2. Подписка — SSH и HTTP туннели
С подпиской вы получаете:
- Фиксированный поддомен для HTTP-туннеля — адрес не меняется
- SSH-туннель — прямой доступ к консоли JetKVM из любой точки мира
HTTP-туннель с фиксированным адресом
cat << 'INITEOF' > /userdata/init.d/S99tuna-http
#!/bin/sh
PIDFILE=/tmp/tuna-http.pid
LOGFILE=/tmp/tuna-http.log
wait_network() {
i=0
while ! ip route | grep -q default; do
sleep 1
i=$((i + 1))
if [ "$i" -ge 60 ]; then
echo "$(date): network timeout" >> "$LOGFILE"
return 1
fi
done
return 0
}
start() {
echo "$(date): starting tuna-http" >> "$LOGFILE"
(
wait_network || exit 1
while true; do
/userdata/tuna/tuna \
--config=/userdata/tuna/.tuna.yml \
--log="$LOGFILE" \
http \
--subdomain=jetkvm \
--inspect=false \
--basic-auth=admin:ВашПароль \
--https-redirect \
80 >> "$LOGFILE" 2>&1
echo "$(date): tuna-http exited, restarting in 5s" >> "$LOGFILE"
sleep 5
done
) &
echo $! > "$PIDFILE"
}
stop() {
if [ -f "$PIDFILE" ]; then
kill "$(cat "$PIDFILE")" 2>/dev/null
pkill -f "/userdata/tuna/tuna.*http" 2>/dev/null
rm -f "$PIDFILE"
fi
}
case "$1" in
start) start ;;
stop) stop ;;
restart) stop; sleep 1; start ;;
*) echo "Usage: $0 {start|stop|restart}" ;;
esac
INITEOF
chmod +x /userdata/init.d/S99tuna-http
Отличие от бесплатной версии — флаг --subdomain=jetkvm, который закрепляет за вами постоянный адрес. После перезапуска туннеля URL останется прежним.
Поддомен из примера уже может быть занят. Зарезервируйте свой поддомен заранее в личном кабинете, затем используйте его в флаге --subdomain=ваш-поддомен.
Пояснение флагов HTTP-туннеля
| Ф лаг | Обязательный | Описание |
|---|---|---|
--subdomain=jetkvm | Нет | Фиксирует постоянный адрес туннеля (только с подпиской) |
--inspect=false | Нет | Отключает инспектор трафика (не нужен для KVM), чтобы не расходовать RAM |
--basic-auth=admin:ВашПароль | Нет | Дополнительная HTTP-авторизация (подробнее) |
--https-redirect | Нет | Перенаправляет HTTP на HTTPS |
80 | Да | Порт веб-интерфейса JetKVM |
Также можно ограничить доступ по IP-подсетям.
SSH-туннель
SSH-туннель позволяет подключаться к консоли JetKVM через интернет. Это удобно для администрирования, обновления прошивки и диагностики.
cat << 'INITEOF' > /userdata/init.d/S98tuna-ssh
#!/bin/sh
PIDFILE=/tmp/tuna-ssh.pid
LOGFILE=/tmp/tuna-ssh.log
wait_network() {
i=0
while ! ip route | grep -q default; do
sleep 1
i=$((i + 1))
if [ "$i" -ge 60 ]; then
echo "$(date): network timeout" >> "$LOGFILE"
return 1
fi
done
return 0
}
start() {
echo "$(date): starting tuna-ssh" >> "$LOGFILE"
(
wait_network || exit 1
while true; do
/userdata/tuna/tuna \
--config=/userdata/tuna/.tuna.yml \
--log="$LOGFILE" \
ssh \
--port=jetkvm-ssh \
--record-session=false \
--password-auth=false >> "$LOGFILE" 2>&1
echo "$(date): tuna-ssh exited, restarting in 5s" >> "$LOGFILE"
sleep 5
done
) &
echo $! > "$PIDFILE"
}
stop() {
if [ -f "$PIDFILE" ]; then
kill "$(cat "$PIDFILE")" 2>/dev/null
pkill -f "/userdata/tuna/tuna.*ssh" 2>/dev/null
rm -f "$PIDFILE"
fi
}
case "$1" in
start) start ;;
stop) stop ;;
restart) stop; sleep 1; start ;;
*) echo "Usage: $0 {start|stop|restart}" ;;
esac
INITEOF
chmod +x /userdata/init.d/S98tuna-ssh
Пояснение флагов SSH-туннеля
| Флаг | Обязательный | Описание |
|---|---|---|
--port=jetkvm-ssh | Нет | Фиксирует порт SSH-туннеля. Без этого флага порт будет назначаться случайно при каждом запуске. Алиас для порта нужно зарезервировать заранее перед запуском. |
--record-session=false | Нет | Отключает запись SSH-сессий на диск. На embedded устройствах с ограниченным хранилищем рекомендуется отключать, чтобы не занимать место. |
--password-auth=false | Нет | Запрещает подключение по паролю — доступ только по SSH-ключам (подробнее) |
Также можно задать статичный логин и пароль или ограничить доступ по IP-подсетям.
Проверка туннелей
Запустите оба скрипта вручную:
/userdata/init.d/S99tuna-http start
/userdata/init.d/S98tuna-ssh start
Убедитесь, что оба процесса запущены:
ps | grep tuna
В выводе должны быть две строки — с http и ssh. Если какого-то процесса нет — смотрите раздел Диагностика неполадок.
Посмотрите логи:
cat /tmp/tuna-http.log
cat /tmp/tuna-ssh.log
В логах HTTP-туннеля будет URL, а в логах SSH-туннеля — инструкция для подключения с указанием адреса и порта.
Управление туннелями
Автоперезапуск при падении обеспечивается циклом while true внутри init-скрипта. Для управления туннелями используйте следующие команды.
Проверка статуса
ps | grep tuna
Остановка туннеля
# Остановить HTTP-туннель
/userdata/init.d/S99tuna-http stop
# Остановить SSH-туннель
/userdata/init.d/S98tuna-ssh stop
Запуск туннеля
# Запустить HTTP-туннель
/userdata/init.d/S99tuna-http start
# Запустить SSH-туннель
/userdata/init.d/S98tuna-ssh start
Перезапуск туннеля
# Перезапустить HTTP-туннель
/userdata/init.d/S99tuna-http restart
# Перезапустить SSH-туннель
/userdata/init.d/S98tuna-ssh restart
Полное отключение автозапуска
Чтобы туннель не запускался при загрузке — переименуйте скрипт, убрав префикс S:
# Отключить автозапуск HTTP-туннеля
mv /userdata/init.d/S99tuna-http /userdata/init.d/disabled-tuna-http
# Включить обратно
mv /userdata/init.d/disabled-tuna-http /userdata/init.d/S99tuna-http
Восстановление после OTA-обновления
Бинарник, конфигурация и init-скрипты хранятся в /userdata/, который сохраняется при OTA-обновлениях. После обновления прошивки через веб-интерфейс JetKVM туннели продолжат работать без дополнительных действий.
В отличие от NanoKVM, на JetKVM не нужно восстанавливать /etc/inittab после обновления — автозапуск через /userdata/init.d/ полностью переживает OTA.
При полной перепрошивке (когда /userdata был очищен) потребуется заново установить бинарник, сохранить токен и создать init-скрипты.
Дополнительные настройки безопасности
Зачем нужен --basic-auth
У JetKVM есть собственная авторизация в веб-интерфейсе. Однако, учитывая историю уязвимостей в IoT-устройствах, мы настоятельно рекомендуем добавить дополнительный уровень защиты. При открытии доступа через интернет лучше перестраховаться — флаг --basic-auth добавит стандартную HTTP-авторизацию (логин и пароль в браузере) ещё до того, как запрос дойдёт до JetKVM.
--basic-auth=mylogin:MyStr0ngP@ss
Задайте свои логин и пароль. Не используйте значения из примеров.