Bind to all interfaces by default and add one-command uninstall script #12

Merged
forgejo-admin merged 6 commits from feature/11_bind_default_and_uninstall into main 2026-09-26 15:15:55 +00:00
Collaborator

Closes #11

Что сделано

Пункт 2 — доступ с Windows-машины (BIND=0.0.0.0)

  • deploy/install.sh: дефолт BIND изменён на 0.0.0.0; токен AUTH_TOKEN для сетевого режима генерируется автоматически при первой установке (защита от «голого» сетевого доступа уже есть в конфиге сервиса).
  • Итоговая сводка установки показывает реальный адрес вида http://<IP-машины>:8787 (IP определяется автоматически) плюс локальный 127.0.0.1; предупреждение про сетевой доступ заменено на честное «вход защищён AUTH_TOKEN, в интернет порт не пробрасывать».
  • Так как конфиг при переустановках не перетирается, сводка показывает BIND из действующего /etc/default/pi-web-monitor, а не из переменных текущего запуска.

Пункт 3 — удаление

  • Новый deploy/uninstall.sh («одна команда», по аналогии с установкой): останавливает и удаляет systemd-юнит, удаляет код /opt/watcherenish (только если это клон именно watcherenish — проверка по origin) и конфиг /etc/default/pi-web-monitor. Node.js/git/curl и данные ~/.pi не трогает. Идемпотентен.
  • В конце сводки установки печатается команда удаления (ссылка на uninstall.sh той же ветки).
  • В README добавлен раздел «Удаление» + обновлены разделы про сетевой доступ и безопасность.

Пункт 1 («зачем TUI на Linux-машине») — правок не требует, объяснение в комментарии к issue: полноценного терминального интерфейса на машине нет и не было — это headless веб-сервис; «объёмный» интерфейс видит только браузер клиента, сама машина остаётся поставщиком данных.

По ходу ревью

  • 0e4f5bb — CORS открыт по умолчанию (по решению заказчика): ALLOWED_ORIGINS не задан → агент отвечает Access-Control-Allow-Origin любому origin на /api/* (токен остаётся обязателен); задан → белый список.
  • 6946ef2 — все скрипты и README переведены на https://forgejo.lamanshe.ru.
  • 6d692f1 + eeb5e70 — установщик больше не молчит про ветку: код ставится из main (даже если сам скрипт взят из ветки PR — раньше это путало), а ветку можно передать первым аргументом или BRANCH=…; явная ветка проверяется git ls-remote, в сводке — напоминание вернуться на main после проверки PR.

Как проверить

# установить код из ветки PR (проверка CORS-дефолта «открыто всем»):
curl -fsSL https://forgejo.lamanshe.ru/forgejo-admin/watcherenish/raw/branch/main/deploy/install.sh | sudo bash -s feature/11_bind_default_and_uninstall
# в сводке должно быть: Код: /opt/watcherenish (ветка feature/11_bind_default_and_uninstall)

# проверка CORS с токеном (должен появиться Access-Control-Allow-Origin):
curl -s -D - -o /dev/null \
  -H "Origin: https://forgejo.lamanshe.ru" \
  -H "Authorization: Bearer $(grep '^AUTH_TOKEN=' /etc/default/pi-web-monitor | cut -d= -f2)" \
  http://127.0.0.1:8787/api/health

# возврат на main (после мержа):
curl -fsSL https://forgejo.lamanshe.ru/forgejo-admin/watcherenish/raw/branch/main/deploy/install.sh | sudo bash

# удаление (идемпотентно, можно прогнать дважды):
curl -fsSL https://forgejo.lamanshe.ru/forgejo-admin/watcherenish/raw/branch/feature/11_bind_default_and_uninstall/deploy/uninstall.sh | sudo bash
# проверить: systemctl status pi-web-monitor (юнит не найден), /opt/watcherenish и /etc/default/pi-web-monitor отсутствуют

Тесты

  • npm test — 33/33 зелёные.
  • uninstall.sh прогнан в песочнице (фейковые INSTALL_DIR/ENV_FILE/SERVICE_NAME): клон watcherenish и конфиг удаляются, чужой git-репозиторий не трогается, повторный запуск чистый, без root скрипт отказывается работать.
  • install.sh прогнан в песочнице на 4 сценария: ветка аргументом (клон в origin/ветку PR), ветка через BRANCH=…, без аргументов (ставит main + подсказка), несуществующая ветка (внятная ошибка до каких-либо изменений).
  • Полный цикл install→uninstall на реальной машине с systemd — за установщиком.
Closes #11 ## Что сделано **Пункт 2 — доступ с Windows-машины (`BIND=0.0.0.0`)** - `deploy/install.sh`: дефолт `BIND` изменён на `0.0.0.0`; токен `AUTH_TOKEN` для сетевого режима генерируется автоматически при первой установке (защита от «голого» сетевого доступа уже есть в конфиге сервиса). - Итоговая сводка установки показывает реальный адрес вида `http://<IP-машины>:8787` (IP определяется автоматически) плюс локальный `127.0.0.1`; предупреждение про сетевой доступ заменено на честное «вход защищён AUTH_TOKEN, в интернет порт не пробрасывать». - Так как конфиг при переустановках не перетирается, сводка показывает BIND из действующего `/etc/default/pi-web-monitor`, а не из переменных текущего запуска. **Пункт 3 — удаление** - Новый `deploy/uninstall.sh` («одна команда», по аналогии с установкой): останавливает и удаляет systemd-юнит, удаляет код `/opt/watcherenish` (только если это клон именно watcherenish — проверка по `origin`) и конфиг `/etc/default/pi-web-monitor`. Node.js/git/curl и данные `~/.pi` не трогает. Идемпотентен. - В конце сводки установки печатается команда удаления (ссылка на `uninstall.sh` той же ветки). - В README добавлен раздел «Удаление» + обновлены разделы про сетевой доступ и безопасность. **Пункт 1 («зачем TUI на Linux-машине»)** — правок не требует, объяснение в комментарии к issue: полноценного терминального интерфейса на машине нет и не было — это headless веб-сервис; «объёмный» интерфейс видит только браузер клиента, сама машина остаётся поставщиком данных. **По ходу ревью** - `0e4f5bb` — CORS открыт по умолчанию (по решению заказчика): `ALLOWED_ORIGINS` не задан → агент отвечает `Access-Control-Allow-Origin` любому origin на `/api/*` (токен остаётся обязателен); задан → белый список. - `6946ef2` — все скрипты и README переведены на `https://forgejo.lamanshe.ru`. - `6d692f1` + `eeb5e70` — установщик больше не молчит про ветку: код ставится из `main` (даже если сам скрипт взят из ветки PR — раньше это путало), а ветку можно передать первым аргументом или `BRANCH=…`; явная ветка проверяется `git ls-remote`, в сводке — напоминание вернуться на `main` после проверки PR. ## Как проверить ```bash # установить код из ветки PR (проверка CORS-дефолта «открыто всем»): curl -fsSL https://forgejo.lamanshe.ru/forgejo-admin/watcherenish/raw/branch/main/deploy/install.sh | sudo bash -s feature/11_bind_default_and_uninstall # в сводке должно быть: Код: /opt/watcherenish (ветка feature/11_bind_default_and_uninstall) # проверка CORS с токеном (должен появиться Access-Control-Allow-Origin): curl -s -D - -o /dev/null \ -H "Origin: https://forgejo.lamanshe.ru" \ -H "Authorization: Bearer $(grep '^AUTH_TOKEN=' /etc/default/pi-web-monitor | cut -d= -f2)" \ http://127.0.0.1:8787/api/health # возврат на main (после мержа): curl -fsSL https://forgejo.lamanshe.ru/forgejo-admin/watcherenish/raw/branch/main/deploy/install.sh | sudo bash # удаление (идемпотентно, можно прогнать дважды): curl -fsSL https://forgejo.lamanshe.ru/forgejo-admin/watcherenish/raw/branch/feature/11_bind_default_and_uninstall/deploy/uninstall.sh | sudo bash # проверить: systemctl status pi-web-monitor (юнит не найден), /opt/watcherenish и /etc/default/pi-web-monitor отсутствуют ``` ## Тесты - `npm test` — 33/33 зелёные. - `uninstall.sh` прогнан в песочнице (фейковые `INSTALL_DIR`/`ENV_FILE`/`SERVICE_NAME`): клон watcherenish и конфиг удаляются, чужой git-репозиторий не трогается, повторный запуск чистый, без root скрипт отказывается работать. - `install.sh` прогнан в песочнице на 4 сценария: ветка аргументом (клон в origin/ветку PR), ветка через `BRANCH=…`, без аргументов (ставит `main` + подсказка), несуществующая ветка (внятная ошибка до каких-либо изменений). - Полный цикл install→uninstall на реальной машине с systemd — за установщиком.
- install.sh: default BIND=0.0.0.0 (AUTH_TOKEN required and auto-generated),
  final summary shows the machine's LAN address and the uninstall command
- add deploy/uninstall.sh: stops/removes the systemd unit, deletes the
  service code (only if it is this project's clone) and the env config;
  Node.js and system packages are left intact
- README: new uninstall section, network access and security notes updated
The config file survives reinstalls, so the summary must reflect the BIND
value the service will actually run with, not the one passed to this run.

"Агент доступен, но браузер заблокировал запрос (CORS). Добавьте адрес этого хаба в ALLOWED_ORIGINS на агенте." - ошибка при подключении агента.

"Агент доступен, но браузер заблокировал запрос (CORS). Добавьте адрес этого хаба в ALLOWED_ORIGINS на агенте." - ошибка при подключении агента.
Author
Collaborator

Разобрался: это не сбой, а штатная защита агента. По умолчанию агент работает в same-origin режиме (CORS opt-in, сделано в #5): он не отдаёт CORS-заголовки никому, поэтому браузер на странице хаба блокирует кросс-доменный запрос к http://<агент>:8787/api/health. Сообщение «Добавьте адрес этого хаба в ALLOWED_ORIGINS на агенте» — ровно об этом.

Что сделать на машине агента:

  1. В /etc/default/pi-web-monitor установить:
    ALLOWED_ORIGINS=http://<IP-машины-хаба>:8787
    
    Origin указывается точно в том виде, в каком он в адресной строке браузера: схема + host + порт, без завершающего слэша. Несколько hub-ов — через запятую.
  2. Применить: sudo systemctl restart pi-web-monitor.
  3. В UI хаба повторить подключение агента (healthcheck должен стать ok).

Удобно: адрес хаба именно в этом формате печатается в итоговой сводке установки хаба (http://<IP>:8787) — можно скопировать оттуда.

По безопасности: ALLOWED_ORIGINS лишь разрешает браузеру указанного origin читать ответы агента; bearer-токен обязателен для всех /api/* как и раньше. Порт агента наружу в интернет по-прежнему открывать не стоит.

Если после этого ошибка осталась, проверьте:

  • origin в конфиге совпадает с адресом хаба байт-в-байт (http vs https, порт, без слэша);
  • рестарт реально выполнен;
  • диагностика: curl -s -D - -o /dev/null -H "Origin: http://<IP-хаба>:8787" http://127.0.0.1:8787/api/health — в ответе должен появиться Access-Control-Allow-Origin.

Если хотите, могу добавить в install.sh агента опциональный вопрос «адрес хаба для CORS» (сразу пропишет ALLOWED_ORIGINS в конфиг) — скажите, внесу в эту же ветку.

Разобрался: это не сбой, а штатная защита агента. По умолчанию агент работает в same-origin режиме (CORS opt-in, сделано в #5): он не отдаёт CORS-заголовки никому, поэтому браузер на странице хаба блокирует кросс-доменный запрос к `http://<агент>:8787/api/health`. Сообщение «Добавьте адрес этого хаба в ALLOWED_ORIGINS на агенте» — ровно об этом. **Что сделать на машине агента:** 1. В `/etc/default/pi-web-monitor` установить: ``` ALLOWED_ORIGINS=http://<IP-машины-хаба>:8787 ``` Origin указывается точно в том виде, в каком он в адресной строке браузера: схема + host + порт, без завершающего слэша. Несколько hub-ов — через запятую. 2. Применить: `sudo systemctl restart pi-web-monitor`. 3. В UI хаба повторить подключение агента (healthcheck должен стать ok). Удобно: адрес хаба именно в этом формате печатается в итоговой сводке установки хаба (`http://<IP>:8787`) — можно скопировать оттуда. **По безопасности:** `ALLOWED_ORIGINS` лишь разрешает браузеру указанного origin читать ответы агента; bearer-токен обязателен для всех `/api/*` как и раньше. Порт агента наружу в интернет по-прежнему открывать не стоит. **Если после этого ошибка осталась**, проверьте: - origin в конфиге совпадает с адресом хаба байт-в-байт (http vs https, порт, без слэша); - рестарт реально выполнен; - диагностика: `curl -s -D - -o /dev/null -H "Origin: http://<IP-хаба>:8787" http://127.0.0.1:8787/api/health` — в ответе должен появиться `Access-Control-Allow-Origin`. Если хотите, могу добавить в `install.sh` агента опциональный вопрос «адрес хаба для CORS» (сразу пропишет `ALLOWED_ORIGINS` в конфиг) — скажите, внесу в эту же ветку.

А можно ли разрешить всем? У нас ведь есть AUTH токен - я думаю этого достаточно.

  1. Можно ли это сделать сразу на машине?
  2. Сделай чтобы так было по умолчанию, но оставь возможность задать конкретные ALLOWED_ORIGINS
А можно ли разрешить всем? У нас ведь есть AUTH токен - я думаю этого достаточно. 1. Можно ли это сделать сразу на машине? 2. Сделай чтобы так было по умолчанию, но оставь возможность задать конкретные ALLOWED_ORIGINS
All /api/* routes already require the Bearer token, so reflecting any Origin
by default is safe: third-party sites cannot read session data without the
token. Setting ALLOWED_ORIGINS now narrows CORS to an explicit allowlist
instead of enabling it. UI error hint, README and installer comments updated.
Author
Collaborator

Сделал в коммите 0e4f5bb (ветка feature/11_bind_default_and_uninstall, тот же PR).

По безопасности: да, токена достаточно. Все /api/* и так требуют Bearer-токен, поэтому открытый CORS не позволяет сторонним сайтам читать данные — без токена они получают 401. CORS управляет лишь тем, ч какой origin браузер разрешит JS читать ответы.

1. Можно ли это сделать сразу на машине? Ничего настраивать не нужно: теперь это поведение по умолчанию. Достаточно обновить код и перезапустить сервис:

curl -fsSL http://10.10.1.7:3000/forgejo-admin/watcherenish/raw/branch/feature/11_bind_default_and_uninstall/deploy/install.sh | sudo bash

Установщик сам подтянет ветку (git reset --hard origin/…), отрестартит pi-web-monitor, конфиг в /etc/default/pi-web-monitor не перетрёт. После обновления подключение агента из хаба заработает без правки конфига.

2. Поведение по умолчанию:

  • ALLOWED_ORIGINS не задан (дефолт) → CORS открыт: агент отвечает Access-Control-Allow-Origin: <Origin> любому origin на /api/*.
  • ALLOWED_ORIGINS задан → работает как белый список: только перечисленные origin (старое поведение, для строгих окружений).

Обновил: сервер (src/server.js), README (переменная + раздел «Безопасность»), подсказку об ошибке в UI хаба и комментарий в шаблоне конфига установщика. npm test — 33/33 зелёные (включая новые тесты на allow-all и на то, что явный список продолжает отсекать чужие origin).

Сделал в коммите `0e4f5bb` (ветка `feature/11_bind_default_and_uninstall`, тот же PR). По безопасности: да, токена достаточно. Все `/api/*` и так требуют Bearer-токен, поэтому открытый CORS не позволяет сторонним сайтам читать данные — без токена они получают 401. CORS управляет лишь тем, *ч какой origin браузер разрешит JS читать ответы*. **1. Можно ли это сделать сразу на машине?** Ничего настраивать не нужно: теперь это поведение по умолчанию. Достаточно обновить код и перезапустить сервис: ```bash curl -fsSL http://10.10.1.7:3000/forgejo-admin/watcherenish/raw/branch/feature/11_bind_default_and_uninstall/deploy/install.sh | sudo bash ``` Установщик сам подтянет ветку (`git reset --hard origin/…`), отрестартит `pi-web-monitor`, конфиг в `/etc/default/pi-web-monitor` не перетрёт. После обновления подключение агента из хаба заработает без правки конфига. **2. Поведение по умолчанию:** - `ALLOWED_ORIGINS` **не задан** (дефолт) → CORS открыт: агент отвечает `Access-Control-Allow-Origin: <Origin>` любому origin на `/api/*`. - `ALLOWED_ORIGINS` **задан** → работает как белый список: только перечисленные origin (старое поведение, для строгих окружений). Обновил: сервер (`src/server.js`), README (переменная + раздел «Безопасность»), подсказку об ошибке в UI хаба и комментарий в шаблоне конфига установщика. `npm test` — 33/33 зелёные (включая новые тесты на allow-all и на то, что явный список продолжает отсекать чужие origin).

Я попробовал без удаления - не заработало. Решил переустановить - вот такие ошибки:
root@developer-agent:# curl -fsSL http://10.10.1.7:3000/forgejo-admin/watcherenish/raw/branch/main/deploy/uninstall.sh | sudo bash
curl: (22) The requested URL returned error: 404
root@developer-agent:
# curl -fsSL http://forgejo.lamanshe.ru/forgejo-admin/watcherenish/raw/branch/main/deploy/uninstall.sh | sudo bash
curl: (22) The requested URL returned error: 404
root@developer-agent:# curl -fsSL https://forgejo.lamanshe.ru/forgejo-admin/watcherenish/raw/branch/main/deploy/uninstall.sh | sudo bash
curl: (22) The requested URL returned error: 404
root@developer-agent:
# ping forgejo.lamanshe.ru

P.S. я настроил домен на forgejo.lamanshe.ru, теперь это будет https://forgejo.lamanshe.ru вместо http://10.10.1.7:3000

Я попробовал без удаления - не заработало. Решил переустановить - вот такие ошибки: root@developer-agent:~# curl -fsSL http://10.10.1.7:3000/forgejo-admin/watcherenish/raw/branch/main/deploy/uninstall.sh | sudo bash curl: (22) The requested URL returned error: 404 root@developer-agent:~# curl -fsSL http://forgejo.lamanshe.ru/forgejo-admin/watcherenish/raw/branch/main/deploy/uninstall.sh | sudo bash curl: (22) The requested URL returned error: 404 root@developer-agent:~# curl -fsSL https://forgejo.lamanshe.ru/forgejo-admin/watcherenish/raw/branch/main/deploy/uninstall.sh | sudo bash curl: (22) The requested URL returned error: 404 root@developer-agent:~# ping forgejo.lamanshe.ru P.S. я настроил домен на forgejo.lamanshe.ru, теперь это будет https://forgejo.lamanshe.ru вместо http://10.10.1.7:3000
Author
Collaborator

Разобрался по пунктам:

1. Почему 404. uninstall.sh — новый файл из этого PR, он есть только в ветке feature/11_bind_default_and_uninstall; в main он попадёт после мержа. Команды из README (и из моего прошлого комментария) с branch/main для uninstall сработают только после того, как PR уйдёт в main. Сейчас удалять нужно из ветки PR:

curl -fsSL https://forgejo.lamanshe.ru/forgejo-admin/watcherenish/raw/branch/feature/11_bind_default_and_uninstall/deploy/uninstall.sh | sudo bash

(проверил: по обоим адресам — и по IP, и по домену — этот URL отдаёт 200; 404 был именно из-за ветки main, домен ни при чём).

2. Новый домен — принято, перевёл всё на https://forgejo.lamanshe.ru (коммит 6946ef2 в этой же ветке): дефолтный REPO_URL в deploy/install.sh и deploy/uninstall.sh, команды установки/удаления и git clone в README. Старый адрес http://10.10.1.7:3000 при этом продолжает работать, существующие установки не ломаются.

3. «Попробовал без удаления — не заработало». Скорее всего дело в конфиге: если ранее по моей инструкции в /etc/default/pi-web-monitor выставлялся ALLOWED_ORIGINS=<адрес хаба> — этот белый список теперь блокирует новый origin хаба (https://forgejo.lamanshe.ru…). С нового дефолта (CORS открыт всем, токен остаётся обязательным) достаточно убрать строку ALLOWED_ORIGINS из конфига (или обновить в ней адрес хаба) и перезапустить сервис. Порядок обновления без удаления:

# на машине АГЕНТА — обновить код (конфиг не перетирается):
curl -fsSL https://forgejo.lamanshe.ru/forgejo-admin/watcherenish/raw/branch/feature/11_bind_default_and_uninstall/deploy/install.sh | sudo bash
# если в /etc/default/pi-web-monitor есть ALLOWED_ORIGINS — удалить/закомментировать эту строку
sudo systemctl restart pi-web-monitor
# проверка CORS (должен появиться заголовок Access-Control-Allow-Origin):
curl -s -D - -o /dev/null -H "Origin: https://forgejo.lamanshe.ru" http://127.0.0.1:8787/api/health

Если после этого подключение всё равно не проходит — пришлите вывод последней команды и содержимое /etc/default/pi-web-monitor (токен можно затереть), посмотрю.

Сводку в теле PR обновил под новый домен.

Разобрался по пунктам: **1. Почему 404.** `uninstall.sh` — новый файл из этого PR, он есть только в ветке `feature/11_bind_default_and_uninstall`; в `main` он попадёт после мержа. Команды из README (и из моего прошлого комментария) с `branch/main` для uninstall сработают только после того, как PR уйдёт в main. Сейчас удалять нужно из ветки PR: ```bash curl -fsSL https://forgejo.lamanshe.ru/forgejo-admin/watcherenish/raw/branch/feature/11_bind_default_and_uninstall/deploy/uninstall.sh | sudo bash ``` (проверил: по обоим адресам — и по IP, и по домену — этот URL отдаёт 200; 404 был именно из-за ветки `main`, домен ни при чём). **2. Новый домен — принято, перевёл всё на `https://forgejo.lamanshe.ru`** (коммит `6946ef2` в этой же ветке): дефолтный `REPO_URL` в `deploy/install.sh` и `deploy/uninstall.sh`, команды установки/удаления и `git clone` в README. Старый адрес `http://10.10.1.7:3000` при этом продолжает работать, существующие установки не ломаются. **3. «Попробовал без удаления — не заработало».** Скорее всего дело в конфиге: если ранее по моей инструкции в `/etc/default/pi-web-monitor` выставлялся `ALLOWED_ORIGINS=<адрес хаба>` — этот белый список теперь блокирует новый origin хаба (`https://forgejo.lamanshe.ru…`). С нового дефолта (CORS открыт всем, токен остаётся обязательным) достаточно **убрать строку `ALLOWED_ORIGINS` из конфига** (или обновить в ней адрес хаба) и перезапустить сервис. Порядок обновления без удаления: ```bash # на машине АГЕНТА — обновить код (конфиг не перетирается): curl -fsSL https://forgejo.lamanshe.ru/forgejo-admin/watcherenish/raw/branch/feature/11_bind_default_and_uninstall/deploy/install.sh | sudo bash # если в /etc/default/pi-web-monitor есть ALLOWED_ORIGINS — удалить/закомментировать эту строку sudo systemctl restart pi-web-monitor # проверка CORS (должен появиться заголовок Access-Control-Allow-Origin): curl -s -D - -o /dev/null -H "Origin: https://forgejo.lamanshe.ru" http://127.0.0.1:8787/api/health ``` Если после этого подключение всё равно не проходит — пришлите вывод последней команды и содержимое `/etc/default/pi-web-monitor` (токен можно затереть), посмотрю. Сводку в теле PR обновил под новый домен.

════════════════════════════════════════════════════════════
УСТАНОВКА ВЫПОЛНЕНА УСПЕШНО
Сервис: pi-web-monitor (systemd, включён автозапуск)
Код: /opt/watcherenish (ветка main)
Адрес: http://10.10.1.21:8787 (из локальной сети)
Локально: http://127.0.0.1:8787
Внимание: BIND=0.0.0.0 — UI доступен по сети, вход защищён AUTH_TOKEN;
пробрасывать порт в интернет не рекомендуется
Конфиг: /etc/default/pi-web-monitor (правки сохраняются при повторных установках)
AUTH_TOKEN: см. /etc/default/pi-web-monitor (не менялся)
Проверка: systemctl status pi-web-monitor
Удаление: curl -fsSL https://forgejo.lamanshe.ru/forgejo-admin/watcherenish/raw/branch/main/deploy/uninstall.sh | sudo bash
════════════════════════════════════════════════════════════
root@developer-agent:/projects/forgejo/developer# systemctl restart pi-web-monitor
root@developer-agent:
/projects/forgejo/developer# curl -s -D - -o /dev/null -H "Origin: https://forgejo.lamanshe.ru" http://127.0.0.1:8787/api/health
HTTP/1.1 401 Unauthorized
Content-Type: application/json; charset=utf-8
Content-Length: 24
Cache-Control: no-store
Date: Sat, 26 Sep 2026 13:38:12 GMT
Connection: keep-alive
Keep-Alive: timeout=5

root@developer-agent:~/projects/forgejo/developer# cat /etc/default/pi-web-monitor

watcherenish / pi-web-monitor — configuration

Created by deploy/install.sh on 2026-09-26 17:14:45 +05.

This file is NOT overwritten on reinstall: manual edits persist.

PORT=8787
BIND=0.0.0.0

Bearer token for /api/*; generated automatically on first install

AUTH_TOKEN=***
SESSIONS_DIR=/root/.pi/agent/sessions
GATE_LOG=/var/log/pi-agent/gate.log
ACTIVE_SESSION_TTL_MIN=15

Optional overrides:

#ALLOWED_ORIGINS=http://192.168.0.204:8787
#GATE_LINE_REGEX=
root@developer-agent:~/projects/forgejo/developer#

════════════════════════════════════════════════════════════ УСТАНОВКА ВЫПОЛНЕНА УСПЕШНО Сервис: pi-web-monitor (systemd, включён автозапуск) Код: /opt/watcherenish (ветка main) Адрес: http://10.10.1.21:8787 (из локальной сети) Локально: http://127.0.0.1:8787 Внимание: BIND=0.0.0.0 — UI доступен по сети, вход защищён AUTH_TOKEN; пробрасывать порт в интернет не рекомендуется Конфиг: /etc/default/pi-web-monitor (правки сохраняются при повторных установках) AUTH_TOKEN: см. /etc/default/pi-web-monitor (не менялся) Проверка: systemctl status pi-web-monitor Удаление: curl -fsSL https://forgejo.lamanshe.ru/forgejo-admin/watcherenish/raw/branch/main/deploy/uninstall.sh | sudo bash ════════════════════════════════════════════════════════════ root@developer-agent:~/projects/forgejo/developer# systemctl restart pi-web-monitor root@developer-agent:~/projects/forgejo/developer# curl -s -D - -o /dev/null -H "Origin: https://forgejo.lamanshe.ru" http://127.0.0.1:8787/api/health HTTP/1.1 401 Unauthorized Content-Type: application/json; charset=utf-8 Content-Length: 24 Cache-Control: no-store Date: Sat, 26 Sep 2026 13:38:12 GMT Connection: keep-alive Keep-Alive: timeout=5 root@developer-agent:~/projects/forgejo/developer# cat /etc/default/pi-web-monitor # watcherenish / pi-web-monitor — configuration # Created by deploy/install.sh on 2026-09-26 17:14:45 +05. # This file is NOT overwritten on reinstall: manual edits persist. PORT=8787 BIND=0.0.0.0 # Bearer token for /api/*; generated automatically on first install AUTH_TOKEN=*** SESSIONS_DIR=/root/.pi/agent/sessions GATE_LOG=/var/log/pi-agent/gate.log ACTIVE_SESSION_TTL_MIN=15 # Optional overrides: #ALLOWED_ORIGINS=http://192.168.0.204:8787 #GATE_LINE_REGEX= root@developer-agent:~/projects/forgejo/developer#
Author
Collaborator

Разобрался — код на машине обновился, но не до той ревизии.

Что произошло. В сводке видно: Код: /opt/watcherenish (ветка main). Установщик по умолчанию ставит ветку main, а правка «CORS открыт по умолчанию» (коммит 0e4f5bb) есть только в ветке PR feature/11_bind_default_and_uninstall — в main она попадёт после мержа. Поэтому агент работает ещё на старом CORS-режиме (opt-in), где пустой ALLOWED_ORIGINS = заголовки не выдаются, отсюда и 401 без Access-Control-Allow-Origin.

Кстати, сам факт 401 — это нормально: без Bearer-токена /api/* всегда отвечает 401. Для проверки CORS нужен запрос с заголовком Origin и токеном — тогда в ответе появится Access-Control-Allow-Origin:

curl -s -D - -o /dev/null \
  -H "Origin: https://forgejo.lamanshe.ru" \
  -H "Authorization: Bearer $(grep '^AUTH_TOKEN=' /etc/default/pi-web-monitor | cut -d= -f2)" \
  http://127.0.0.1:8787/api/health

Как исправить сейчас — до мержа ставим код из ветки PR:

# на машине АГЕНТА, из ветки PR (конфиг не перетрётся):
curl -fsSL https://forgejo.lamanshe.ru/forgejo-admin/watcherenish/raw/branch/feature/11_bind_default_and_uninstall/deploy/install.sh | sudo bash

ALLOWED_ORIGINS у вас закомментирован — ничего в конфиге менять не нужно, после установки кода из ветки PR CORS будет открыт всем (токен останется обязателен). Подключение агента из хаба заработает без правок конфига. После мержа этого PR в main достаточно будет один раз переустановить из main — вернётесь на обычную ветку.

Чтобы такая ситуация больше не путала, добавил в коммите 6d692f1 предупреждение в сводку установки: если код ставится не из main, установщик явно печатает жёлтую плашку «временная установка для проверки PR, после мержа переустановите из main». npm test — 33/33 зелёные.

Если после установки из ветки PR подключение всё равно не пройдёт — пришлите вывод curl-команды выше, посмотрю дальше.

Разобрался — код на машине обновился, но не до той ревизии. **Что произошло.** В сводке видно: `Код: /opt/watcherenish (ветка main)`. Установщик по умолчанию ставит ветку `main`, а правка «CORS открыт по умолчанию» (коммит `0e4f5bb`) есть только в ветке PR `feature/11_bind_default_and_uninstall` — в `main` она попадёт после мержа. Поэтому агент работает ещё на старом CORS-режиме (opt-in), где пустой `ALLOWED_ORIGINS` = заголовки не выдаются, отсюда и 401 без `Access-Control-Allow-Origin`. Кстати, сам факт `401` — это нормально: без Bearer-токена `/api/*` всегда отвечает 401. Для проверки CORS нужен запрос с заголовком Origin **и** токеном — тогда в ответе появится `Access-Control-Allow-Origin`: ```bash curl -s -D - -o /dev/null \ -H "Origin: https://forgejo.lamanshe.ru" \ -H "Authorization: Bearer $(grep '^AUTH_TOKEN=' /etc/default/pi-web-monitor | cut -d= -f2)" \ http://127.0.0.1:8787/api/health ``` **Как исправить сейчас** — до мержа ставим код из ветки PR: ```bash # на машине АГЕНТА, из ветки PR (конфиг не перетрётся): curl -fsSL https://forgejo.lamanshe.ru/forgejo-admin/watcherenish/raw/branch/feature/11_bind_default_and_uninstall/deploy/install.sh | sudo bash ``` `ALLOWED_ORIGINS` у вас закомментирован — ничего в конфиге менять не нужно, после установки кода из ветки PR CORS будет открыт всем (токен останется обязателен). Подключение агента из хаба заработает без правок конфига. После мержа этого PR в main достаточно будет один раз переустановить из main — вернётесь на обычную ветку. **Чтобы такая ситуация больше не путала**, добавил в коммите `6d692f1` предупреждение в сводку установки: если код ставится не из `main`, установщик явно печатает жёлтую плашку «временная установка для проверки PR, после мержа переустановите из main». `npm test` — 33/33 зелёные. Если после установки из ветки PR подключение всё равно не пройдёт — пришлите вывод curl-команды выше, посмотрю дальше.

Не работает, я прям код скопировал из ветки в install.sh файл, чтобы точно взять его с твоей ветки, но все равно. Вот вывод:
root@developer-agent:/tmp# INSTALL_USER=root ./install.sh
[install] 1/7 Проверка окружения
[install] ✓ окружение: Linux + systemd, пользователь root, каталог /opt/watcherenish
[install] 2/7 Проверка Node.js (нужен >= 20)
[install] ✓ Node.js v24.21.0 уже установлен
[install] 3/7 Код: /opt/watcherenish (ветка main)
[install] ✓ код обновлён до origin/main (6b9103b)
[install] 4/7 Тесты (npm test)
✔ GET /api/summary: counters on fixtures dir (58.376211ms)
✔ GET /api/sessions: list sorted by mtime desc, search works (58.426287ms)
✔ GET /api/sessions/🆔 entries with previews (21.841421ms)
✔ GET /api/sessions/:id/messages: transcript for rendering (17.846806ms)
✔ GET /api/logs/gate: graceful when file missing (14.366368ms)
✔ GET /api/logs/gate: returns tail lines (19.504995ms)
✔ AUTH_TOKEN: api requires Bearer, 401 without/with-wrong token (28.10716ms)
✔ AUTH_TOKEN: static UI served without token, so user can enter it (7.013048ms)
✔ GET /api/health: 401 without/wrong token, 200 with correct token (8.343679ms)
✔ GET /api/health: works without AUTH_TOKEN, reports missing sessions dir as degraded (4.622355ms)
✔ CORS: allowed origin gets ACAO on GET, disallowed does not (5.060894ms)
✔ CORS: preflight OPTIONS answered with allow methods/headers for allowed origin (5.950541ms)
✔ CORS: without ALLOWED_ORIGINS no CORS headers even with Origin (same-origin mode) (3.438603ms)
✔ loadConfig: defaults without env (1.886643ms)
✔ loadConfig: reads all env keys (1.496785ms)
✔ loadConfig: BIND 0.0.0.0 without AUTH_TOKEN throws (0.652883ms)
✔ loadConfig: BIND 0.0.0.0 with AUTH_TOKEN is allowed (0.285444ms)
✔ loadConfig: ACTIVE_SESSION_TTL_MIN must be a positive number (0.407179ms)
✔ loadConfig: allowedOrigins defaults to empty list (same-origin mode) (1.829163ms)
✔ loadConfig: ALLOWED_ORIGINS is parsed into trimmed origin list (0.421218ms)
✔ tailFile: returns last N lines of a log (8.575904ms)
✔ tailFile: missing file -> error, no throw (3.480369ms)
✔ tailFile: no trailing newline handled (4.18277ms)
✔ parseSessionFile: normal session — header, entry count, tree links (16.906662ms)
✔ parseSessionFile: broken JSON line is skipped with warning, rest parses (6.465627ms)
✔ aggregateSession: counts messages, tool calls, errors (4.349413ms)
✔ aggregateSession: sums usage across assistant messages (normal) (3.402425ms)
✔ aggregateSession: includes standalone usage and compaction usage (3.005234ms)
✔ aggregateSession: tool duration via toolCallId link (2.137795ms)
✔ aggregateSession: start/end from first/last entry timestamps (3.492102ms)
✔ aggregateSession: models list from model_change entries (4.409686ms)
✔ listSessionFiles: finds .jsonl recursively under sessions dir (1.762114ms)
✔ parseSessionFile: missing file returns null session, warning, no throw (3.047767ms)
ℹ tests 33
ℹ suites 0
ℹ pass 33
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 734.358304
[install] ✓ тесты пройдены
[install] 5/7 Конфигурация: /etc/default/pi-web-monitor
[install] ✓ конфиг уже существует — не перетираю (ручные правки сохранены)
[install] 6/7 systemd-юнит: /etc/systemd/system/pi-web-monitor.service
[install] ✓ юнит установлен, сервис перезапущен
[install] 7/7 Проверка живости (GET /api/health)
[install] ✓ сервис отвечает: http://127.0.0.1:8787/api/health

════════════════════════════════════════════════════════════
УСТАНОВКА ВЫПОЛНЕНА УСПЕШНО
Сервис: pi-web-monitor (systemd, включён автозапуск)
Код: /opt/watcherenish (ветка main)
Адрес: http://10.10.1.21:8787 (из локальной сети)
Локально: http://127.0.0.1:8787
Внимание: BIND=0.0.0.0 — UI доступен по сети, вход защищён AUTH_TOKEN;
пробрасывать порт в интернет не рекомендуется
Конфиг: /etc/default/pi-web-monitor (правки сохраняются при повторных установках)
AUTH_TOKEN: см. /etc/default/pi-web-monitor (не менялся)
Проверка: systemctl status pi-web-monitor
Удаление: curl -fsSL https://forgejo.lamanshe.ru/forgejo-admin/watcherenish/raw/branch/main/deploy/uninstall.sh | sudo bash
════════════════════════════════════════════════════════════
root@developer-agent:/tmp# curl -s -D - -o /dev/null
-H "Origin: https://forgejo.lamanshe.ru"
-H "Authorization: Bearer $(grep '^AUTH_TOKEN=' /etc/default/pi-web-monitor | cut -d= -f2)"
http://127.0.0.1:8787/api/health
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Content-Length: 98
Cache-Control: no-store
Date: Sat, 26 Sep 2026 14:50:14 GMT
Connection: keep-alive
Keep-Alive: timeout=5

root@developer-agent:/tmp#

Не работает, я прям код скопировал из ветки в install.sh файл, чтобы точно взять его с твоей ветки, но все равно. Вот вывод: root@developer-agent:/tmp# INSTALL_USER=root ./install.sh [install] 1/7 Проверка окружения [install] ✓ окружение: Linux + systemd, пользователь root, каталог /opt/watcherenish [install] 2/7 Проверка Node.js (нужен >= 20) [install] ✓ Node.js v24.21.0 уже установлен [install] 3/7 Код: /opt/watcherenish (ветка main) [install] ✓ код обновлён до origin/main (6b9103b) [install] 4/7 Тесты (npm test) ✔ GET /api/summary: counters on fixtures dir (58.376211ms) ✔ GET /api/sessions: list sorted by mtime desc, search works (58.426287ms) ✔ GET /api/sessions/:id: entries with previews (21.841421ms) ✔ GET /api/sessions/:id/messages: transcript for rendering (17.846806ms) ✔ GET /api/logs/gate: graceful when file missing (14.366368ms) ✔ GET /api/logs/gate: returns tail lines (19.504995ms) ✔ AUTH_TOKEN: api requires Bearer, 401 without/with-wrong token (28.10716ms) ✔ AUTH_TOKEN: static UI served without token, so user can enter it (7.013048ms) ✔ GET /api/health: 401 without/wrong token, 200 with correct token (8.343679ms) ✔ GET /api/health: works without AUTH_TOKEN, reports missing sessions dir as degraded (4.622355ms) ✔ CORS: allowed origin gets ACAO on GET, disallowed does not (5.060894ms) ✔ CORS: preflight OPTIONS answered with allow methods/headers for allowed origin (5.950541ms) ✔ CORS: without ALLOWED_ORIGINS no CORS headers even with Origin (same-origin mode) (3.438603ms) ✔ loadConfig: defaults without env (1.886643ms) ✔ loadConfig: reads all env keys (1.496785ms) ✔ loadConfig: BIND 0.0.0.0 without AUTH_TOKEN throws (0.652883ms) ✔ loadConfig: BIND 0.0.0.0 with AUTH_TOKEN is allowed (0.285444ms) ✔ loadConfig: ACTIVE_SESSION_TTL_MIN must be a positive number (0.407179ms) ✔ loadConfig: allowedOrigins defaults to empty list (same-origin mode) (1.829163ms) ✔ loadConfig: ALLOWED_ORIGINS is parsed into trimmed origin list (0.421218ms) ✔ tailFile: returns last N lines of a log (8.575904ms) ✔ tailFile: missing file -> error, no throw (3.480369ms) ✔ tailFile: no trailing newline handled (4.18277ms) ✔ parseSessionFile: normal session — header, entry count, tree links (16.906662ms) ✔ parseSessionFile: broken JSON line is skipped with warning, rest parses (6.465627ms) ✔ aggregateSession: counts messages, tool calls, errors (4.349413ms) ✔ aggregateSession: sums usage across assistant messages (normal) (3.402425ms) ✔ aggregateSession: includes standalone usage and compaction usage (3.005234ms) ✔ aggregateSession: tool duration via toolCallId link (2.137795ms) ✔ aggregateSession: start/end from first/last entry timestamps (3.492102ms) ✔ aggregateSession: models list from model_change entries (4.409686ms) ✔ listSessionFiles: finds .jsonl recursively under sessions dir (1.762114ms) ✔ parseSessionFile: missing file returns null session, warning, no throw (3.047767ms) ℹ tests 33 ℹ suites 0 ℹ pass 33 ℹ fail 0 ℹ cancelled 0 ℹ skipped 0 ℹ todo 0 ℹ duration_ms 734.358304 [install] ✓ тесты пройдены [install] 5/7 Конфигурация: /etc/default/pi-web-monitor [install] ✓ конфиг уже существует — не перетираю (ручные правки сохранены) [install] 6/7 systemd-юнит: /etc/systemd/system/pi-web-monitor.service [install] ✓ юнит установлен, сервис перезапущен [install] 7/7 Проверка живости (GET /api/health) [install] ✓ сервис отвечает: http://127.0.0.1:8787/api/health ════════════════════════════════════════════════════════════ УСТАНОВКА ВЫПОЛНЕНА УСПЕШНО Сервис: pi-web-monitor (systemd, включён автозапуск) Код: /opt/watcherenish (ветка main) Адрес: http://10.10.1.21:8787 (из локальной сети) Локально: http://127.0.0.1:8787 Внимание: BIND=0.0.0.0 — UI доступен по сети, вход защищён AUTH_TOKEN; пробрасывать порт в интернет не рекомендуется Конфиг: /etc/default/pi-web-monitor (правки сохраняются при повторных установках) AUTH_TOKEN: см. /etc/default/pi-web-monitor (не менялся) Проверка: systemctl status pi-web-monitor Удаление: curl -fsSL https://forgejo.lamanshe.ru/forgejo-admin/watcherenish/raw/branch/main/deploy/uninstall.sh | sudo bash ════════════════════════════════════════════════════════════ root@developer-agent:/tmp# curl -s -D - -o /dev/null \ -H "Origin: https://forgejo.lamanshe.ru" \ -H "Authorization: Bearer $(grep '^AUTH_TOKEN=' /etc/default/pi-web-monitor | cut -d= -f2)" \ http://127.0.0.1:8787/api/health HTTP/1.1 200 OK Content-Type: application/json; charset=utf-8 Content-Length: 98 Cache-Control: no-store Date: Sat, 26 Sep 2026 14:50:14 GMT Connection: keep-alive Keep-Alive: timeout=5 root@developer-agent:/tmp#
The installer always checked out main even when the script itself was
fetched from a PR branch, so testing PR code on a real machine required
editing the script by hand (report by forgejo-admin in PR #12).

- Branch can now be passed as the first argument or via BRANCH env;
  without it main is installed and the summary/hint says so explicitly.
- Explicit branch is verified with git ls-remote before any changes.
- README documents installing from a non-main branch.
Author
Collaborator

Разобрался — моя прошлая инструкция была ошибочной, прошу прощения за потерянное время: установщик из ветки PR на самом деле всегда ставит код из main (BRANCH жёстко по умолчанию main). Это видно и в вашем логе: «Код: /opt/watcherenish (ветка main)», «код обновлён до origin/main (6b9103b)». Ручное копирование install.sh не помогало именно поэтому — ветку кода скрипт из своей ветки не наследует. Ваш curl-вывод при этом корректный: 200 OK без заголовка Access-Control-Allow-Origin — ровно то, что отдаёт старый код из main (CORS opt-in). Т.е. проблема не в вашей машине, а в установщике.

Исправил в коммите eeb5e70 (эта же ветка/PR):

  1. Установщику можно явно передать ветку — первым аргументом после bash или через BRANCH=…:
curl -fsSL https://forgejo.lamanshe.ru/forgejo-admin/watcherenish/raw/branch/main/deploy/install.sh | sudo bash -s feature/11_bind_default_and_uninstall
# или: sudo bash install.sh feature/11_bind_default_and_uninstall
# или: sudo BRANCH=feature/11_bind_default_and_uninstall bash install.sh

Теперь не нужно копировать файл вручную: один curl с bash -s <ветка> ставит код ровно из PR-ветки. Явно заданная ветка проверяется через git ls-remote ещё до каких-либо изменений — с опечаткой установка падает сразу с внятной ошибкой.

  1. Запуск без аргументов по-прежнему ставит main, но теперь скрипт об этом явно пишет и печатает подсказку, как поставить другую ветку — больше никакой неявной «магии веток».

Проверено в песочнице (с заглушкой systemd): ветка аргументом ✓, ветка через env ✓, без аргументов — main + подсказка ✓, несуществующая ветка — внятная ошибка ✓. npm test — 33/33 зелёные.

Проверка на вашей машине:

# на машине АГЕНТА — теперь одной командой, без копирования файлов:
curl -fsSL https://forgejo.lamanshe.ru/forgejo-admin/watcherenish/raw/branch/main/deploy/install.sh | sudo bash -s feature/11_bind_default_and_uninstall
# в сводке должно появиться: Код: /opt/watcherenish (ветка feature/11_bind_default_and_uninstall)
# и жёлтая плашка «временная установка для проверки PR»

# затем проверка CORS (должен появиться Access-Control-Allow-Origin):
curl -s -D - -o /dev/null \
  -H "Origin: https://forgejo.lamanshe.ru" \
  -H "Authorization: Bearer $(grep '^AUTH_TOKEN=' /etc/default/pi-web-monitor | cut -d= -f2)" \
  http://127.0.0.1:8787/api/health

После этого подключение агента из хаба должно заработать. Конфиг (/etc/default/pi-web-monitor) перетирать не нужно — ALLOWED_ORIGINS у вас закомментирован, открытый CORS включится сам. После мержа PR достаточно один раз переустановить из main без аргументов.

Разобрался — моя прошлая инструкция была ошибочной, прошу прощения за потерянное время: установщик из ветки PR на самом деле **всегда ставит код из `main`** (`BRANCH` жёстко по умолчанию `main`). Это видно и в вашем логе: «Код: /opt/watcherenish (ветка main)», «код обновлён до origin/main (6b9103b)». Ручное копирование `install.sh` не помогало именно поэтому — ветку кода скрипт из своей ветки не наследует. Ваш curl-вывод при этом корректный: `200 OK` без заголовка `Access-Control-Allow-Origin` — ровно то, что отдаёт старый код из `main` (CORS opt-in). Т.е. проблема не в вашей машине, а в установщике. **Исправил в коммите `eeb5e70` (эта же ветка/PR):** 1. Установщику можно явно передать ветку — первым аргументом после `bash` или через `BRANCH=…`: ```bash curl -fsSL https://forgejo.lamanshe.ru/forgejo-admin/watcherenish/raw/branch/main/deploy/install.sh | sudo bash -s feature/11_bind_default_and_uninstall # или: sudo bash install.sh feature/11_bind_default_and_uninstall # или: sudo BRANCH=feature/11_bind_default_and_uninstall bash install.sh ``` Теперь не нужно копировать файл вручную: один curl с `bash -s <ветка>` ставит код ровно из PR-ветки. Явно заданная ветка проверяется через `git ls-remote` ещё до каких-либо изменений — с опечаткой установка падает сразу с внятной ошибкой. 2. Запуск без аргументов по-прежнему ставит `main`, но теперь скрипт об этом явно пишет и печатает подсказку, как поставить другую ветку — больше никакой неявной «магии веток». Проверено в песочнице (с заглушкой systemd): ветка аргументом ✓, ветка через env ✓, без аргументов — main + подсказка ✓, несуществующая ветка — внятная ошибка ✓. `npm test` — 33/33 зелёные. **Проверка на вашей машине:** ```bash # на машине АГЕНТА — теперь одной командой, без копирования файлов: curl -fsSL https://forgejo.lamanshe.ru/forgejo-admin/watcherenish/raw/branch/main/deploy/install.sh | sudo bash -s feature/11_bind_default_and_uninstall # в сводке должно появиться: Код: /opt/watcherenish (ветка feature/11_bind_default_and_uninstall) # и жёлтая плашка «временная установка для проверки PR» # затем проверка CORS (должен появиться Access-Control-Allow-Origin): curl -s -D - -o /dev/null \ -H "Origin: https://forgejo.lamanshe.ru" \ -H "Authorization: Bearer $(grep '^AUTH_TOKEN=' /etc/default/pi-web-monitor | cut -d= -f2)" \ http://127.0.0.1:8787/api/health ``` После этого подключение агента из хаба должно заработать. Конфиг (`/etc/default/pi-web-monitor`) перетирать не нужно — `ALLOWED_ORIGINS` у вас закомментирован, открытый CORS включится сам. После мержа PR достаточно один раз переустановить из `main` без аргументов.
Sign in to join this conversation.
No reviewers
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!12
No description provided.