Table of Contents

Развёртывание под базовым путём (PathBase)

Продукты: МоиОтчеты Корпоративный Сервер, МоиОтчеты Публикатор

По умолчанию МоиОтчеты Корпоративный Сервер или Публикатор занимает корневую часть домена (https://company.com/...). Если на домене уже работают другие сервисы (или требуется сохранить единую cookie-сессию с ними), продукт можно развернуть под произвольным префиксом URL.

Пример: при указании префикса /reports весь продукт становится доступен по адресам вида https://company.com/reports/api/..., https://company.com/reports/app/, https://company.com/reports/designer/... и т.д.

1. Что это даёт

  • Весь продукт обслуживается под префиксом — веб-приложение, публичный API, Online Designer и статические/WASM-превью.
  • Единый вход работает для всех частей: auth-cookie действует на весь домен, поэтому вы остаётесь залогиненым при переходах между /reports/app/, /reports/designer/, /reports/api/... и т.п.
  • API-документация Backend'а (Swagger / OpenAPI) показывает пути с префиксом.

2. Конфигурация

2.1. appsettings.json

Задайте MainConfig.Server.PublicPathBase нужным префиксом. По умолчанию пусто (root-хостинг).

{
  "MainConfig": {
    "Server": {
      "PublicPathBase": "/reports"
    }
  }
}

При установке через мастер установки значение запрашивается на экране параметров («Публичный базовый путь») и записывается в генерируемый appsettings.Production.json, который монтируется во все контейнеры сервисов.

2.2. Переменные среды

Стандартный механизм переопределения ASP.NET Core (двойное подчёркивание __ для вложенных ключей):

MainConfig__Server__PublicPathBase=/reports

Переменная должна попасть в окружение каждого контейнера сервисов — значение, экспортированное в shell хоста, не достигает ни Docker-контейнеров, ни Kubernetes-подов. В Docker Compose добавьте запись environment: каждому сервису; в Kubernetes — env: каждому контейнеру. В штатных инсталляциях это не нужно: общий appsettings.Production.json (раздел 2.1) уже смонтирован во все контейнеры.

Публичный префикс остаётся в пути запроса на всём маршруте: прокси передаёт /reports/... без изменений, а каждый сервис (включая Gateway) сам переносит префикс на Request.PathBase через UsePathBase — поэтому сгенерированные фреймворком URL (редиректы, Location, Swagger) автоматически несут префикс. Никакой покомпонентной настройки не требуется.

3. Пример развёртывания с nginx

server {
    listen 443 ssl;
    server_name company.com;

    ssl_certificate     /etc/ssl/certs/company.com.crt;
    ssl_certificate_key /etc/ssl/private/company.com.key;

    # Передаём запросы /reports/ на Gateway, сохраняя полный URI без изменений.
    # НЕ добавляйте слэш в конец proxy_pass — `http://gateway/` срезал бы префикс
    # /reports, и сервисы его не увидели бы: префикс должен остаться в пути запроса,
    # его срезает каждый сервис сам через UsePathBase.
    location /reports/ {
        proxy_pass http://gateway;
        proxy_set_header Host              $host;
        proxy_set_header X-Real-IP         $remote_addr;
        proxy_set_header X-Forwarded-For   $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Forwarded-Host  $host;
        proxy_http_version 1.1;
        proxy_set_header Connection        "";
        proxy_buffering off;
    }
}

4. Пример развёртывания в Kubernetes (Ingress)

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: gateway
spec:
  tls:
    - hosts: [company.com]
      secretName: company-com-tls
  rules:
    - host: company.com
      http:
        paths:
          - path: /reports(/|$)(.*)
            pathType: ImplementationSpecific
            backend:
              service:
                name: fr-gateway
                port:
                  number: 80
  • Auth-cookie устанавливается с Path=/ на весь домен, поэтому отправляется для /reports/app/, /reports/designer/, /reports/api/... и остальных маршрутов без повторной авторизации.
  • OIDC callback — внешний IdP (например, https://id.быстрыеотчеты.рф) получит redirect_uri вида https://company.com/reports/account/oidc/signin-*. Зарегистрируйте этот URL в настройках клиента IdP с префиксом.

6. Известные ограничения

  • LogoLink/FaviconLink/HomePageLink/AboutLink/SlaLink/FirstStepsVideoLink в MainConfig.Server должны включать префикс при использовании относительных путей (например, /assets/logo.svg → /reports/assets/logo.svg). Для абсолютных URL добавьте префикс в хост.
  • Не используйте префикс, содержащий имя сервисного сегмента — app, admin, designer, wasmpreview или staticpreview (например, /app/reports или /reports/admin/...). Такой префикс не поддерживается, и приложение не будет корректно резолвиться под ним.

7. Минимальный рабочий пример

Вся необходимая конфигурация — единственный ключ в общем MainConfig (appsettings.json):

{
  "MainConfig": {
    "Server": {
      "PublicPathBase": "/reports"
    }
  }
}

Поставьте сервисы за обратным прокси, который форвардит /reports/ на Gateway (см. раздел 3 для nginx, раздел 4 для Kubernetes Ingress). Каждый сервис срезает префикс сам, как только значение попадает в его конфигурацию — в штатных инсталляциях общий appsettings.Production.json смонтирован во все контейнеры, поэтому этого одного значения достаточно — приложение загрузится под префиксом /reports (например https://company.com/reports/app/).

8. Использование SDK с развёртыванием под базовым путём

Сторонний клиент, обращающийся к публичному API через SDK, должен попадать под публичный префикс каждым запросом. Механизм различается для C# и JavaScript SDK, причём в случае с C# есть один подводный камень.

C# SDK (FastReport.Cloud.SDK / FastReport.Cloud.SDK.Web)

Опции PathBase/basePath нет — префикс должен быть частью базового URL, и этот базовый URL обязательно заканчивается слэшем. .NET разрешает относительные URI запросов SDK (api/manage/v1/...) относительно базового URL по RFC 3986, замещая его последний path-сегмент, поэтому без завершающего слэша сегмент-префикс молча отбрасывается.

// ПРАВИЛЬНО — запросы уходят на https://company.com/reports/api/manage/v1/...
services.AddFastReportCloud(options =>
{
    options.Host = "https://company.com/reports/"; // префикс + завершающий слэш
    options.ApiKey = "...";
});

// или, если вы создаёте HttpClient сами:
httpClient.BaseAddress = new Uri("https://company.com/reports/");
// НЕПРАВИЛЬНО — .NET разрешает "api/manage/v1/ApiKeys" относительно "https://company.com/reports"
// и ОТБРАСЫВАЕТ "/reports": запросы молча попадают в корень домена (404 / не тот тенант).
options.Host = "https://company.com/reports"; // без завершающего слэша

JavaScript SDK (fastreport-cloud-sdk)

JS SDK предоставляет настраиваемый basePath и строит URL конкатенацией строк, а не по правилам RFC 3986, поэтому завершающий слэш не нужен — конструктор сам его отсекает:

const apiClient = new ApiClient();
apiClient.basePath = "https://company.com/reports"; // завершающий слэш необязателен