Резервный туннель для обслуживания (mgmt-туннель)¶
Проблема¶
Если вы используете SSH-туннель через slug.dix.su:2222, а потом обновляете или
перезапускаете dixsu-device-client на этом же устройстве — соединение рвётся
и удалённый доступ пропадает. Устройство становится «глухим» до физического вмешательства.
Решение: два независимых туннеля¶
Держите на устройстве два отдельных device_client-сервиса с разными слагами:
| Туннель | Слаг | Назначение |
|---|---|---|
| Основной | mydevice |
Ваш сайт/сервис, порт 80 |
| Резервный | mydevice-mgmt |
SSH-доступ для обслуживания, порт 22 |
Обновление основного туннеля всегда делайте через mydevice-mgmt, не через основной.
Mgmt-туннель трогайте только в крайнем случае.
Слаги PRO-тарифа позволяют до 2 дополнительных слагов, PERS — без ограничений. Создать дополнительный слаг можно в личном кабинете → «Мои туннели».
Настройка резервного сервиса (systemd)¶
# Создаём env-файл для mgmt-туннеля
cat > /etc/dixsu/device-client-mgmt.env << 'EOF'
SERVER_HOST=proxy.dix.su
SERVER_PORT=443
DEVICE_SLUG=mydevice-mgmt
DEVICE_TOKEN=<токен-второго-слага>
LOCAL_PORT=22
EOF
chmod 600 /etc/dixsu/device-client-mgmt.env
# Создаём отдельный systemd-юнит
cat > /etc/systemd/system/dixsu-device-client-mgmt.service << 'EOF'
[Unit]
Description=dix.su Device Client — mgmt tunnel (SSH)
After=network-online.target
Wants=network-online.target
[Service]
EnvironmentFile=/etc/dixsu/device-client-mgmt.env
ExecStart=/usr/local/bin/dixsu-device-client ${DEVICE_SLUG} ${DEVICE_TOKEN} ${LOCAL_PORT}
Restart=always
RestartSec=10
StartLimitIntervalSec=0
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable --now dixsu-device-client-mgmt
Настройка резервного сервиса (OpenRC / Alpine / postmarketOS)¶
# env-файл
cat > /etc/dixsu/device-client-mgmt.env << 'EOF'
SERVER_HOST=proxy.dix.su
SERVER_PORT=443
DEVICE_SLUG=mydevice-mgmt
DEVICE_TOKEN=<токен-второго-слага>
LOCAL_PORT=22
EOF
chmod 600 /etc/dixsu/device-client-mgmt.env
# init-скрипт
cat > /etc/init.d/dixsu-device-client-mgmt << 'EOF'
#!/sbin/openrc-run
description="dix.su Device Client — mgmt tunnel (SSH)"
depend() {
need net
after networkmanager
}
ENV_FILE=/etc/dixsu/device-client-mgmt.env
respawn
respawn_delay 5
respawn_max 0
start() {
ebegin "Starting dixsu-device-client-mgmt"
. "$ENV_FILE"
start-stop-daemon --start \
--background \
--make-pidfile \
--pidfile /run/dixsu-device-client-mgmt.pid \
--stdout /var/log/dixsu-device-client-mgmt.log \
--stderr /var/log/dixsu-device-client-mgmt.log \
--env "SERVER_HOST=${SERVER_HOST}" \
--env "SERVER_PORT=${SERVER_PORT}" \
--exec /usr/local/bin/dixsu-device-client \
-- "$DEVICE_SLUG" "$DEVICE_TOKEN" "$LOCAL_PORT"
eend $?
}
stop() {
ebegin "Stopping dixsu-device-client-mgmt"
start-stop-daemon --stop --pidfile /run/dixsu-device-client-mgmt.pid
eend $?
}
EOF
chmod +x /etc/init.d/dixsu-device-client-mgmt
rc-update add dixsu-device-client-mgmt default
rc-service dixsu-device-client-mgmt start
Процедура безопасного обновления бинаря¶
# 1. SSH через mgmt-туннель
ssh -p 2222 \
-o "ProxyCommand=bash -c '{ echo DIXSU:mydevice-mgmt; cat; } | nc mydevice-mgmt.dix.su 2222'" \
root@localhost
# 2. Скачать свежий бинарь (arm64 или x86_64_musl — в зависимости от архитектуры)
wget https://dix.su/downloads/device_client_linux_arm64 -O /tmp/dc-new
chmod +x /tmp/dc-new
# 3. Остановить основной туннель, обновить бинарь, очистить Burrito-кеш
rc-service dixsu-device-client stop
mv /tmp/dc-new /usr/local/bin/dixsu-device-client
rm -rf /root/.local/share/.burrito/device_client_erts-*/
# 4. Запустить — оба сервиса используют один и тот же бинарь
rc-service dixsu-device-client start
Mgmt-туннель при этом не прерывается: он не останавливался, а respawn автоматически
поднимет его если что-то пойдёт не так.
Добавить respawn к уже работающему сервису¶
Если у вас один сервис без respawn (старая настройка):
OpenRC — добавьте в init-скрипт перед start():
systemd — уже работает: Restart=always и RestartSec=10 включены
по умолчанию в скрипте install-service.sh.
Альтернатива SSH: браузерный терминал через ttyd¶
ttyd — терминал прямо в браузере поверх
HTTP/WebSocket. Работает на любом тарифе (включая SIMPLE) — открытый SSH-порт
не нужен. Доступен только через личный кабинет dix.su (путь /auth/terminal/{slug}),
защищён системным логином и паролем устройства.
Браузерный терминал работает в два этапа:
- HTML-страница (
/auth/terminal/{slug}) — грузится через HTTP-прокси: modulauth запрашивает у dixu_proxyHost: slug.dix.su, тот форвардит наLOCAL_PORTdevice_client. Значит LOCAL_PORT device_client должен быть 7681 — иначе вместо ttyd откроется основной сервис (или 404). - WebSocket (
/auth/terminal/{slug}/ws) — идёт через TCP relay (dix.su:4781 → устройство:7681) независимо от LOCAL_PORT.
Поэтому нужен отдельный слаг с LOCAL_PORT=7681 — обычно mydevice-mgmt.
Совместить ttyd и веб-сервис (порт 80) на одном слаге не получится.
Прокинуть SSH (порт 22) через порт 4781 нельзя: порт 4781 жёстко маппится на target-порт 7681. Для SSH нужен отдельный порт 4022.
Установка ttyd¶
#!/bin/sh
# Работает в bash и ash/Alpine
if command -v apk > /dev/null 2>&1; then
apk update && apk add ttyd
elif command -v apt > /dev/null 2>&1; then
apt update && apt install -y ttyd
elif command -v pacman > /dev/null 2>&1; then
pacman -Sy --noconfirm ttyd
elif command -v dnf > /dev/null 2>&1; then
dnf install -y ttyd
elif command -v yum > /dev/null 2>&1; then
yum install -y ttyd
else
# Универсально: скачать бинарь напрямую
ARCH=$(uname -m)
[ "$ARCH" = "aarch64" ] && ARCH="aarch64" || ARCH="x86_64"
curl -fsSL "https://github.com/tsl0922/ttyd/releases/latest/download/ttyd.$ARCH" \
-o /usr/local/bin/ttyd
chmod +x /usr/local/bin/ttyd
fi
Сервис автозапуска — systemd¶
cat > /etc/systemd/system/ttyd.service <<'EOF'
[Unit]
Description=ttyd web terminal
After=network.target
[Service]
ExecStart=/usr/bin/ttyd --port 7681 --writable login
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable --now ttyd
Сервис автозапуска — OpenRC (Alpine Linux и другие)¶
cat > /etc/init.d/ttyd <<'EOF'
#!/sbin/openrc-run
description="ttyd web terminal"
command="/usr/bin/ttyd"
command_args="--port 7681 --writable login"
command_background=true
pidfile="/run/ttyd.pid"
depend() { need net; }
EOF
chmod +x /etc/init.d/ttyd
rc-update add ttyd default
rc-service ttyd start
Сервис автозапуска — macOS (LaunchDaemon)¶
cat > /Library/LaunchDaemons/su.dix.ttyd.plist <<'EOF'
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key><string>su.dix.ttyd</string>
<key>ProgramArguments</key>
<array>
<string>/usr/local/bin/ttyd</string>
<string>--port</string><string>7681</string>
<string>--writable</string><string>login</string>
</array>
<key>RunAtLoad</key><true/>
<key>KeepAlive</key><true/>
</dict>
</plist>
EOF
launchctl load /Library/LaunchDaemons/su.dix.ttyd.plist
Установка и сервис — Windows (PowerShell, от администратора)¶
Скачать ttyd.exe заранее.
# Установка через winget
winget install tsl0922.ttyd
# Сервис через NSSM (рекомендуется)
winget install nssm
nssm install ttyd "C:\Windows\System32\ttyd.exe" "--port 7681 --writable cmd"
nssm set ttyd Start SERVICE_AUTO_START
nssm start ttyd
Запуск туннеля для ttyd¶
Запустите device_client с LOCAL_PORT=7681. Это может быть основной слаг или
отдельный mgmt-слаг — на ваше усмотрение:
# Вариант А: отдельный mgmt-слаг (рекомендуется для независимости)
SERVER_HOST=proxy.dix.su SERVER_PORT=443 \
device_client mydevice-mgmt <mgmt-токен> 7681
# Вариант Б: основной слаг (если устройство одно и параллельный сервис не нужен)
SERVER_HOST=proxy.dix.su SERVER_PORT=443 \
device_client mydevice <основной-токен> 7681
После запуска откройте браузерный терминал в личном кабинете:
Браузер покажет запрос системного логина и пароля устройства (запрос ttyd).
Не путайте с
https://mydevice-mgmt.dix.su— это страница вашего туннеля, а не браузерный терминал.
Для дополнительной защиты: установите ограничение allowed_ips для mgmt-слага
в настройках личного кабинета.
Безопасность: держите mgmt-туннель замороженным¶
Рекомендация
Держите mgmt-туннель замороженным в обычное время и размораживайте только когда нужен доступ. Даже при защите на уровне dix.su открытый mgmt-туннель — это постоянно доступный шелл устройства.
Браузерный терминал (ttyd) не требует пароля по умолчанию: ttyd запускается от root и сразу даёт shell без авторизации. Замороженный mgmt-туннель закрывает доступ к нему полностью — прокси возвращает страницу «туннель заморожен» даже авторизованным пользователям.
Когда нужен терминал:
- Перейдите в личный кабинет → Мои туннели
- Нажмите Разморозить рядом с mgmt-слагом
- Выполните работу
- Снова нажмите Заморозить
Разморозка и заморозка занимают секунду. device_client при этом остаётся
запущенным на устройстве — туннель переходит в нужное состояние мгновенно.
Для дополнительной защиты можно также добавить пароль в ttyd:
# systemd: добавьте --credential login:password в ExecStart
ExecStart=/usr/bin/ttyd --port 7681 --writable --credential myuser:mypassword login
# OpenRC: добавьте в command_args
command_args="--port 7681 --writable --credential myuser:mypassword login"
Или ограничьте доступ по IP в настройках mgmt-слага (личный кабинет → «Мои туннели» → Настройки слага → allowed_ips).