Skip to main content

On-prem multi-tenant setup: URLs, environment and enrollment

This guide covers an organization running multiple tenants on its own infrastructure, with Cortega AI Booster, Endpoint Guard and the VS Code AI Booster Pack. Multi-tenancy is independent of hosting: an on-prem installation can serve multiple tenants. AI Verifier is no longer a standalone desktop product; use Cortega AI Booster. Existing ai_verifier, verifier_seats, ai_verifier_user and /api/v1/verifier/* identifiers remain in the implementation. Do not rename configuration or API paths.

1. Choose the configuration file​

Install pathFile the operator editsWhat produces runtime .env
Existing Docker hosts / on-premCopy deploy/.env.example to repository-root .envOperator, including addressing and secrets
AWS scriptsdeploy/aws/.env, copied from deploy/aws/env.exampledeploy/aws/deploy.sh
TerraformCloud-specific .env from deploy/terraform/env.example, plus Terraform inputsdeploy/terraform/deploy.sh
Local source developmentRepository-root .env from .env.exampleOperator; localhost defaults are development settings

For on-prem, run compose from the repository root with --env-file .env. Container env_file: ../.env is relative to deploy/. LLM provider environment keys belong in repository-root .env.provider-keys, consumed only by gateway containers. Pin the Cortega images to the release you deploy and use its matching gateway pin. Generate separate secrets for CORTEGA_ENCRYPTION_KEY, JWT_SECRET, INTERNAL_SECRET, OIDC_COOKIE_SECRET and CORTEGA_CLIENT_TELEMETRY_TOKEN; openssl rand -hex 32 produces 64 hex characters. Match POSTGRES_PASSWORD to the password in DATABASE_URL. Keep MANAGEMENT_BACKEND_URL, REDIS_URL, CLICKHOUSE_URL, PROMETHEUS_URL and OTEL_COLLECTOR_URL as private service addresses, adjusted for your network topology. Never substitute the public app URL for a private database or backend address.

2. Reserve DNS names and TLS certificates​

Use Cortega's hosted naming pattern as the concrete example: open live.cortega.ai to see the application. The app, gateway frontends and telemetry each use one subdomain directly under cortega.ai. There is no extra ai level and no tenant name in these shared service URLs.

For your on-prem installation, replace cortega.ai with a domain you control: live.example.com, gw.example.com, mcp-gw.example.com, http-gw.example.com and telemetry.example.com. Do not point customer devices at Cortega's hosted service when enrolling them into your own installation. Your DNS names must be reachable from employee browsers, native services and developer tools (including VPN users). External here means reachable by clients; private DNS is fine.

Client URL / hostnameRoute at your TLS nginx / load balancerConfiguration
https://live.cortega.aiCore edge-ingress on WEBAPP_HTTP_PORT, then webapp nginx → webapp-backend → management-backend for /api/v1/*; SPA for /CORTEGA_APP_ORIGIN, CORS_ORIGINS; native cortega_url; VS Code cortega.ai.serverUrl
https://gw.cortega.aiGateway ingress, LLM frontend (gateway port 4001); /v1/* is preservedGateway suffix, LLM template and advertised scheme/port
https://mcp-gw.cortega.aiGateway ingress, MCP frontend (port 3001); preserve /mcp and OAuth discovery pathsMCP host template
https://http-gw.cortega.aiGateway ingress, HTTP frontend (port 5001), including configured browser/OIDC routesHTTP host template
https://telemetry.cortega.aiCore telemetry-ingest host bind on 4320; container listens on 4318CORTEGA_CLIENT_TELEMETRY_URL, CLIENT_TELEMETRY_HTTP_BIND
App /api/v1/edge/sso/oauth/callbackSame app API chain; preserve host, scheme and pathRegister the full URL in each applicable IdP OAuth client
App /api/v1/auth/sso/callbackSame app API chainSSO_REDIRECT_URL for console login
App /api/v1/verifier/*Same app API chain, including browser sign-in, token polling, config, device registration and Projects/Legal MCPExisting API paths used by AI Booster Pack; these are not the gateway /mcp frontend
Insights public URL, when enabledYour Superset reverse proxy, with embedding supportedSUPERSET_PUBLIC_BASE_URL, SUPERSET_EMBED_ALLOWED_DOMAINS; private SUPERSET_BASE_URL stays server-side

For multiple gateway groups, reserve all three frontend names per group. With the example templates, group engineering adds engineering.cortega.ai, mcp-engineering.cortega.ai and http-engineering.cortega.ai. Do not assume nginx supports arbitrary tenant subdomains or tenant URL prefixes: tenant assignment comes from authenticated identities, domains, invitations and CAs. A shared app origin and shared gateway hosts can serve multiple tenants.

With this naming pattern, a wildcard certificate for *.example.com can cover all five customer hostnames, including live.example.com. Multi-tenancy does not require a second level of subdomains. Keep the single-level templates below and check each generated hostname against your DNS and certificate SANs.

3. Set public addressing and tenant mode​

The following shows the shared cortega.ai hostname pattern. For your on-prem runtime .env, replace every cortega.ai with your own domain before applying it, and add the images, secrets and datastore settings. These values illustrate URL configuration; they are not a complete copy of Cortega's production .env.

CORTEGA_MULTI_TENANCY_ENABLED=true
CORTEGA_APP_ORIGIN=https://live.cortega.ai
CORS_ORIGINS=https://live.cortega.ai
SESSION_MODE=cookie
COOKIE_SECURE=true
CORTEGA_COOKIE_SECURE=true
CORTEGA_COOKIE_DOMAIN=
SELF_SERVE_SIGNUP_ENABLED=false

CORTEGA_GATEWAY_HOST_SUFFIX=cortega.ai
CORTEGA_GATEWAY_PUBLIC_SCHEME=https
CORTEGA_GATEWAY_HTTP_PORT=443
CORTEGA_GATEWAY_EXTERNAL_ENABLED=yes
CORTEGA_INSTALL_NGINX=yes
GATEWAY_INGRESS_HOST_SUFFIX=cortega.ai
GATEWAY_INGRESS_PUBLIC_SCHEME=https
GATEWAY_INGRESS_HTTP_PORT=443
GATEWAY_INGRESS_LLM_HOST_TEMPLATE={gateway}.{suffix}
GATEWAY_INGRESS_MCP_HOST_TEMPLATE=mcp-{gateway}.{suffix}
GATEWAY_INGRESS_HTTP_HOST_TEMPLATE=http-{gateway}.{suffix}

CORTEGA_CLIENT_TELEMETRY_URL=https://telemetry.cortega.ai
EDGE_TRUST_PROXY_CLIENT_CERT_HEADER=false
EDGE_CLIENT_CERT_HEADER=X-Cortega-Edge-Client-Cert

The CORTEGA_GATEWAY_* values are managed-install inputs; gateway-compose.sh reads the GATEWAY_INGRESS_* runtime values. Keep both sets consistent when filling an on-prem file manually. Advertised HTTPS/443 does not itself install a TLS listener: nginx routing, certificate files and published host binds must be supplied. GATEWAY_INGRESS_BIND in the gateway compose file controls its private nginx listener, and GATEWAY_PUBLIC_HTTP_BIND controls its other published listener; neither is the advertised client port. WEBAPP_HTTP_PORT is the core ingress bind, not the public origin.

GATEWAY_INGRESS_ADVERTISE_GROUP can choose the group advertised to clients. For separate private gateway addressing, set GATEWAY_INGRESS_INTERNAL_HOST_SUFFIX, GATEWAY_INGRESS_INTERNAL_SCHEME, GATEWAY_INGRESS_INTERNAL_PORT and the three GATEWAY_INGRESS_INTERNAL_*_HOST_TEMPLATE values. They default to public addressing; verify that server-side callers can actually resolve and reach those URLs.

For one host, choose non-conflicting binds: for example core WEBAPP_HTTP_PORT=127.0.0.1:8080, gateway GATEWAY_PUBLIC_HTTP_BIND=127.0.0.1:8081, private gateway GATEWAY_INGRESS_BIND=127.0.0.1:18081, and telemetry CLIENT_TELEMETRY_HTTP_BIND=127.0.0.1:4320. A host nginx can route to these ports. If nginx runs on a different host, use reachable private-IP binds and firewall rules allowing that proxy. Loopback binds cannot be reached across machines. Use INSTALL_TOPOLOGY=multi only when gateways are on separate hosts; it is unrelated to the number of tenants. Configure sidecar management, Redis and OTEL reachability for those hosts as described in the load balancer guide.

Multi-tenant mode enables per-tenant model access controls and disables Pass-Through Routing, MCP OAuth, and gateway Basic Auth/OIDC identities. It does not disable console SSO or device SSO enrollment. Keep email self-serve signup disabled for an admin-provisioned enterprise rollout: that separate flow has its own tenant-creation behavior and is not the device enrollment flow below.

4. Configure nginx, rather than only editing .env​

The AWS and Terraform deploy scripts generate app, gateway, telemetry and optional Superset nginx routes. Running the existing-environment compose files alone does not run those generators. In particular docker-compose.aws-lb.yml mounts deploy/nginx/lb.d: supply the configuration before starting that service. Gateway compose mounts deploy/nginx/conf.d, whose default has no per-group routes until rendered by gateway-compose.sh. Render/start the desired gateway groups using that script with the correct base compose file and network settings. Use deploy/gateway-compose.sh plan gw=1 to review the desired group, then deploy/gateway-compose.sh up gw=1 with the appropriate CORTEGA_COMPOSE_FILE for that host. See the load balancer guide for the deployed release.

For an existing host nginx, these are the essential proxy directives for each host (use the upstream from the URL table; this example is the app on the same host). Replace live.cortega.ai with your own app hostname before installing it:

server {
listen 443 ssl;
server_name live.cortega.ai;
ssl_certificate /etc/nginx/certs/server.pem;
ssl_certificate_key /etc/nginx/certs/server-key.pem;
client_max_body_size 40m;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_buffering off;
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
}
}

Use separate host blocks for gateway and telemetry routes. Preserve authorization headers and paths, disable buffering for LLM/MCP streaming, and support WebSocket upgrade for frontends that need it. If another trusted proxy terminates TLS first, preserve its verified external scheme instead of replacing it with the internal HTTP hop's scheme. Wrong scheme/host headers generate wrong OAuth callback URLs. Keep database, Redis, gateway admin/metrics, and the raw OTEL collector private. Client telemetry must use telemetry-ingest, which derives tenant/person identity from the device credential; do not expose the collector or share its internal token with users. Set CORTEGA_CLIENT_TELEMETRY_TOKEN before starting the packaged core: the client collector requires it even before a tenant enables collection.

For certificate enrollment, use deploy/nginx/edge-mtls.conf.example as the mTLS reference. Configure the trusted Enrollment CA bundle and optional client certificates so ordinary browsers can still log in. Set EDGE_TRUST_PROXY_CLIENT_CERT_HEADER=true only after the TLS terminator validates client certificates and overwrites X-Cortega-Edge-Client-Cert with its verified, escaped certificate. Prevent access around that terminator and strip spoofable client-cert headers on other ingress paths. For an ALB certificate header use EDGE_CLIENT_CERT_HEADER=X-Amzn-Mtls-Clientcert. Enrollment CA trust is separate from the local interception CA installed on a workstation.

EDGE_OBSERVABILITY_URL is an optional fallback. The backend first chooses a registered public gateway HTTP URL, then this fallback, then the request origin. Check the actual observability_url returned to an enrolled device; a fallback will not override an already registered public gateway URL.

5. Prepare tenants and their sign-in providers​

  1. Activate the installation license with the required Endpoint Guard/AI Booster features and sufficient installation Edge seats.
  2. As Tenant 0/platform admin, create an active tenant for each organization or business unit. Enable the products, AI Booster package/seat capacity and agents that tenant needs. Installation licensing and tenant entitlements both apply.
  3. Assign tenant teams, provider/model access, budgets and the default routing choice. Configure Endpoint Guard → AI Assistants separately for each tenant: which tools are routed, usage telemetry, prompt/response collection and optional repository inventory. Sign-in alone does not turn every collection option on.
  4. Create users in the correct tenant, or assign its permitted SSO registration domains in Tenant Management. Domain lists are edited by Tenant 0 admins. When several tenants share one email domain, pre-provision exact users or use tenant-specific invitations/certificates; a domain alone cannot distinguish them.
  5. Configure a tenant SSO provider under Endpoint Guard → Enrollment, or the installation fallback via SSO_ENABLED, SSO_ISSUER_URL, SSO_CLIENT_ID, SSO_CLIENT_SECRET and SSO_REDIRECT_URL. Register the Edge OAuth callback in the OAuth client used for device/Pack sign-in, even when console login works.

Device SSO resolves an existing user's tenant before matching registration domains. Unknown, unmatched emails become pending access requests; device SSO does not silently create a new tenant. Pending Tenant 0 requests require administrator approval or assignment before retrying. Suspended users and inactive tenants cannot enroll.

6. Register AI Booster, Endpoint Guard and VS Code​

ClientEnrollmentWhat is recorded
AI Booster desktopEnterprise sign-in with your app origin or a tenant-specific invitation, then browser SSONative person-device registration in Endpoint Guard → Seats
Endpoint Guard headlessMDM installs package, per-device certificate/private key and cortega_url; alternatively an administrator imports a generated identityNative registration; trusted Enrollment CA identifies the tenant
AI Booster Pack in VS CodeSet cortega.ai.serverUrl to app origin, then Cortega AI Booster Pack: Sign inSeparate VS Code person-computer registration, labeled VS

For AI Booster invitations, create a link for the intended email and tenant under Enrollment. The link has the form https://live.cortega.ai/api/v1/edge/sso/i/<code>. Paste it into the native app's Enterprise sign-in field. Browser SSO must prove the invited email; the invitation carries the tenant. For domain-based enrollment enter the bare app origin. Never leave the server blank on an on-prem client, since client defaults point to the hosted service.

For headless Endpoint Guard, follow the certificate import/MDM instructions in the Endpoint Guard deployment guide. Shared EDGE_AGENT_ENROLLMENT_KEY enrollment is a legacy compatibility path: it proves possession of a shared secret, not a unique managed identity. Prefer tenant-specific certificates for a multi-tenant fleet.

The VS Code Pack uses /api/v1/verifier/auth/start: it asks for an email, displays a user code and opens the verification page. Confirm the browser code matches. The backend chooses that user's tenant IdP, else a domain-matched tenant IdP, else the installation IdP. SSO must return the typed email. The Pack polls /api/v1/verifier/auth/token, receives a session/rotating refresh credential, and calls POST /api/v1/verifier/me/device with VS Code's computer ID. It configures supported local AI tools from /api/v1/verifier/me/config; run Sync AI tools with Cortega and restart the tools. See the coding-tools guide for adapter coverage, shared profiles, undo and repair.

There are two capacity checks for the Pack: sign-in grants the legacy ai_verifier_user role, limited by the tenant's verifier_seats; VS device registration also checks Endpoint Guard/AI Booster tenant capacity and the installation edge_devices limit. A repeated sign-in on the same computer by the same person reuses the VS registration; another person or computer takes another. Native and VS registrations have different device identities, so deploying both can create separate Seats rows. Plan capacity for the actual client combination. Removing a VS row alone does not disable the user; the next sync can recreate it. Removing the role frees the role-based allocation; disable the account to stop further sign-ins. A full allocation returns 402 seats_full.

The Pack configures tools and usage reporting; it does not install a machine-wide TLS interception service. Native Endpoint Guard supplies that enforcement. The AI Booster desktop app exposes Projects, usage, query analysis/log and settings; verification notifications/document-check screens are no longer its primary UI.

7. Optional service URLs and on-prem egress​

SettingPurpose and requirement
ASSIST_MCP_BASE_URL, ASSIST_MCP_INTERNAL_TOKENCore → separately deployed Cortega Assist REST API. Blank URL hides Diagnose. Token must match Assist's server configuration.
Assist public /mcpSeparate MCP client route; deploy behind a dedicated governed gateway frontend with rate limits. Core app nginx does not automatically host Assist.
MODEL_INTEL_BASE_URL, MODEL_INTEL_API_TOKENCore → independent Model Intelligence replica; optional recommendations/capability metadata.
COURTLISTENER_BASE_URL, COURTLISTENER_API_TOKENLegal agent case-law lookup, when enabled. Optional fallback URL/token and LEGAL_DATA_BASE_URL/LEGAL_DATA_API_TOKEN cover replica/additional-source use.
CORTEGA_CCM_URLLicense activation/phone-home; default Cloud Manager endpoint is https://cloudmgr.cortega.ai. Plan reachability for activation.
SSO_ISSUER_URL / tenant IdPCore and browser reachability to the chosen identity provider.
EMAIL_FROM + Resend or EMAIL_SMTP_*Email delivery for workflows that send mail; optional unless those workflows are used.

Assist, Model Intelligence and Legal Data are independent deployments, not services included in the core release package. Internal service URLs need only be reachable by the caller; public MCP endpoints need client DNS/TLS. An on-prem deployment is not automatically an air-gapped deployment: also account for image downloads, configured LLM providers, IdP, license activation and any enabled external sources.

8. Acceptance check before customer rollout​

  1. From a workstation on the actual client network, verify app, each gateway frontend and telemetry DNS/TLS. Confirm /api/v1/health works through the app proxy; confirm nginx upstreams and public advertised URLs match.
  2. Sign in to the console, then AI Booster and VS Code using test users from two tenants. Verify both OAuth callbacks, correct tenant assignment and Seats rows. Test an unmatched email, a full tenant and a disabled tenant.
  3. Route one supported assistant through the gateway. Verify the selected team/model, tenant, key attribution and budget/guardrail behavior in observability, not only that configuration was saved. Test that the other tenant cannot use its resources.
  4. Enable tenant usage telemetry and confirm it reaches the correct tenant/person; prompt text appears only when collection is enabled. Verify native captured traffic separately from configured assistant gateway traffic.
  5. Enroll one MDM/certificate pilot and inspect its identity method and tenant. Confirm browsers still work without a client certificate and spoofed headers cannot bypass the terminator.
  6. If using Assist, confirm its /readyz, console Diagnose and an MCP query about this setup. Deploy a rebuilt knowledge pack with the customer release.

Troubleshooting​

SymptomLikely cause / action
Console works but device/Pack SSO failsEdge OAuth callback is missing from the applicable tenant or fallback IdP, or nginx changes host/scheme.
Sign-in goes to hosted CortegaNative server field or cortega.ai.serverUrl still uses its default; set your full app origin.
403 account_pendingUnknown domain or pending Tenant 0 request; assign/approve the user, then retry SSO.
402 seats_fullCheck role-based AI Booster allocation, person-device registrations and installation Edge limit.
App loads but AI tools failApp and gateway URLs use separate nginx routes; check the advertised LLM frontend and streaming support.
No assistant usageCheck tenant telemetry toggle, returned telemetry URL, telemetry-ingest route and internal collector token.
Certificates enroll into the wrong tenantVerify the issuing Enrollment CA and the explicit user assignment; avoid a shared domain as the only tenant selector.
Proxy cannot reach a healthy containerHost bind is loopback on a different machine, port conflict, wrong Docker network, or private firewall rule.