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
Задайте свои логин и пароль. Не используйте значения из примеров.
Аутентификация в SSH-туннеле
Вариант 1. По SSH-ключам (рекомендуется)
Флаг --password-auth=false отключает вход по паролю. Для подключения потребуется предварительно добавить публичный SSH-ключ в личном кабинете.
Подробная инструкция: Настройка SSH-ключей
Туннельные ноды имеют публичный адрес. Злоумышленники могут просканировать порты и начать подбор пароля. Для долгоживущих SSH-туннелей настоятельно рекомендуем отключить парольную аутентификацию.
Вариант 2. Статичный логин и пароль
Если SSH-ключи не подходят, можно задать фиксированные учётные данные:
--auth=user:pass
Замените user и pass на свои значения.
Ограничение по IP-подсетям
Для HTTP и SSH туннелей можно ограничить доступ по IP-адресам.
Разрешить доступ только с определённых подсетей:
--cidr-allow="203.0.113.0/24"
Запретить доступ из определённых подсетей:
--cidr-deny="198.51.100.0/24"
Можно комбинировать — разрешить подсеть, но исключить отдельные адреса:
--cidr-allow="10.0.0.0/24" --cidr-deny="10.0.0.33/32"
Используйте фильтрацию по IP с осторожностью. Если вы ошибётесь с подсетью или ваш IP-адрес изменится — вы потеряете удалённый доступ к JetKVM. Убедитесь, что у вас есть альтернативный способ управления устройством (например, локальный доступ).
Диагностика неполадок
Устройство не загружается после добавления init-скрипта
Если JetKVM перестал загружаться после добавления скрипта в /userdata/init.d/, наиболее частые причины:
- Шебанг
#!/bin/bash— bash на JetKVM отсутствует - Скрипт блокирует загрузку — процесс не запущен в фоне (
&) - Расширение
.sh— скрипт был включён черезsource, что сломало init-процесс - Синтаксическая ошибка — прерывает выполнение init
Способы восстановления:
- UART serial console — если есть доступ к UART-порту JetKVM, подключитесь через serial console (115200 baud) и удалите или переименуйте проблемный скрипт
- Factory reset — нажмите и удерживайте кнопку сброса на JetKVM (внимание: это может очистить
/userdata/)
Процесс tuna не запускается
Проверьте, что процесс присутствует в списке:
ps | grep tuna
Если в выводе нет строк с /userdata/tuna/tuna — проверьте:
- Скрипт существует и имеет права на выполнение:
ls -la /userdata/init.d/S9*tuna*
- Скрипт запускается без ошибок:
/userdata/init.d/S99tuna-http start
- Бинарник tuna работает:
/userdata/tuna/tuna version
Просмотр логов
Логи туннелей записываются в /tmp/ и доступны до перезагрузки устройства:
# Логи HTTP-туннеля
cat /tmp/tuna-http.log
# Логи SSH-туннеля
cat /tmp/tuna-ssh.log
Для наблюдения за логами в реальном времени:
tail -f /tmp/tuna-http.log
Типичные ошибки в логах
| Ошибка | Причина | Решение |
|---|---|---|
token is invalid | Неверный или просроченный токен | Повторите config save-token с актуальным токеном со страницы |
Domain already reserved | Поддомен занят другим пользователем | Выберите другое имя через --subdomain= |
port alias not found | Алиас порта не зарезервирован | Зарезервируйте алиас в личном кабинете |
connection refused | Нет доступа к интернету | Проверьте сеть: ping -c 3 8.8.8.8 |
exec format error | Неправильная архитектура бинарника | Убедитесь, что используете tuna_linux_arm (ARMv7) |
Нет доступа к интернету
Проверьте, что JetKVM имеет сет евое подключение:
# Проверить наличие IP-адреса
ip addr
# Проверить маршрут по умолчанию
ip route
# Проверить доступ в интернет
ping -c 3 8.8.8.8
Логи пропали после перезагрузки
Логи хранятся в /tmp/, который очищается при перезагрузке. Это нормальное поведение. Если нужно сохранять логи между перезагрузками, измените путь в init-скриптах:
LOGFILE=/userdata/tuna/tuna-http.log
Частая запись логов может сократить ресурс хранилища. Используйте это только для временной отладки.
Туннель работал и перестал
- Проверьте логи на наличие ошибок
- Убедитесь, что токен всё ещё действителен в личном кабинете
- Проверьте, что скрипт в
/userdata/init.d/на месте и исполняем:
ls -la /userdata/init.d/S9*tuna*
Ссылки
- JetKVM — официальный сайт
- JetKVM — GitHub
- JetKVM — документация
- HTTP-туннель — все флаги
- SSH-туннель — все флаги
- Настройка SSH-ключей
- Запуск tuna как сервис
Мониторинг доступности
Помимо туннелей для удалённого доступа, вы можете настроить мониторинг доступности JetKVM. Heartbeat-мониторинг будет отправлять вам уведомления, если устройство потеряет связь с интернетом или перестанет отвечать.
Полная инструкция: Мониторинг доступности JetKVM