Nginx-роутинг

MultiAgent никогда не распределяет запросы сам: на каждом сервере работает свой Nginx-контейнер — {слаг}-nginx, по умолчанию agents-nginx, — который MultiAgent разворачивает, настраивает и обновляет. Все приложения сервера — агенты, продукты, инструменты с веб-интерфейсом и произвольные сервисы — раздаются по подпапкам одного адреса: {база}/{слаг}/. Никаких отдельных доменов, поддоменов и ручных конфигов под каждое приложение: у сервера один адрес, и каждое приложение живёт в своей подпапке.

Как это работает

На каждом управляемом сервере MultiAgent поднимает один контейнер {слаг}-nginx (по умолчанию agents-nginx; сервис nginx) — это Debian-сборка nginx (nginx:1.31), а не Alpine: она запускается и на старых ядрах, на которых Alpine-сборка падает на старте. Контейнер ставится из вкладки Nginx страницы сервера: MultiAgent создаёт файлы конфигурации на сервере (загружаются по защищённому каналу), присоединяет контейнер к общей docker-сети и запускает его.

Перед установкой MultiAgent проверяет, свободен ли порт, на котором должен работать nginx. Если его уже занял кто-то другой — например, на машине давно работает свой веб-сервер на порту 80, — nginx переезжает на следующий свободный порт, а об этом сообщается в ленте прогресса; адрес панели и все ссылки на приложения считаются уже по новому порту, и поле порта во вкладке обновляется само. Уже работающий nginx при повторных применениях сохраняет свой порт — вверх он не уползает. Без этой проверки установка просто падала бы на занятом порту, оставляя остановленный контейнер и закрытую дверь к приложениям.

Конфигурация маршрутов собирается из базы MultiAgent автоматически: при каждом изменении (создали, изменили или удалили запись агента, продукта или инструмента, добавили или отредактировали ссылку или пользовательский маршрут, установили или удалили центральный вход, изменили порты) конфиг пересобирается и применяется сам. Применение не обрывает соединения: конфигурация проверяется и перезагружается внутри уже работающего веб-сервера, поэтому открытые страницы и живые чаты не рвутся (контейнер пересоздаётся только когда меняется его собственный файл настройки). Изменение адреса сервера (хост, публичный адрес или шаблон URL) тоже пересобирает маршруты и дополнительно синхронизирует настройки центрального входа. Установки показывают свои шаги в ленте прогресса, изменения записей применяются в фоне. Кнопка «Применить конфигурацию» во вкладке прогоняет то же обновление вручную — удобно, когда правку сделали прямо на сервере.


Источники маршрутов

Общая таблица маршрутов собирается автоматически из пяти источников:

  • Агенты и продукты — каждая развёрнутая запись агента (включая продукты из каталога) автоматически даёт маршрут: появляется вместе с записью и исчезает с её удалением;
  • Дополнительные ссылки агентов и продуктов — ссылка со вкладки «Ссылки» с указанным маршрутом получает свою подпапку, которая ведёт на выбранный порт сервера: появляется вместе со ссылкой и исчезает вместе с ней;
  • Инструменты с веб-интерфейсом — инструмент, у шаблона которого объявлен веб-порт, получает маршрут автоматически (порт берётся из шаблона и обновляется при каждом развёртывании); без веб-порта инструмент остаётся на прямом адресе http://{хост}:{порт};
  • Центральный вход — производный маршрут с фиксированным слагом auth (адрес {база}/auth/ — страница входа): появляется вместе с установкой центрального входа на вкладке «Авторизация» и исчезает после его удаления; read-only, никогда не закрывается защитой и не имеет собственного переключателя;
  • Кастомные маршруты — единственный вид с ручным управлением: произвольный http(s)-адрес (не обязательно управляемый MultiAgent — служба на своём порту, локальный сервис, внешняя система), с редактированием, отключением и удалением.

Вкладка показывает все маршруты, отсортированные по слагу, с публичным адресом и целью для каждого; автоматические виды помечены «Managed by MultiAgent» и кликом ведут к исходной записи (клик по строке центрального входа открывает вкладку «Авторизация» страницы сервера).


Схема трафика

Трафик идёт так: http(s)://{хост сервера}/{слаг}/ → Nginx сервера → контейнер приложения во внутренней docker-сети ({имя контейнера}:{порт}). Приложения адресуются по именам контейнеров, поэтому публиковать порты наружу не нужно.

  • Резолвинг на лету — конфиг использует внутренний резолвер и переменные адресов: Nginx стартует и работает независимо от того, какие приложения существуют. Неработающее, остановленное или ещё не развёрнутое приложение даёт ошибку только на своей подпапке, остальные маршруты продолжают работать;
  • WebSocket и большие ответы — поддерживаются постоянные соединения (живые чаты агентов), длинные таймауты и безлимитный размер передаваемых данных;
  • Заголовки — приложению передаются служебные данные о префиксе, хосте и схеме, поэтому чувствительные к префиксу приложения строят правильные абсолютные адреса; за внешним прокси приложения получают https-схему и исходный хост;
  • Корень / — отдаётся домашней страницей сервера, когда она установлена (см. ниже); без неё корень ведёт себя как обычная резервная страница.

Порты приложений по умолчанию частные: они опубликованы только на 127.0.0.1 сервера, то есть доступны лишь самому серверу и контейнерам его общей docker-сети — ровно тот путь, по которому ходит nginx. Так на одной машине соседние развёртывания не видят портов друг друга. Наружу порт открывается переключателем «Публичный порт» (вкладка «Порты» у агента и приложения, строка порта у инструмента). Публичными всегда остаются только слушатели HTTP/HTTPS самого nginx и порт службы резервного копирования, а общий Postgres всегда закрыт. Поэтому ссылки на приложение с частным портом ведут на его адрес через nginx — {база}/{слаг}/, — а не на недоступный прямой http://{хост}:{порт}. Управление такими приложениями MultiAgent ведёт сам, по закрытому каналу к серверу.


Защита приложений (центральный вход)

Если на сервере установлен центральный вход (вкладка «Авторизация» страницы сервера, подробнее — на странице Серверы), защищённые маршруты пропускаются через него: посетитель один раз входит на странице входа {база}/auth/ и дальше открывает любое защищённое приложение сервера без повторного логина.

  • Агенты и продукты закрыты «за центральным входом» по умолчанию — переключатель в карточке приложения позволяет открыть их снова. Инструменты с веб-интерфейсом и пользовательские маршруты защищаются по вашему выбору: переключатель «За центральным входом» на строке. Сам маршрут входа (auth) никогда не закрывается;
  • Для защиты нужен HTTPS: она включается, только когда фронт работает по HTTPS — локальный сертификат и порт HTTPS из вкладки Nginx либо публичный адрес сервера (или шаблон адреса вида https://{база}/{слаг}), когда TLS снимает верхний обратный прокси. Иначе установленный центральный вход остаётся неактивным;
  • Машинные пути не закрываются: /{слаг}/api/… и /{слаг}/svelteChatHub работают без входа (у приложений там своя авторизация — JWT или API-ключ), и файл манифеста (manifest.json) тоже отдаётся без входа — браузер запрашивает его отдельно от страницы, без общих данных браузера, и без этого защищённая вкладка показывала бы ошибку. А прямой доступ по адресу host:port в обход nginx сохраняет собственный вход приложения. Остановленный центральный вход закрывает только свои защищённые маршруты — остальные подпапки продолжают работать;
  • Личность и секрет: защищённое приложение получает заголовки личности посетителя (имя, группы, email), а агенты и продукты дополнительно — секрет X-SSO-Token, по которому убеждаются, что запрос пришёл через nginx (сверка с SSO_PROXY_TOKEN в переменных окружения агента); инструментам и пользовательским маршрутам секрет не передаётся.

Кнопка «Применить конфигурацию» на вкладке «Авторизация» не только применяет настройки, но и завершает все открытые сессии: каждому браузеру придётся войти заново с текущим паролем. Так изменение доступа действительно становится заметным сразу. Файл манифеста защищённых приложений (см. выше) при этом продолжает отдаваться — приложение устанавливается и открывается по-прежнему.

Forgejo подключается к центральному входу сам — без переключателя: как только вход установлен, защита работает и Forgejo запущен, на его странице входа появляется кнопка входа через центральный вход, а первый вход заводит аккаунт из личности входа. Логин и пароль администратора Forgejo следуют за центральным входом; на вкладке Forgejo для этого есть кнопка «Синхронизировать авторизацию». Если условия пропадают, кнопка входа исчезает сама, а собственные аккаунты Forgejo и его собственная форма входа продолжают работать как раньше.


Пространство имён и зарезервированные префиксы

Слаг первого уровня — единое пространство имён на каждый сервер, общее для агентов, продуктов, инструментов и пользовательских маршрутов: один и тот же слаг может существовать на разных серверах, но на одном сервере его можно занять только один раз. Слаги — только строчные буквы, цифры и дефисы ([a-z0-9-]+).

Служебные пути MultiAgent зарезервированы и не могут стать слагами: api, v1, swagger, servers, agents, tools, workspaces, analytics, accounts, data, а также слаг auth — он зарезервирован на каждом сервере независимо от того, установлен ли центральный вход, и принадлежит его маршруту. Агента с именем api, servers или auth создать нельзя — форма подсветит это сразу, а сервер отклонит запись.


Кастомные маршруты

Кастомный маршрут направляет подпапку на любой абсолютный http(s)-адрес, доступный с сервера: служба на своём порту, локальное приложение, внешняя система. Для создания нужны имя, слаг по правилам пространства имён и цель — абсолютный адрес вида http(s)://… (значение без схемы отклоняется).

  • Каждое изменение (создание, редактирование, включение, отключение, удаление) сразу пересобирает и применяет конфиг;
  • Отключённый маршрут убирает свою подпапку — она начинает отвечать ошибкой 404, запись остаётся в таблице;
  • Удаление освобождает слаг для любого вида — другой агент, инструмент или маршрут сможет его занять;
  • Если у цели есть собственный базовый путь (например, http://host/wiki), он подставляется вместо слага: /{слаг}/docs/page достигает /wiki/docs/page.

Сертификаты

Сертификаты управляются из того же вкладки Nginx — три вида:

  • Самоподписанный — генерируется MultiAgent и служит резервным сертификатом; его можно скачать как файл .crt и импортировать в доверенные сертификаты системы;
  • Собственная пара PEM — вставляется или загружается; цепочка и ключ проверяются до записи (ключ должен совпадать с сертификатом, просроченный отклоняется с предупреждением);
  • Let’s Encrypt — бесплатные сертификаты через сам Nginx (проверка владения доменом по протоколу ACME): тестовая (staging) и рабочая площадка, один запрос за раз, домен должен указывать на сервер.

Ключевые материалы хранятся только на сервере (папка ssl/{домен}/: полная цепочка + приватный ключ) и монтируются в контейнер только для чтения — в базе MultiAgent лишь метаданные. Каждое обновление конфигурации продлевает сертификаты, истекающие в течение 30 дней (самоподписанные перегенерируются, Let’s Encrypt запрашивается заново), плюс есть ручное продление по строке. HTTPS-порт опционален: пока он пуст, публикуется только HTTP, и сертификаты хранятся, но не раздаются. Успешный запрос Let’s Encrypt при пустом порте сам включает его (443) — сертификат сразу обслуживается, а выбранный вами порт или явно выключенный HTTPS не переопределяются. В локальном режиме (свой сертификат и порт HTTPS) весь HTTP, включая подпапки маршрутов, перенаправляется на HTTPS — исключение только /.well-known/acme-challenge/, по которому продолжает отвечать сам Nginx. Когда TLS снимает верхний обратный прокси (шаблон адреса https://{база}/{слаг}), HTTP-слушатель продолжает раздавать маршруты — браузер уже работает по HTTPS у прокси.


Сам MultiAgent в подпапке

MultiAgent — и сам такое приложение: его можно разместить не только в корне домена, но и в любой подпапке (ваш-домен/multiagent), причём тем же самым образом и без пересборки. Никаких настроек внутри программы для этого не нужно — MultiAgent понимает, где он находится, по адресу запроса. Есть два способа сказать ему об этом.

Через переменную окружения — когда верхний прокси передаёт путь как есть, без изменений. Достаточно добавить при запуске:

- MULTIAGENT_BASE_PATH=/multiagent

MultiAgent сам отрежет префикс и один раз перенаправит запросы, набранные без него, в адрес с подпапкой. Путь проверки сертификата (/.well-known/) остаётся в корне — так его выпуск продолжает работать. Пустое значение означает работу в корне домена.

Через заголовок прокси — когда подпапкой управляет сам прокси: в его настройках к обычному проксированию добавляется одна строка — proxy_set_header X-Forwarded-Prefix /multiagent;. Тогда MultiAgent читает подпапку из заголовка и ничего не перенаправляет — маршрутизацией полностью владеет прокси.

При развёртывании на управляемом сервере ничего из этого не требуется: конфигурация, которую MultiAgent сам для него собирает, уже передаёт подпапку и нужный заголовок. В одном домене можно держать несколько экземпляров в разных подпапках: у каждого своя база и свои ключи, поэтому вход в одном никогда не действует в другом, а в браузере у каждой подпапки своё отдельное состояние.


Домашняя страница сервера

Корень / Nginx отдаёт домашнюю страницу сервера, когда она установлена (вкладка «Домашняя страница» страницы сервера; требуется установленный Nginx). Это статичная панель карточек, которую MultiAgent сам собирает из своей базы и загружает на сервер: по карточке на каждого агента, продукт и инструмент с адресом — с реальными логотипами проектов. Общие действия — не карточки, а строка кнопок-значков в правом верхнем углу: «Git» (пока запущен Forgejo), «Вход по QR-коду» (когда включён центральный вход) и всегда крайняя справа «Выйти». Отдельного входа у страницы нет: при включённом центральном входе она закрыта вместе с остальными приложениями. Подробнее — на странице Домашняя страница сервера.

Подпапки приложений всегда имеют приоритет над путями страницы: агент со слагом settings будет отдан по /settings/, а сама домашняя страница продолжит работать в корне. Если Nginx остановлен, страдает только корень — подпапки приложений продолжают работать.


Публичный адрес

Канонический публичный адрес каждого приложения — {база}/{слаг}/. База выводится в одном месте и по порядку: сначала — публичный адрес сервера (поле на вкладке «Общее»); если оно пусто — база шаблона адреса агентов вида {база}/{slug} (так за проксированным сервером получаются https-ссылки без собственного сертификата); иначе — http(s)://{хост сервера}[:{порт nginx}]. Публичный адрес и шаблон разделены намеренно: шаблон в первую очередь задаёт, как MultiAgent сам обращается к API агентов, а публичный адрес — только то, куда ведут ссылки для людей. Схема следует одному правилу: любой сертификат + включённый HTTPS-порт → https, иначе http. Прямой доступ http://{хост}:{порт} остаётся запасным путём и помечен «direct access» в интерфейсе; для приложений с частным портом он не работает, и ссылка ведёт на адрес через nginx.

← Оглавление документации