Сервис на удаленной машине (вопрос) #1

Closed
opened 2026-09-26 08:01:56 +00:00 by forgejo-admin · 5 comments

Сейчас уже можно например подключить systemd сервис на linux машине, а смотреть данные (UI) на своей Windows машине?

Сейчас уже можно например подключить systemd сервис на linux машине, а смотреть данные (UI) на своей Windows машине?
Collaborator

Да, уже можно — всё для этого в проекте готово.

Как это устроено сейчас

watcherenish — обычное веб-приложение (Node.js ≥ 20, без внешних зависимостей). Сам сервис ставится на Linux-машину, где работает агент pi, а UI открывается в браузере — на Windows-машине ничего устанавливать не нужно.

  1. На Linux-машине — systemd-юнит из репозитория:
sudo cp deploy/pi-web-monitor.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now pi-web-monitor

Перед этим поправьте в юните User=, WorkingDirectory= и SESSIONS_DIR= под своего пользователя (по умолчанию там pi и /home/pi/.pi/agent/sessions).

  1. Доступ с Windows-машины — два варианта:
  • SSH-туннель (рекомендуется): ssh -L 8787:127.0.0.1:8787 user@linux-host, затем в браузере открыть http://localhost:8787. Сервис по умолчанию слушает только 127.0.0.1 и наружу не торчит. Альтернатива — Tailscale.
  • Прямой доступ по доверенной сети: в юните задать BIND=0.0.0.0 и раскомментировать AUTH_TOKEN=<секрет>. Без токена сервер на 0.0.0.0 сознательно откажется стартовать (проверка в src/config.js). Токен вводится один раз в UI. Внимание: транскрипты содержат содержимое файлов и вывод команд — выставлять UI в интернет нельзя, только доверенная сеть.

Суть: Linux нужен только на машине, где пишет агент (там лежат ~/.pi/agent/sessions и gate.log, сервис их читает); Windows — просто «тонкий клиент» с браузером.

Если хотите что-то изменить под этот сценарий (например, задокументировать его в README или упростить настройку туннеля) — скажите, оформлю отдельной задачей. Пока вопрос содержательный ответа не требует кода, перевожу в blocked до вашей реакции.

Да, уже можно — всё для этого в проекте готово. **Как это устроено сейчас** `watcherenish` — обычное веб-приложение (Node.js ≥ 20, без внешних зависимостей). Сам сервис ставится на Linux-машину, где работает агент pi, а UI открывается в браузере — на Windows-машине ничего устанавливать не нужно. 1. На Linux-машине — systemd-юнит из репозитория: ```bash sudo cp deploy/pi-web-monitor.service /etc/systemd/system/ sudo systemctl daemon-reload sudo systemctl enable --now pi-web-monitor ``` Перед этим поправьте в юните `User=`, `WorkingDirectory=` и `SESSIONS_DIR=` под своего пользователя (по умолчанию там `pi` и `/home/pi/.pi/agent/sessions`). 2. Доступ с Windows-машины — два варианта: - **SSH-туннель (рекомендуется)**: `ssh -L 8787:127.0.0.1:8787 user@linux-host`, затем в браузере открыть `http://localhost:8787`. Сервис по умолчанию слушает только `127.0.0.1` и наружу не торчит. Альтернатива — Tailscale. - **Прямой доступ по доверенной сети**: в юните задать `BIND=0.0.0.0` и раскомментировать `AUTH_TOKEN=<секрет>`. Без токена сервер на `0.0.0.0` сознательно откажется стартовать (проверка в `src/config.js`). Токен вводится один раз в UI. Внимание: транскрипты содержат содержимое файлов и вывод команд — выставлять UI в интернет нельзя, только доверенная сеть. **Суть**: Linux нужен только на машине, где пишет агент (там лежат `~/.pi/agent/sessions` и `gate.log`, сервис их читает); Windows — просто «тонкий клиент» с браузером. Если хотите что-то изменить под этот сценарий (например, задокументировать его в README или упростить настройку туннеля) — скажите, оформлю отдельной задачей. Пока вопрос содержательный ответа не требует кода, перевожу в `blocked` до вашей реакции.
Author
Owner

А можем ли мы это разделить концептуально? То есть должен быть UI независимый, в нем я хочу иметь возможность подключить агента. Например я запускаю UI на своей Windows машине, там выбираю пункт - подключить агента. Мне предлагает ввести какие то данные, например, ip адрес, название, описание и так далее (только нужное). После подтверждения, проверяется что на указанной машине подключен systemctl service (банальный healthcheck) и если все ок, то я начинаю видеть его на своем UI. Я могу "провалиться" в него и посмотреть все данные, которые есть сейчас.

А можем ли мы это разделить концептуально? То есть должен быть UI независимый, в нем я хочу иметь возможность подключить агента. Например я запускаю UI на своей Windows машине, там выбираю пункт - подключить агента. Мне предлагает ввести какие то данные, например, ip адрес, название, описание и так далее (только нужное). После подтверждения, проверяется что на указанной машине подключен systemctl service (банальный healthcheck) и если все ок, то я начинаю видеть его на своем UI. Я могу "провалиться" в него и посмотреть все данные, которые есть сейчас.
Collaborator

Да, разделить можно — текущая архитектура к этому уже почти готова.

Что уже есть

Сервер — монолит из двух слабо связанных половин: статический UI (public/) и REST API (/api/* в src/server.js) с Bearer-авторизацией. UI данные не хранит — всё берёт из API. То есть «независимый UI + сервис на машине агента» уже фактически работает (systemd-юнит в deploy/, страница открывается откуда угодно). Сейчас они просто живут на одном origin, протокольной связки нет.

Целевая схема — как вы описали

  1. UI становится «хабом агентов»: страница хранит список подключений — имя, описание, host:port, токен (в localStorage, как сейчас хранится токен одного сервера).
  2. «Подключить агента» — форма (нужное минимум: имя, адрес, токен; описание опционально), после подтверждения — healthcheck.
  3. Healthcheck: dedicated GET /api/health на стороне агента (сейчас его нет). Тот же Bearer-токен: тогда подключение различает три состояния — «машина/порт недоступны» (сетевая ошибка), «сервис есть, токен неверный» (401), «OK» (200: процесс жив, SESSIONS_DIR существует). Анонимный health-эндпоинт делать не предлагаю — он палит существование сервиса.
  4. Переключение агентов — селектор в шапке; все вызовы API идут к base URL выбранного агента. Существующие экраны (сводка, сессии, транскрипт, gate.log) переезжают без изменения логики — меняется только база запросов.
  5. CORS: сейчас сервер не отдаёт CORS-заголовки — при открытии хаба с другого origin браузер заблокирует запросы. Нужен конфиг ALLOWED_ORIGINS на агенте (либо хаб продолжит раздаваться каждым агентом, как сейчас, а «хаб» — просто отдельная страница/приложение).
  6. Безопасность — как и сейчас: доверенная сеть, SSH-туннель или Tailscale; для чистого HTTP вне туннеля токен виден в трафике. Read-only гарантии остаются на стороне сервера агента. У каждого агента свой порт/токен, отзыв = смена AUTH_TOKEN + рестарт юнита.

Разбивка на этапы

  • Этап A (маленький PR, сервер): GET /api/health + ALLOWED_ORIGINS (CORS) + тесты. Обратно совместимо, текущий сценарий «UI с того же origin» не ломается.
  • Этап B (средний PR, UI): реестр агентов в localStorage, модалка «Подключить агента» с healthcheck, переключатель агентов в шапке, все запросы через base URL выбранного агента.
  • Этап C (опционально): упаковка UI в десктоп-приложение (Tauri/Electron). Не обязателен — браузерной страницы достаточно; имеет смысл, только если хочется «нативного» ярлыка на Windows.

Со своей стороны для старта жду подтверждения: делаем по этапам A → B (C пока не трогаем)? Если да — оформлю подзадачами и начну с этапа A. Пока жду реакции, оставляю issue в blocked.

Да, разделить можно — текущая архитектура к этому уже почти готова. **Что уже есть** Сервер — монолит из двух слабо связанных половин: статический UI (`public/`) и REST API (`/api/*` в `src/server.js`) с Bearer-авторизацией. UI данные не хранит — всё берёт из API. То есть «независимый UI + сервис на машине агента» уже фактически работает (systemd-юнит в `deploy/`, страница открывается откуда угодно). Сейчас они просто живут на одном origin, протокольной связки нет. **Целевая схема — как вы описали** 1. UI становится «хабом агентов»: страница хранит список подключений — имя, описание, `host:port`, токен (в localStorage, как сейчас хранится токен одного сервера). 2. «Подключить агента» — форма (нужное минимум: имя, адрес, токен; описание опционально), после подтверждения — healthcheck. 3. Healthcheck: dedicated `GET /api/health` на стороне агента (сейчас его нет). Тот же Bearer-токен: тогда подключение различает три состояния — «машина/порт недоступны» (сетевая ошибка), «сервис есть, токен неверный» (401), «OK» (200: процесс жив, `SESSIONS_DIR` существует). Анонимный health-эндпоинт делать не предлагаю — он палит существование сервиса. 4. Переключение агентов — селектор в шапке; все вызовы API идут к base URL выбранного агента. Существующие экраны (сводка, сессии, транскрипт, gate.log) переезжают без изменения логики — меняется только база запросов. 5. CORS: сейчас сервер не отдаёт CORS-заголовки — при открытии хаба с другого origin браузер заблокирует запросы. Нужен конфиг `ALLOWED_ORIGINS` на агенте (либо хаб продолжит раздаваться каждым агентом, как сейчас, а «хаб» — просто отдельная страница/приложение). 6. Безопасность — как и сейчас: доверенная сеть, SSH-туннель или Tailscale; для чистого HTTP вне туннеля токен виден в трафике. Read-only гарантии остаются на стороне сервера агента. У каждого агента свой порт/токен, отзыв = смена `AUTH_TOKEN` + рестарт юнита. **Разбивка на этапы** - **Этап A (маленький PR, сервер):** `GET /api/health` + `ALLOWED_ORIGINS` (CORS) + тесты. Обратно совместимо, текущий сценарий «UI с того же origin» не ломается. - **Этап B (средний PR, UI):** реестр агентов в localStorage, модалка «Подключить агента» с healthcheck, переключатель агентов в шапке, все запросы через base URL выбранного агента. - **Этап C (опционально):** упаковка UI в десктоп-приложение (Tauri/Electron). Не обязателен — браузерной страницы достаточно; имеет смысл, только если хочется «нативного» ярлыка на Windows. Со своей стороны для старта жду подтверждения: делаем по этапам A → B (C пока не трогаем)? Если да — оформлю подзадачами и начну с этапа A. Пока жду реакции, оставляю issue в `blocked`.
Author
Owner

Можешь создать issues с Этапом A и B? Если да, сделай это. Назначь себя в качестве исполнителя

Можешь создать issues с Этапом A и B? Если да, сделай это. Назначь себя в качестве исполнителя
Collaborator

Готово:

  • #5 — Этап A: healthcheck /api/health + CORS (ALLOWED_ORIGINS), исполнитель — я.
  • #6 — Этап B: UI-хаб агентов (реестр подключений, модалка «Подключить агента» с healthcheck, переключение base URL), исполнитель — я; делаю после #5, так как переключение на удалённого агента без его healthcheck не проверить.

Берусь за Этап A, ветка feature/5_api_health_and_cors. #1 оставляю зонтичной задачей плана хаба и перевожу в in_progress — прогресс буду отражать в #5/#6.

Готово: - #5 — **Этап A**: healthcheck `/api/health` + CORS (`ALLOWED_ORIGINS`), исполнитель — я. - #6 — **Этап B**: UI-хаб агентов (реестр подключений, модалка «Подключить агента» с healthcheck, переключение base URL), исполнитель — я; делаю после #5, так как переключение на удалённого агента без его healthcheck не проверить. Берусь за Этап A, ветка `feature/5_api_health_and_cors`. #1 оставляю зонтичной задачей плана хаба и перевожу в `in_progress` — прогресс буду отражать в #5/#6.
Sign in to join this conversation.
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
forgejo-admin/watcherenish#1
No description provided.