Веб-интерфейс

Управление Throne из браузера с помощью thronectl web: настройка с Docker, юнитом systemd или вручную, доступ через туннель SSH, HTTPS или обратный прокси и безопасность.

thronectl web предоставляет веб-интерфейс для Throne. В браузере можно смотреть и переключать подключение, выбирать и тестировать профили, импортировать профили и обновлять подписки, следить за трафиком и логом, менять настройки, создавать резервные копии и восстанавливать их. Он работает с headless Throne и с Throne для компьютера, в котором включён Throne API. В Throne для Android нет Throne API, поэтому веб-интерфейс не может им управлять.

Веб-интерфейс входит в thronectl, а не в Throne. thronectl web — небольшой веб-сервер, шлюз: браузер обращается к шлюзу, а шлюз — к Throne через Throne API, с тем же адресом и ключом, что и остальные команды thronectl. Сам Throne веб-страниц не отдаёт.

Пользуйтесь веб-интерфейсом, когда удобнее смотреть и нажимать, например с телефона или с компьютера без thronectl. Для скриптов, горячих клавиш и автоматизации используйте команды thronectl. Оба способа работают одновременно.

Быстрый старт

Выберите вариант, который соответствует тому, как работает Throne. В каждом из них шлюз работает на том же устройстве, что и Throne, где Throne отвечает на все его запросы, включая административные.

Docker

Образ Docker запускает шлюз рядом с Throne, в том же контейнере, если задана переменная THRONE_WEB_LISTEN. В compose.yaml из репозитория Throne добавьте эту переменную в службу throne и опубликуйте порт:

services:
  throne:
    environment:
      THRONE_WEB_LISTEN: "*:9096"
    ports: ["2080:2080", "9096:9096"]

На хосте, доступном из интернета, публикуйте только адрес в локальной сети, например "192.168.1.2:9096:9096". С docker run добавьте -e THRONE_WEB_LISTEN='*:9096' -p 9096:9096. Затем запустите контейнер и прочитайте его лог:

docker compose up -d
docker compose logs throne

В логе будут пароль и отпечаток самоподписанного сертификата. Откройте https://<host>:9096/, сравните отпечаток, как описано в разделе Локальная сеть, и войдите.

  • Точка входа контейнера запускает thronectl web рядом с Throne, как только API Throne начинает отвечать, и сама находит адрес и ключ API. Если шлюз завершается, точка входа запускает его снова через 3 секунды, поэтому неверное значение THRONE_WEB_* появляется в логе каждые 3 секунды. Кроме того, шлюз перезапускается вместе с контейнером.
  • Шлюз хранит своё состояние в /var/lib/throne/web на томе с данными.
  • Остальные переменные THRONE_WEB_*, например THRONE_WEB_TLS, THRONE_WEB_ALLOW_HOST или THRONE_WEB_PASSWORD_FILE (см. Параметры), добавляются в тот же блок environment:.

Пакеты для Linux (systemd)

Пакеты .deb и .rpm устанавливают thronectl как /usr/bin/thronectl и второй юнит, throne-web.service, который запускает thronectl web рядом с throne.service. Он работает не от root: systemd выделяет ему собственного динамического пользователя, передаёт ему ключ Throne /var/lib/throne/config/api.key как учётные данные (credential) и хранит его состояние в /var/lib/throne-web. Пакет не включает этот юнит:

sudo systemctl enable --now throne-web
sudo journalctl -u throne-web | grep 'web UI password'

Пока при первом запуске Throne не создаст файл ключа, юнит завершается ошибкой, и systemd запускает его снова каждые 5 секунд, как и после любой другой ошибки. Он слушает 127.0.0.1:9096: открывайте его через туннель SSH. Чтобы изменить его параметры, раскомментируйте переменные в /etc/throne/web.env (см. Параметры) и выполните sudo systemctl restart throne-web. Обновления сохраняют ваши правки. Никогда не записывайте в этот файл ключ или пароль. Пользователь юнита не может читать файлы, доступные только root, например ключ в другом месте, ключ TLS или файл пароля; в /etc/throne/web.env показано, как передать их через LoadCredential= (sudo systemctl edit throne-web). Для порта ниже 1024 нужна возможность CAP_NET_BIND_SERVICE в AmbientCapabilities= и CapabilityBoundingSet= юнита.

Вручную, в любой системе

Установите thronectl на устройство, где работает Throne (см. Установка thronectl), подключите его к Throne так же, как для любой другой команды (см. Подключение thronectl к Throne), и запустите шлюз:

export THRONE_KEY_FILE=~/.config/throne/api-key
thronectl web

Он один раз выводит пароль и адрес, на котором работает:

thronectl web: created the web UI password: k7mfq-2xhpa-9tnwe-c3rjd
thronectl web: change it with 'thronectl web passwd'
thronectl web: serving on http://127.0.0.1:9096/ for Throne at 127.0.0.1:9095

Откройте http://127.0.0.1:9096/ в браузере на том же устройстве и войдите с этим паролем. thronectl web работает, пока вы не нажмёте Ctrl+C. Он запускается и без Throne: пока Throne не ответит, веб-интерфейс сообщает, что Throne недоступен.

Для Throne для компьютера сначала включите API (Настройки (Settings) → Настройки интеграции (Integration Settings) → Throne API, см. Включение API в Throne) и сохраните его ключ в файл, как описано в разделе Подключение thronectl к Throne. В Windows, в PowerShell:

$env:THRONE_KEY_FILE = "$HOME\throne-api-key.txt"
thronectl web

Доступ с другого устройства

По умолчанию шлюз слушает 127.0.0.1:9096, куда могут обращаться только программы на устройстве с Throne. С другого устройства используйте туннель SSH, HTTPS в локальной сети или обратный прокси.

Туннель SSH

Если вы можете войти на устройство по SSH, оставьте шлюз на loopback и проложите к нему туннель со своего компьютера:

ssh -L 9096:127.0.0.1:9096 user@host

Пока этот сеанс открыт, откройте http://localhost:9096/ на своём компьютере (https:// для варианта с Docker, который работает по HTTPS). Из сети устройства к шлюзу никто не обратится, а SSH шифрует трафик. Если порт 9096 на вашем компьютере занят, выберите другой локальный порт: ssh -L 19096:127.0.0.1:9096 user@host, затем http://localhost:19096/.

Локальная сеть (HTTPS)

Чтобы открывать веб-интерфейс напрямую с других устройств в вашей сети, разрешите шлюзу слушать сетевой адрес:

thronectl web --listen '*:9096'

*:9096 слушает все адреса устройства, 192.168.1.2:9096 — один. На сетевом адресе шлюз работает по HTTPS. Если вы не дадите ему сертификат, он создаёт самоподписанный сертификат в своём каталоге состояния и при каждом запуске выводит его отпечаток:

thronectl web: created a self-signed TLS certificate in /home/you/.config/thronectl/web/tls
thronectl web: TLS certificate SHA-256 fingerprint: 3F:A1:5C:…:9C
thronectl web: serving on https://localhost:9096/ for Throne at 127.0.0.1:9095
thronectl web: serving on https://192.168.1.2:9096/ for Throne at 127.0.0.1:9095

Браузер предупредит, что сертификату нельзя доверять, потому что его не подписал ни один центр сертификации. Прежде чем принять его:

  1. Откройте сведения о сертификате со страницы предупреждения или из адресной строки.
  2. Сравните его отпечаток SHA-256 с тем, который вывел шлюз.
  3. Принимайте сертификат, только если они совпадают. Если они различаются, что-то между вами и устройством перехватывает соединение: не входите.

Отпечаток показывает и страница System веб-интерфейса. Разрешите порт 9096 в брандмауэре устройства, и только из вашей сети.

  • Сертификат выписан на localhost, имя хоста устройства и адреса, которые были у устройства, когда шлюз его создал. Чтобы создать новый, например после смены адреса устройства, удалите папку tls в каталоге состояния и перезапустите шлюз. Отпечаток при этом изменится.
  • Самоподписанный сертификат действует 10 лет. Если срок истёк или сертификат не читается, шлюз создаёт новый при следующем запуске.
  • Чтобы использовать собственный сертификат, передайте цепочку сертификатов и закрытый ключ в файлах PEM через --tls-cert и --tls-key. Шлюз читает их при запуске; после продления перезапустите его.

За обратным прокси

Обратный прокси, например nginx или Caddy, может отдавать веб-интерфейс под вашим именем хоста с сертификатом, которому доверяют браузеры. Оставьте шлюз на loopback, где он работает по обычному HTTP, доступному только программам на устройстве, и передайте ему имя хоста:

thronectl web --allow-host throne.example.com

На loopback шлюз отвечает только на запросы к localhost, 127.0.0.1, ::1 и к именам из --allow-host (см. Проверка Host). Если прокси работает на другом устройстве или в другом контейнере, шлюз должен слушать сетевой адрес: добавьте там --tls off и сделайте этот адрес доступным только прокси, потому что пароль и сеанс передаются по нему без шифрования.

Прокси должен:

  • Передавать заголовок Host таким, каким его отправил браузер. Шлюз отклоняет изменения, у которых заголовок Origin не совпадает с заголовком Host (403 csrf). nginx заменяет этот заголовок, если его не задать; Caddy сохраняет его.
  • Принимать тела запросов до 512 MiB — это самая большая резервная копия, которую восстанавливает веб-интерфейс. nginx принимает 1 MiB, если не задать client_max_body_size.
  • Передавать ответы по мере поступления. Веб-интерфейс получает обновления и лог потоком. Шлюз отправляет X-Accel-Buffering: no, что отключает для них буферизацию nginx.

nginx:

server {
    listen 443 ssl;
    server_name throne.example.com;
    ssl_certificate     /etc/ssl/certs/throne.example.com.pem;
    ssl_certificate_key /etc/ssl/private/throne.example.com.key;

    location / {
        proxy_pass http://127.0.0.1:9096;
        proxy_set_header Host $http_host;
        client_max_body_size 512m;
    }
}

Caddy:

throne.example.com {
    reverse_proxy 127.0.0.1:9096
}

За прокси все браузеры обращаются к шлюзу с адреса прокси, поэтому неудачные попытки входа из одного браузера блокируют и остальные.

Пароль

У веб-интерфейса один пароль и нет учётных записей пользователей. При первом запуске шлюз создаёт случайный пароль, сохраняет его хеш (argon2id) в файле password в своём каталоге состояния и один раз выводит пароль:

thronectl web: created the web UI password: k7mfq-2xhpa-9tnwe-c3rjd
thronectl web: change it with 'thronectl web passwd'
Вариант Где найти первый пароль
Docker docker compose logs throne
Юнит systemd sudo journalctl -u throne-web | grep 'web UI password'
Вручную В терминале, где вы запустили thronectl web

Эта строка остаётся в логе, поэтому смените пароль после первого входа:

  • На странице System веб-интерфейса. Это завершает сеансы во всех остальных браузерах.
  • Командой thronectl web passwd, запущенной от имени пользователя шлюза и с тем же каталогом состояния (--state-dir или THRONE_WEB_STATE_DIR). В терминале она дважды спрашивает пароль, не показывая вводимое; иначе читает одну строку из стандартного ввода. Работающий шлюз замечает новый пароль в течение 5 секунд и завершает все сеансы. В варианте с Docker: docker compose exec throne thronectl web passwd.

Пароль должен содержать не меньше 8 символов. Под systemd задайте его от root; файл останется за пользователем юнита:

sudo thronectl web passwd --state-dir /var/lib/throne-web

Забытый пароль. Задайте новый командой thronectl web passwd или удалите файл password из каталога состояния и перезапустите шлюз. Тогда он создаст новый пароль и выведет его.

Файл пароля. --password-file FILE (или THRONE_WEB_PASSWORD_FILE) берёт пароль открытым текстом из файла вместо сохранённого хеша, например из секрета Docker. Один перевод строки в конце не учитывается; пустой файл — ошибка. Шлюз проверяет файл каждые 5 секунд и завершает все сеансы, когда он меняется. Если файл становится пустым или нечитаемым, шлюз сохраняет прежний пароль и сообщает об этом в логе. С файлом пароля страница System не может сменить пароль, как и thronectl web passwd, пока задана THRONE_WEB_PASSWORD_FILE: меняйте сам файл.

services:
  throne:
    environment:
      THRONE_WEB_LISTEN: "*:9096"
      THRONE_WEB_PASSWORD_FILE: /run/secrets/throne_web_password
    secrets: [throne_web_password]
secrets:
  throne_web_password:
    file: ./web-password.txt

Сеансы. Вход действует, пока браузер не простаивает 12 часов, и не дольше 7 дней. Sign out на странице System завершает его. Шлюз хранит сеансы в памяти, поэтому его перезапуск завершает все сеансы. Он хранит не больше 64 сеансов; ещё один вход завершает сеанс, который дольше всех не использовался.

Что умеет веб-интерфейс

Страница Что можно делать
Status Смотреть состояние, запущенный профиль, kill switch и текущую скорость; подключаться и отключаться; включать и выключать TUN и системный прокси (системный прокси — только в Throne для компьютера); выбирать профиль маршрутизации; перезапускать профиль, когда этого требует настройка; следить за тестами и отменять их.
Profiles Просматривать группы и профили с результатами тестов, фильтровать и сортировать их; подключать профиль или лучший профиль группы; тестировать задержку, IP и скорость; очищать результаты; удалять профили. Импортировать ссылки для обмена, файл или URL. Добавлять группы и подписки, обновлять и удалять их.
Traffic Скорость за последние две минуты и суммарный трафик по профилям или приложениям за 24 часа, 7 дней или 30 дней.
Logs Лог Throne по мере записи, с паузой, текстовым фильтром, временем строк, копированием и цветами для предупреждений и ошибок. Страница хранит последние 5000 строк.
Settings Настройки, которыми управляет API, геофайлы и наборы правил запущенного профиля.
Backup Скачать резервную копию выбранных частей. Загрузить архив, посмотреть, что в нём, и восстановить выбранные части; Throne перезапускается, а веб-интерфейс ждёт его.
System Версии Throne и шлюза, есть ли у шлюза права администратора, отпечаток сертификата, пароль, выход, перезапуск Throne и завершение его работы.

Изменения, сделанные в другом месте — в окне Throne, через thronectl или при обновлении подписки, — появляются в веб-интерфейсе в течение нескольких секунд: шлюз спрашивает у Throne, что изменилось (GET /v1/events), и страница загружает заново только это.

Что остаётся в приложении для компьютера

Веб-интерфейс не редактирует:

  • правила профилей маршрутизации (он только активирует профиль маршрутизации),
  • WARP и записи OTP,
  • собственные настройки профиля, например его сервер, порты или TLS,
  • список текущих подключений,
  • настройки, которыми API не управляет.

Настройте это в Throne для компьютера и перенесите с помощью резервной копии: создайте её в приложении для компьютера, затем восстановите на странице Backup или командой thronectl backup restore, как описано в разделе Перенос конфигурации с компьютера. Throne отклоняет архивы с профилями, которые запускали бы программы или читали файлы на его устройстве, например с профилями дополнительного ядра (Extra Core) (invalid_archive).

Параметры

thronectl web [--listen ADDR] [--state-dir DIR] [--tls auto|on|off] [--tls-cert FILE --tls-key FILE]
              [--allow-host LIST] [--password-file FILE]
thronectl web passwd [--state-dir DIR]

У каждого параметра есть переменная окружения. Флаг важнее своей переменной.

Флаг Переменная Значение по умолчанию и смысл
--listen ADDR THRONE_WEB_LISTEN 127.0.0.1:9096. Принимает PORT (на 127.0.0.1), IP:PORT, [IPv6]:PORT и *:PORT (все адреса), как --api-listen у Throne. Имена хостов не принимаются.
--state-dir DIR THRONE_WEB_STATE_DIR Папка для хеша пароля и самоподписанного сертификата; шлюз создаёт её доступной только своему пользователю. По умолчанию: $STATE_DIRECTORY от systemd, иначе thronectl/web в вашей папке конфигурации: ~/.config/thronectl/web в Linux, ~/Library/Application Support/thronectl/web в macOS, %AppData%\thronectl\web в Windows.
--tls auto|on|off THRONE_WEB_TLS auto (по умолчанию): HTTPS на сетевом адресе, обычный HTTP на loopback. on: HTTPS и на loopback. off: обычный HTTP; на сетевом адресе — только за обратным прокси с TLS. off вместе с сертификатом — ошибка.
--tls-cert FILE, --tls-key FILE THRONE_WEB_TLS_CERT, THRONE_WEB_TLS_KEY Ваша цепочка сертификатов и закрытый ключ в PEM вместо самоподписанного сертификата. Указывайте оба. С auto они включают HTTPS и на loopback.
--allow-host LIST THRONE_WEB_ALLOW_HOST Дополнительные имена хостов, по которым браузеры могут обращаться к шлюзу, через запятую или пробел, например имя обратного прокси. См. Проверка Host.
--password-file FILE THRONE_WEB_PASSWORD_FILE Пароль открытым текстом, например секрет Docker, вместо сохранённого хеша. См. Пароль.

Шлюз находит Throne так же, как любая команда thronectl: адрес — из --addr или THRONE_ADDR (по умолчанию 127.0.0.1:9095), ключ — из --key-file, THRONE_KEY или THRONE_KEY_FILE, а под systemd — из учётных данных api.key (LoadCredential=api.key:/path/to/key). --timeout на него не влияет.

Коды завершения thronectl web:

Код Когда
0 Его остановили с помощью Ctrl+C или SIGTERM. Он завершает работу в течение 5 секунд.
2 Неверный параметр или переменная, нет ключа, пустой или нечитаемый файл пароля, повреждённый файл password или сертификат, который не загружается.
3 Он не может начать слушать, например потому что порт занят другой программой, или другая ошибка.

Проверка Host

Веб-страница может заставить ваш браузер отправлять запросы к шлюзу под своим именем хоста (DNS rebinding). Поэтому шлюз проверяет имя хоста в каждом запросе:

  • На адресе loopback он принимает localhost, 127.0.0.1, ::1 и имена из --allow-host.
  • На сетевом адресе он принимает любое имя, если не задан --allow-host. Если задан — принимает эти имена, имена loopback и IP-адреса.

На другие имена он отвечает 421 Misdirected Request.

Безопасность

  • Веб-интерфейс — административный клиент. Тот, кто вошёл, может делать то же, что и thronectl, включая административные запросы: импортировать и удалять профили, менять настройки, скачивать резервные копии, которые содержат учётные данные ваших профилей и секреты OTP в открытом виде, восстанавливать резервные копии, перезапускать Throne и завершать его работу. Давайте пароль только тем, кому можно управлять Throne.
  • Ключ API остаётся у шлюза. Браузер никогда его не получает. Он получает только cookie сеанса и токен сеанса, и каждый запрос требует и то, и другое.
  • Ограничения входа. После 5 неудачных попыток входа за 5 минут с одного адреса (для IPv6 — из одной сети /64) шлюз отклоняет вход с этого адреса на 60 секунд, а после каждой следующей неудачи — вдвое дольше, но не больше 15 минут. Если всего за минуту не удаётся больше 30 попыток входа, он отклоняет любой вход, пока эта минута не пройдёт. Успешный вход сбрасывает неудачи своего адреса. Неудачная попытка входа длится не меньше полсекунды, а лог шлюза называет заблокированные адреса.
  • Первый пароль остаётся в логе. Журнал systemd могут читать root и участники групп, например adm или systemd-journal; лог контейнера — все, кому разрешено запускать docker. Смените пароль после первого входа.
  • Предпочитайте loopback и туннель SSH. В сети используйте HTTPS и проверяйте отпечаток сертификата или используйте сертификат, которому доверяют браузеры. Обычный HTTP на сетевом адресе передаёт пароль и сеанс без шифрования; шлюз предупреждает об этом при запуске.
  • Запускайте шлюз на устройстве с Throne. Тогда API Throne может оставаться на loopback. Шлюзу на другом устройстве нужен API в сети, а для административных запросов — --api-admin-lan.

Устранение неполадок

Симптом Причина и решение
Throne is not reachable. Retrying… (throne_unreachable) Throne не запущен, его API выключен или у шлюза неверный адрес. Проверьте --addr или THRONE_ADDR и выполните thronectl status с настройками шлюза. Веб-интерфейс повторяет попытку каждые 2 секунды и обновляется, когда Throne отвечает.
Throne refuses the web UI или Throne refused the connection (throne_rejected) У шлюза неверный ключ. Дайте шлюзу текущий ключ Throne (config/api.key в каталоге данных headless Throne) и перезапустите его. Шлюз на другом устройстве Throne может также отклонять на 60 секунд после 5 неудачных попыток с его адреса, например из-за другого клиента со старым ключом с того же адреса.
The web UI's connection to Throne lacks admin rights (forbidden): лог, импорт, настройки, удаление, резервные копии, перезапуск и завершение работы не выполняются Шлюз работает не на устройстве с Throne, а Throne отвечает на административные запросы только оттуда. Запустите шлюз на устройстве с Throne или разрешите Throne отвечать на административные запросы из сети: --api-admin-lan (THRONE_API_ADMIN_LAN=1) для headless Throne, Разрешить управление из локальной сети (Allow management from the local network) в приложении для компьютера. Страница System показывает, есть ли у шлюза права администратора.
421 Misdirected Request: this host name is not accepted Проверка Host: вы открыли шлюз по имени, которое он не принимает. Используйте localhost или IP-адрес либо добавьте имя через --allow-host.
За обратным прокси не удаётся войти: The web UI server refused the request because it came from another origin (403 csrf) Прокси меняет заголовок Host. Передавайте его без изменений, например с proxy_set_header Host $http_host; в nginx.
Too many failed attempts. Try again in … s. (rate_limited) Подождите, пока закончится обратный отсчёт. См. Безопасность.
Браузер предупреждает о сертификате Так и должно быть с самоподписанным сертификатом. Сравните отпечатки, как описано в разделе Локальная сеть.
thronectl web завершается: address already in use; --listen picks another address Порт 9096 занят другой программой или другим thronectl web. Остановите её или укажите другой --listen.
Восстановление резервной копии через nginx завершается ошибкой 413 Задайте client_max_body_size 512m;.
Страница Logs сообщает This Throne is too old to share its log with the web UI, или изменения, сделанные в окне Throne, появляются с задержкой до 30 секунд Throne старее шлюза, и в нём нет GET /v1/logs или GET /v1/events. Без событий шлюз читает состояние Throne каждые 2 секунды, а всё остальное — каждые 30 секунд. Обновите Throne.
The password comes from a password file Измените файл, указанный в --password-file. Шлюз замечает изменение в течение 5 секунд.