---
title: "Nginx-роутинг"
id: "1536"
type: "page"
slug: "routes"
published_at: "2026-08-28T05:15:08+00:00"
modified_at: "2026-10-04T03:29:35+00:00"
url: "https://pastukhov.com/agents/multiagent/docs/routes"
markdown_url: "https://pastukhov.com/agents/multiagent/docs/routes.md"
excerpt: "MultiAgent никогда не распределяет запросы сам: на каждом сервере работает свой Nginx-контейнер — {слаг}-nginx, по…"
---

# Nginx-роутинг

[https://pastukhov.com/agents/multiagent/docs/routes.md](https://pastukhov.com/agents/multiagent/docs/routes.md)

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 ведёт сам, по закрытому каналу к серверу.

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

Если на сервере установлен **центральный вход** (вкладка «Авторизация» страницы сервера, подробнее — на странице [Серверы](/agents/multiagent/docs/servers)
), защищённые маршруты пропускаются через него: посетитель один раз входит на странице входа `{база}/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-коду» (когда включён центральный вход) и всегда крайняя справа «Выйти». Отдельного входа у страницы нет: при включённом центральном входе она закрыта вместе с остальными приложениями. Подробнее — на странице [Домашняя страница сервера](/agents/multiagent/docs/heimdall)
.

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

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

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

[← Оглавление документации](/agents/multiagent/docs)
