Table of Contents

Installation

The FrontEnd Server runs as an ASP.NET Core 8 application, deployed as a Docker container built on top of a customer base image plus an overlay of customisation DLLs. A separate React shell container serves the SPA; both halves are wired together through the shell's runtime config which points at the BFF's HTTP root.

This document is the reference install guide for the FrontEnd Server. For an end-to-end "Hello World" walkthrough (database + auth server + Data API + FrontEnd Server + React shell), see Get Started with Mib v5.0 (Docker) or Get Started with Mib v5.0 (Podman).

For maintaining an existing IIS / .NET Framework install, see Legacy MVC — IIS Installation. New deployments must not start there.

Related docs.
System Overview — backend overlay system explains the 4-layer image stack (base image → NuGet deps → MibServer3 own DLLs → customer customisations) that backs every production deploy.
Local Development covers running the FrontEnd Server locally for component development.

What the FrontEnd Server is

A .NET 8 ASP.NET Core application that:

  • Aggregates pages from the Data API and microservices (Permission, EditHistory, Concurrency, FileManagement) and emits a single {schema, data} response per page render (GET /api/v2/display/<pageKey>/<id>).
  • Hosts every C# customisation as compiled DLLs overlaid into /app/. See Backend overlay system.
  • Exposes the OAuth callback (/oauth/callback) and writes the encrypted .AspNetCore.Cookies session cookie used by the React shell.
  • Hosts the legacy MVC /Display/<pageKey> route for backwards compatibility with server-rendered components — new deployments rarely touch this.

It does not serve the React shell. The shell is a separate Docker container (built from MibFrontEnd/apps/cms) that serves static assets via nginx and points at the FrontEnd Server's HTTP root.

Prerequisites

A working FrontEnd Server depends on several other services being reachable:

Service Why the FrontEnd Server needs it
Database (SQL Server / Azure SQL) FrontEnd DB — page templates, menu, user preferences. Tables prefixed MIB3UX_*, PAGE_*, MENU_*.
MibAuthorizationServer OAuth issuer. Validates session cookies and refreshes tokens.
MibServerApi (Data API) Source of mediatype metadata + item data.
Permission Microservice Per-user/group permission lookup. Required at startup; the FrontEnd Server's readiness probe fails until the first permission-metadata fetch succeeds.
EditHistory Microservice (optional) Required only if UseEditHistoryMicroService=true. Provides the audit panel data.
Concurrency Microservice (optional) Required only if UserConcurrencyServiceUrl is set. Drives the "who else is editing this" UI.
FileManagement Microservice (optional) Required for TSV export and any media-file integration.
React shell container Serves the SPA the operators use. Without it, the FrontEnd Server still works as an API, but no UI is reachable.

For a graphical view of how these fit together, see System Overview — what the CMS actually is.

Deployment models

Two supported deployment models. The first is the modern path; the second exists for legacy customers still running on Windows IIS.

1. Docker (modern)

The FrontEnd Server ships as an OCI image built on the mcr.microsoft.com/dotnet/aspnet:8.0 base. Customers typically take that image, layer their customisation DLLs on top, and publish the result as a "customer base image":

# Customer base image — built once per release
FROM <agile-registry>/mib/frontend:<version>
COPY my-customisation/bin/Release/net8.0/*.dll /app/
COPY my-customisation/config/                  /app/config/

Engineering deploys then add a thin overlay on top of the customer base image with only the DLLs that changed since the last release. See Backend overlay system for the full layering model.

Minimal docker-compose.yml

version: '3.8'

services:
  mib-frontend:
    image: <agile-registry>/mib/frontend:<version>
    restart: unless-stopped
    ports:
      - "8080:8080"
    environment:
      # Where the FrontEnd Server itself lives (used for OAuth callbacks etc.)
      MIBCMSFRONTENDSERVERBASECONFIG_DEFAULT_ROOTURL: "https://cms.example.com/"
      MIBCMSFRONTENDSERVERBASECONFIG_DEFAULT_FRONTENDAPPPATH: "/app"

      # OAuth client (matches the API_CLIENTS row in MibAuthorization)
      MIBAUTHORIZATIONCLIENTCONFIG_DEFAULT_SERVERURL:    "https://auth.example.com/"
      MIBAUTHORIZATIONCLIENTCONFIG_DEFAULT_CLIENTID:     "mibFrontEndClient"
      MIBAUTHORIZATIONCLIENTCONFIG_DEFAULT_CLIENTSECRET: "${MIB_FRONTEND_CLIENT_SECRET}"

      # Data API
      MIBAPICLIENTCONFIG_DEFAULT_URL: "https://api.example.com/"

      # Permission Microservice (required)
      MIBPERMISSIONMICROSERVICECLIENTCONFIG_DEFAULT_SERVERURL: "http://permission-ms"

      # Optional microservices
      MIBCMSFRONTENDSERVERBASECONFIG_DEFAULT_USEEDITHISTORYMICROSERVICE: "true"
      MIBEDITHISTORYMICROSERVICECLIENTCONFIG_DEFAULT_APIURL:             "http://edithistory-ms"
      MIBCMSFRONTENDSERVERBASECONFIG_DEFAULT_USERCONCURRENCYSERVICEURL:  "http://concurrency-ms"
      MIBFILEMANAGEMENTMICROSERVICECLIENTCONFIG_DEFAULT_URLMICROSERVICE: "http://filemanagement-ms"

      # FrontEnd DB
      # NOTE: `sql2005` is the framework's identifier for the SQL Server
      # driver family — it's the correct, modern value for any SQL Server
      # version (2008, 2012, 2016, 2019, 2022, Azure SQL). The label is
      # historical; don't change it based on your actual server version.
      MIBDATABASECONFIG_DEFAULT_TYPE:     "sql2005"
      MIBDATABASECONFIG_DEFAULT_SERVER:   "db.example.com"
      MIBDATABASECONFIG_DEFAULT_DATABASE: "mibfrontend"
      MIBDATABASECONFIG_DEFAULT_USERNAME: "mibfrontend_user"
      MIBDATABASECONFIG_DEFAULT_PASSWORD: "${DB_PASSWORD}"

      # Cache (Couchbase / Memcached / app-memory)
      MIBCACHECONFIG_DEFAULT_APP: "true"

  mib-shell:
    image: ghcr.io/agilecontent/mib-frontend:<version>
    restart: unless-stopped
    ports:
      - "4000:4000"
    environment:
      # The shell's runtime config: where the BFF lives, what federated remotes to load
      VITE_API_URL:                  "https://cms.example.com/"
      VITE_CUSTOM_COMPONENTS_URL:    "https://customer-remote.example.com/assets/remoteEntry.js"
      VITE_CUSTOM_COMPONENTS_2_URL:  ""
      VITE_CUSTOM_COMPONENTS_3_URL:  ""

The React shell at mib-shell is mandatory for an end-user-facing deployment. It can be hosted on the same domain as the BFF behind a reverse proxy (recommended — avoids CORS) or on a separate domain (requires CORS configuration; see CorsOrigins below).

Database migrations

Same as the legacy install — see Database migrations below. The same mibmigrator CLI runs against the same migration assemblies; only the place where you run it differs (typically a one-off Kubernetes Job or a CI step rather than a Windows CLI).

2. IIS on Windows (legacy)

Older customers still run the FrontEnd Server inside IIS on Windows Server. The deploy uses the same DLLs, the same mibconfig files, and the same OAuth client setup — only the host changes.

See Legacy IIS installation at the bottom of this page.

Database migrations

The FrontEnd DB is bootstrapped with mibmigrator. See Framework — MibMigrator tool for the CLI details.

Two migration assemblies, run in order against the FrontEnd DB section:

mibmigrator \
  -assembly=MediaiBox.Core.Database.Migrations.dll \
  -configPath=./config -section=front

mibmigrator \
  -assembly=MediaiBox.Cms.FrontEnd.Database.Migrations.dll \
  -configPath=./config -section=front

In containerised deploys the migrations typically run as a one-off init container or a CI step before the FrontEnd Server pod starts.

OAuth client registration

Each FrontEnd Server instance is an OAuth client of the MibAuthorization Server. Register it by inserting a row into API_CLIENTS in the Auth DB:

INSERT INTO API_CLIENTS
    (NAME, OWNER, ACTIVE, ALLOWS_REFRESH_TOKEN, ALLOWED_ORIGINS,
     OAUTH_CLIENT_ID, OAUTH_CLIENT_SECRET, OAUTH_CLIENT_TYPE,
     REDIRECT_URI, CONFIGURABLE_PERMISSIONS_URL)
VALUES
    ('My CMS', 1, 1, 1, 1,
     'mibFrontEndClient', 'mY53Cr37aCc3s5K3y', 1,
     'https://cms.example.com/oauth/callback',
     'https://cms.example.com/configurablepermissions');

Key columns:

  • OAUTH_CLIENT_TYPE = 1 — Authorization Code grant (the only grant supported by the FrontEnd Server).
  • REDIRECT_URI — must exactly match the FrontEnd Server's /oauth/callback URL.
  • CONFIGURABLE_PERMISSIONS_URL — the FrontEnd Server's /configurablepermissions endpoint. Used by the Authorization Server admin UI to know what permissions this client exposes for configuration. See Permissions Controller.

For details on OAuth client registration, see Authorization Server Configuration.

Configuration

The FrontEnd Server uses the MIB framework's MibConfig system. Every config can be supplied as an XML .mibconfig file in /app/config/ or as an environment variable matching the pattern MIB<CONFIGNAME>_<SECTION>_<KEY>. In container deployments env vars are the norm.

A full reference is in the per-config docs under CMS · MibConfig. Here's the minimal set for a working FrontEnd Server:

Config Purpose Reference
MibCmsFrontEndServerBaseConfig Self-URL, default language, feature toggles MibCmsFrontEndServerBaseConfig
MibAuthorizationClientConfig OAuth client identity + Auth Server URL MibAuthorizationServerConfig
MibApiClientConfig Data API base URL
MibPermissionMicroServiceClientConfig Permission MS URL Microservices — Permissions
MibDatabaseConfig FrontEnd DB connection MibDatabaseConfig
MibCacheConfig Cache backend (in-memory / Memcached / Couchbase) MibCache (framework)
MibObjectCacheConfig Per-table TTLs
MibTranslationConfig Dictionaries for {DICT:Section/Key} Localization
MibLogConfig Log targets (file / DB / EventViewer / stdout) MibLog (framework)

Optional configs:

Config When needed
MibEditHistoryMicroServiceClientConfig When UseEditHistoryMicroService=true
MibFileManagementMicroServiceClientConfig When using TSV exports or file uploads

Env-var shape

MibConfig flattens the XML structure into env vars by uppercasing the path and joining with _:

<MibAuthorizationClientConfig>
  <default>
    <serverUrl>https://auth.example.com</serverUrl>
  </default>
</MibAuthorizationClientConfig>

becomes

MIBAUTHORIZATIONCLIENTCONFIG_DEFAULT_SERVERURL=https://auth.example.com

Notable MibCmsFrontEndServerBaseConfig keys (React-era)

<MibCmsFrontEndServerBaseConfig>
  <default>
    <!-- Self-URL — must match what's registered as the OAuth REDIRECT_URI prefix -->
    <rootUrl>https://cms.example.com/</rootUrl>

    <!-- Path under which the React shell is served (typically /app via reverse proxy) -->
    <frontEndAppPath>/app</frontEndAppPath>

    <!-- Default language picked when the user has no preference -->
    <defaultLanguage>en-us</defaultLanguage>

    <!-- Pre-React rendering switch — leave false unless explicitly needed for legacy MVC -->
    <renderOnlyMibComponents>false</renderOnlyMibComponents>

    <!-- Concurrency MS pairing -->
    <userConcurrencyServiceUrl>http://concurrency-ms</userConcurrencyServiceUrl>
    <userConcurrencyPollingTime>00:00:10</userConcurrencyPollingTime>

    <!-- Audit trail integration -->
    <useEditHistoryMicroService>true</useEditHistoryMicroService>

    <!-- CORS — only if the React shell is served from a different origin -->
    <corsOrigins>https://shell.example.com</corsOrigins>
    <corsMethods>GET,POST,PUT,DELETE,PATCH,OPTIONS</corsMethods>
    <corsHeaders>Content-Type,Authorization,If-None-Match,If-Match</corsHeaders>

    <!-- TSV downloads via FileManagement (MIB 6.0+) -->
    <useFileManagementServiceForTsvDownload>true</useFileManagementServiceForTsvDownload>
  </default>
</MibCmsFrontEndServerBaseConfig>

The full reference is at MibCmsFrontEndServerBaseConfig.

CorsOrigins

Only relevant when the React shell is served from a different origin than the FrontEnd Server. If both run under one reverse proxy (e.g. https://cms.example.com/app/ for the shell and https://cms.example.com/api/v2/... for the BFF), CORS is not in play — omit corsOrigins / corsMethods / corsHeaders.

When configured, you must also enable CorsAllowCredentials so the browser sends the .AspNetCore.Cookies cookie cross-origin.

Pairing with the React shell

The React shell needs three pieces of runtime config:

  1. VITE_API_URL — the FrontEnd Server's root (e.g. https://cms.example.com/). The shell hits <root>/api/v2/... for page renders and <root>/oauth/... for the login redirect.
  2. VITE_CUSTOM_COMPONENTS_URL (and _2, _3) — federated remote URLs. See System Overview — federated remotes.
  3. A working CORS or same-origin setup. Same-origin (one reverse proxy) is strongly preferred — avoids CORS, lets the cookie ride along by default, simplifies SameSite policy.

The shell does not need to know about the Data API, microservices, or any other backend service. Everything goes through the FrontEnd Server.

Verifying the install

A healthy FrontEnd Server pod should:

  1. Pass its readiness probe at /healthcheck (200 OK).
  2. Serve the OAuth callback at /oauth/callback.
  3. Serve /configurablepermissions (200 OK, returns GenericPermission JSON; supports ETag / 304).
  4. Return a non-empty /api/v2/display/<startPage>/0 once you log in through the React shell.
  5. Emit a [RenderV2-Stats] log line per page render — see System Overview — observability.

If /healthcheck is failing, the most common causes are:

  • Permission MS unreachable. Startup blocks on the first permission-metadata fetch by default. See the MetadataInitialFetchTimeoutSeconds setting in Microservices — Permissions.
  • Database unreachable. Check MIBDATABASECONFIG_* and the FrontEnd DB connection.
  • Auth Server unreachable. Check MIBAUTHORIZATIONCLIENTCONFIG_DEFAULT_SERVERURL.
  • Missing customisation DLL. Pod crashes early with a FileNotFoundException on a MediaiBox.*.dll or <Customer>.Mib3.*.dll. See Backend overlay system — version pinning.

See also