> ## Documentation Index
> Fetch the complete documentation index at: https://docs.prisme.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Configuration

> The most important post-install settings — auth, mail, event retention, upload limits, crawler, runtime — with the env var and Helm value path for each.

This page documents the settings you'll most often tune **after** the basic install. The Helm-level wiring (DB URLs, secrets, ingress) lives in [Install with Helm](/self-hosting/kubernetes/helm); the exhaustive env-var dump lives in [Environment Variables](/self-hosting/kubernetes/environment-variables).

<Info>
  Every option on this page is **already wired in the Helm chart defaults** — either via a dedicated Helm value or as a direct environment variable on the relevant service.

  Each setting is listed as the **env var name** with its **Helm values path** written right below it. **Always set the Helm value when one exists** rather than overriding the env var directly — they map to the same setting, but the Helm value is the supported, upgrade-safe path.
</Info>

***

## Pin all service & app tags

Pin **all** core service and app image tags to the desired tag. Available tags are listed on the [Prisme.ai releases page](https://gitlab.com/prisme.ai/prisme.ai/-/releases).

## prismeai-runtime dependencies

### LLM and vector store credentials

LLM Gateway and Storage workspaces consume credentials through `WORKSPACE_SECRET_*` environment variables exposed on **prismeai-runtime**.

<Info>
  The string after `llm-gateway_` or `storage_` is the **secret name** as it will be consumed by the LLM Gateway and Storage workspaces. The names you choose here must match the secret names referenced from the products configuration at the later [products install](/self-hosting/install-products) step.
</Info>

<Tabs>
  <Tab title="Elasticsearch Vector store">
    Declare every vector store credential as a `WORKSPACE_SECRET_storage_*` variable.

    **Examples:**

    | Field        | Variable                                          |
    | ------------ | ------------------------------------------------- |
    | Host         | `WORKSPACE_SECRET_storage_elasticsearch_host`     |
    | Username     | `WORKSPACE_SECRET_storage_elasticsearch_username` |
    | Password     | `WORKSPACE_SECRET_storage_elasticsearch_password` |
    | Index prefix | `WORKSPACE_SECRET_storage_index_prefix`           |

    `WORKSPACE_SECRET_storage_index_prefix` prefixes every RAG index name — useful when sharing the same cluster between several Prisme.ai platforms. The platform appends `_` automatically, so **the value must not end with `-` or `_`** (e.g. set `acme`, not `acme_`).
  </Tab>

  <Tab title="Opensearch Vector store">
    Declare every vector store credential as a `WORKSPACE_SECRET_storage_*` variable.

    **Examples:**

    | Field        | Variable                                       |
    | ------------ | ---------------------------------------------- |
    | Host         | `WORKSPACE_SECRET_storage_opensearch_host`     |
    | Username     | `WORKSPACE_SECRET_storage_opensearch_username` |
    | Password     | `WORKSPACE_SECRET_storage_opensearch_password` |
    | Index prefix | `WORKSPACE_SECRET_storage_index_prefix`        |

    `WORKSPACE_SECRET_storage_index_prefix` prefixes every RAG index name — useful when sharing the same cluster between several Prisme.ai platforms. The platform appends `_` automatically, so **the value must not end with `-` or `_`** (e.g. set `acme`, not `acme_`).
  </Tab>

  <Tab title="LLM providers">
    Declare every LLM provider credential as a `WORKSPACE_SECRET_llm-gateway_*` variable.

    **Examples:**

    | Provider     | Variable                                                                                                         |
    | ------------ | ---------------------------------------------------------------------------------------------------------------- |
    | AWS Bedrock  | `WORKSPACE_SECRET_llm-gateway_awsBedrockAccessKey`<br />`WORKSPACE_SECRET_llm-gateway_awsBedrockSecretAccessKey` |
    | OpenAI       | `WORKSPACE_SECRET_llm-gateway_openaiApiKey`                                                                      |
    | Azure OpenAI | `WORKSPACE_SECRET_llm-gateway_azureOpenaiApiKey`                                                                 |

    You can add as many secrets as you need — one per distinct API key — always following the same `WORKSPACE_SECRET_llm-gateway_<secretName>` pattern. `<secretName>` is free-form: pick any identifier, then reference that exact same name from the platform UI when configuring the provider to consume the secret.
  </Tab>
</Tabs>

<Tip>
  Alternatively, these secrets can be entered directly from the **Secrets** page of the **LLM Gateway** and **Storage** workspaces (after they are imported during products installation), without touching environment variables.
</Tip>

### Runtime app endpoints (custom deployments)

With the standard Helm charts, runtime → app routing is wired automatically. If you run a custom deployment, verify that the runtime configuration points to the right hosts:

```env theme={null}
APP_CONFIG_CustomCode_apiUrl=http://FUNCTIONS_HOST:80
APP_CONFIG_Crawler_apiUrl=http://SEARCHENGINE_HOST:80
```

`FUNCTIONS_HOST` must point to `prismeai-functions`, `SEARCHENGINE_HOST` to `prismeai-searchengine`, both reachable from `prismeai-runtime`.

***

## prismeai-api-gateway: Accounts and authentication

| Setting                                                              | Default   | Description                                                                                                                                                              |
| -------------------------------------------------------------------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `ACCOUNT_VALIDATION_METHOD`<br />Helm: `prismeai-api-gateway.env`    | `email`   | How new signups are validated. Set to `auto` for SSO-only deployments where every account is implicitly trusted. `manual` requires a super-admin to approve each signup. |
| `DISABLE_LOCAL_SIGNIN`<br />Helm: `prismeai-api-gateway.env`         | `false`   | Disable username/password sign-in. Only SSO providers remain available.                                                                                                  |
| `DISABLE_LOCAL_SIGNUP`<br />Helm: `prismeai-api-gateway.env`         | `false`   | Disable local sign-up API. Existing local users can still sign in.                                                                                                       |
| `SUPER_ADMIN_EMAILS`<br />Helm: `prismeai-api-gateway.config.admins` | —         | Comma-separated emails granted super-admin rights across all workspaces.                                                                                                 |
| `PASSWORD_VALIDATION_REGEXP`<br />Helm: `prismeai-api-gateway.env`   | `.{8,32}` | Custom regex for password complexity.                                                                                                                                    |
| `MFA_FORCE_LOCAL`<br />Helm: `prismeai-api-gateway.env`              | `true`    | Require TOTP multi-factor authentication for all local (password) accounts. SSO and anonymous accounts are exempt. Set to `false` to disable.                            |

### Sessions and tokens

Prisme.ai follows the standard OIDC split between **session** (server-side, on the auth server) and **access token** (JWT, on the client):

* The browser holds an **OIDC session cookie** issued by `prismeai-api-gateway`. As long as that cookie is valid, the gateway can silently mint a new JWT without prompting the user to log in again.
* Clients (Studio, APIs, automations) hold an **access token JWT** and present it on every request. When the JWT expires, the client bounces through the gateway, which — if the session cookie is still alive — hands back a fresh JWT.
* Expiring the session cookie is what actually forces a re-login, after the JWT expiration.

| Setting                                                         | Default              | Description                                                                                                                                                                                          |
| --------------------------------------------------------------- | -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `SESSION_COOKIES_MAX_AGE`<br />Helm: `prismeai-api-gateway.env` | `2592000` (30 d)     | Lifetime of the OIDC session cookie, in seconds. Controls **how long until the user is forced to re-authenticate**.                                                                                  |
| `ACCESS_TOKENS_MAX_AGE`<br />Helm: `prismeai-api-gateway.env`   | `2592000` (30 d)     | Lifetime of the access-token JWT, in seconds. Controls **how often a client silently refreshes** its token against the gateway. Lower it (e.g. `3600` for 1 h) to shrink the window of a leaked JWT. |
| `SOCKETIO_COOKIE_MAX_AGE`<br />Helm: `prismeai-events.env`      | from `cookie` module | Sticky-session cookie for `prismeai-events`. Raise this if events sessions drop too aggressively.                                                                                                    |

<Tip>
  A common production setup is a long `SESSION_COOKIES_MAX_AGE` (days / weeks for user convenience) combined with a short `ACCESS_TOKENS_MAX_AGE` (1–4 h) so JWTs rotate frequently while users stay logged in.
</Tip>

***

## Email provider

Configure at least one provider to send signup-validation / password-reset emails.

### Mailgun

```yaml theme={null}
prismeai-api-gateway:
  providers:
    mailgun:
      apiKey: ""                                # or use existingSecret
      existingSecret: "core-prismeai-api-gateway-mailgun"
      emailFrom: '"Prisme.ai" <no-reply@example.com>'
  env:
    - name: EMAIL_DRIVER
      value: "mailgun"
```

### SMTP

```yaml theme={null}
prismeai-api-gateway:
  env:
    - name: EMAIL_DRIVER
      value: "smtp"
    - name: EMAIL_FROM
      value: '"Prisme.ai" <no-reply@example.com>'
    - name: SMTP_HOST
      value: "smtp.example.com"
    - name: SMTP_PORT
      value: "587"
    - name: SMTP_USER
      value: "user"
    - name: SMTP_PASS
      value: "password"      # prefer existingSecret
    - name: SMTP_SECURE
      value: "false"       # true for port 465
```

***

## CORS

By default, the API gateway only accepts cross-origin requests from `CONSOLE_URL` and from workspace custom domains. To embed agents or call the API from another origin (e.g. a public website hosting the chat widget), allowlist it explicitly:

| Setting                                                                 | Default | Description                                                                                                                                                                                                                                                                                          |
| ----------------------------------------------------------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `CORS_ADDITIONAL_ALLOWED_ORIGINS`<br />Helm: `prismeai-api-gateway.env` | —       | Comma-separated list of extra origins accepted for CORS, in addition to `CONSOLE_URL` and workspace custom domains. Each entry must include the scheme (e.g. `https://www.example.com,https://app.partner.com`). Required when embedding the chat widget or calling the API from a third-party site. |

***

## Exposing several front-end domains

A single Prisme.ai platform can serve its **front-end (Studio / console)** on **several domains at once** — e.g. `studio.example.com`, `team-a.example.com`, `team-b.example.com` — all backed by the same core services. This is the standard multi-tenant SaaS setup.

<Info>
  Only the **front-end** is multi-domain. The **API gateway always keeps a single public domain** (`global.apiUrl`, e.g. `https://api.example.com/v2`) — every console domain talks to that same backend URL.
</Info>

There are three things to wire, all in your `prismeai-core` values file:

### 1. List every console domain in `global.consoleUrl`

`global.consoleUrl` accepts a **comma-separated** list of front-end URLs. The **first entry is the default** — it's the one used for emails and sign-out when a request carries no recognizable origin. Every entry is automatically allow-listed by the api-gateway for **OIDC `redirect_uris`**, **CSP `frame-ancestors`** and **CORS**, so you don't have to repeat them anywhere else.

```yaml theme={null}
global:
  # Single backend domain, shared by every console domain below
  apiUrl: "https://api.example.com/v2"

  # Comma-separated list of front-end URLs (multi-domain SaaS). The first
  # entry is the default used for emails/signout when no per-request origin
  # is available. All entries are auto-allowlisted by api-gateway for OIDC
  # redirect_uris, CSP frame-ancestors and CORS.
  consoleUrl: "https://studio.example.com,https://team-a.example.com,https://team-b.example.com"
```

### 2. Point every domain's DNS at the load balancer

Create a DNS record for **each** console domain that resolves to the **same** ingress load balancer (the ALB / NLB / nginx service that fronts the platform) — typically a `CNAME` to the LB hostname, or an `A`/`ALIAS` record to its address. All the front domains share one load balancer; the ingress routing (next step) is what dispatches each host to the right service. Don't forget your TLS certificates must cover every domain (SAN cert or one cert per domain, depending on your ingress controller).

### 3. Add a front-end rule per domain on the ingress

Each console domain needs its own `host` rule on the ingress, all pointing to the **same** `prismeai-console` service. Define the console backend once with a YAML anchor, then reuse it for every domain — that keeps the block DRY as the list grows:

```yaml theme={null}
ingresses:
  - name: core-ingress
    annotations:
      # … your ingress-controller annotations (class, TLS, redirects) …
    rules:
      # ── API gateway: a SINGLE domain ──────────────────────────────
      - host: api.example.com
        http: &API_SERVICE
          paths:
            - path: "/"
              pathType: Prefix
              backend:
                service:
                  name: prismeai-core-prismeai-api-gateway
                  port:
                    number: 80

      # ── Front-end: ONE block per console domain ───────────────────
      - host: studio.example.com          # default console (1st consoleUrl entry)
        http: &CONSOLE_SERVICE
          paths:
            - path: "/"
              pathType: Prefix
              backend:
                service:
                  name: prismeai-core-prismeai-console
                  port:
                    number: 80
      - host: team-a.example.com          # reuses the same console service
        http: *CONSOLE_SERVICE
      - host: team-b.example.com
        http: *CONSOLE_SERVICE
```

Adding a new front domain later is then a three-line change: add it to `global.consoleUrl`, create its DNS record, and append one more `- host: … / http: *CONSOLE_SERVICE` rule.

***

## Upload and request limits

| Setting                                                                                                     | Default              | Description                                                                                                                       |
| ----------------------------------------------------------------------------------------------------------- | -------------------- | --------------------------------------------------------------------------------------------------------------------------------- |
| `UPLOADS_MAX_SIZE`<br />Helm: `prismeai-api-gateway.env`, `prismeai-workspaces.env`, `prismeai-runtime.env` | `100000000` (100 MB) | Max user upload size in bytes. The chart sets this on all three services; lower it if you want to clamp uploads further.          |
| `UPLOADS_ALLOWED_MIMETYPES`<br />Helm: `prismeai-workspaces.env`                                            | —                    | Comma-separated MIME types accepted on upload. Recommended: `image/*,text/*,video/*,audio/*,application/*,font/*,message/rfc822`. |
| `REQUEST_MAX_SIZE`<br />Helm: `prismeai-functions.env`, `prismeai-api-gateway.env`                          | `1mb`                | Max request body size accepted by the service. Raise `prismeai-functions` to `20mb` for code-heavy automation payloads.           |

***

## Event retention and cleanup

The platform produces a large volume of activity events. Tune retention or you'll outgrow your Elasticsearch or OpenSearch cluster.

```yaml theme={null}
prismeai-events:
  events:
    cleanupjob: true                            # Create a cronjob to call /cleanup API in order to regularly apply retention, clean unused & inactive workspaces

    # 1. Delete events older than 3 years
    retention: 1080

    # 2. Delete all events from small & inactive workspaces:
    workspaceMaxEvents: 5000                    # with max N events
    workspaceInactivityDays: 14                 # & inactive for N days

    # 3. Strip payload & output fields from runtime.automations.executed events older than:
    automationExecutedExpiration: "14d"
```

| Setting                                                                       | Default        | Description                                                                                                                                                                                                                                                     |
| ----------------------------------------------------------------------------- | -------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `EVENTS_STORAGE_NAMESPACE`<br />Helm: `prismeai-events.env`                   | —              | Per-tenant event index prefix when sharing an ES / OS cluster.                                                                                                                                                                                                  |
| `BROKER_EMIT_MAXLEN`<br />Helm: `prismeai-runtime.env`, `prismeai-events.env` | `100000` chars | Max event payload size emitted to the broker. Default keeps the broker healthy; raise it only if you understand the disk impact.                                                                                                                                |
| `BROKER_EMIT_EXECUTED_AUTOMATION_MAXLEN`<br />Helm: `prismeai-runtime.env`    | `10000` chars  | Tighter limit for `runtime.automations.executed` (monitoring-only events).                                                                                                                                                                                      |
| `EVENTS_BUFFER_FLUSH_AT`<br />Helm: `prismeai-events.env`                     | `500`          | Flush the in-memory events buffer once it holds this many events. Pairs with `EVENTS_BUFFER_FLUSH_EVERY` — whichever threshold is hit first triggers a flush. Raise it on Performance deployments to reduce write amplification on Elasticsearch or OpenSearch. |
| `EVENTS_BUFFER_FLUSH_EVERY`<br />Helm: `prismeai-events.env`                  | `1000` ms      | Flush the buffer every N milliseconds even if `EVENTS_BUFFER_FLUSH_AT` isn't reached. Lower it for fresher activity feeds, raise it to reduce ES write load.                                                                                                    |
| `ELASTIC_SEARCH_TIMEOUT`<br />Helm: `prismeai-events.env`                     | `20000ms`      | Lower it to fail faster on slow ES queries, raise it to tolerate heavier load.                                                                                                                                                                                  |

***

## Functions (custom code)

The two settings below are the most often tuned — see [Functions Microservice](/self-hosting/entreprise/functions) for the full env-var reference (task storage, memory caps, NPM registry, …).

| Setting                                                | Default | Description                                        |
| ------------------------------------------------------ | ------- | -------------------------------------------------- |
| `REQUEST_MAX_SIZE`<br />Helm: `prismeai-functions.env` | `20mb`  | Max request body accepted by `prismeai-functions`. |
| `KERNEL_POOL_SIZE`<br />Helm: `prismeai-functions.env` | `10`    | Python Jupyter kernels kept warm per pod.          |

***

## Crawler & Searchengine

The settings below are the most often tuned — see [Crawler & SearchEngine Microservices](/self-hosting/entreprise/crawler-searchengine) for the full env-var reference.

| Setting                                                                                 | Default                 | Description                                                                                           |
| --------------------------------------------------------------------------------------- | ----------------------- | ----------------------------------------------------------------------------------------------------- |
| `ELASTIC_INDICES_PREFIX`<br />Helm: `prismeai-crawler.env`, `prismeai-searchengine.env` | —                       | Index name prefix. Set when sharing Elasticsearch with other tenants.                                 |
| `MAX_CONTENT_LEN`<br />Helm: `prismeai-crawler.env`                                     | `1500000` (1.5 M chars) | Max indexed document size.                                                                            |
| `DOWNLOAD_DELAY`<br />Helm: `prismeai-crawler.env`                                      | `0`                     | Seconds between requests to the same source. Set to `0.5` for typical sources to avoid rate-limiting. |
| `REQUEST_QUEUES_POLLING_SIZE`<br />Helm: `prismeai-crawler.env`                         | `1`                     | Concurrent requests per pod. `8` for typical document mix.                                            |
| `REQUEST_QUEUES_POLLING_INTERVAL`<br />Helm: `prismeai-crawler.env`                     | `2` s                   | Queue poll frequency.                                                                                 |
| `DEFAULT_ENGINE_WEBPAGES_LIMIT`<br />Helm: `prismeai-crawler.env`                       | `30000`                 | Max pages indexed per search engine before crawling stops.                                            |

***

## Rate limiting

The platform enforces rate limits at three places, with different semantics:

| Layer                        | Where it's configured                                         | Behavior on excess               |
| ---------------------------- | ------------------------------------------------------------- | -------------------------------- |
| **Authentication endpoints** | `RATE_LIMIT_*` env vars on `prismeai-api-gateway`             | HTTP 429, request rejected       |
| **Workspace APIs**           | `prismeai-api-gateway-config` ConfigMap in core k8s namespace | HTTP 429, request rejected       |
| **Automations**              | `RATE_LIMIT_*` env vars on `prismeai-runtime`                 | Slowed down, execution continues |

### Authentication endpoints (`prismeai-api-gateway` env variables)

`RATE_LIMIT_*` env vars protect signup, login and password reset. Requests above the threshold are **rejected** with HTTP 429. Tune these tighter for production to slow down credential-stuffing or signup abuse. See [Environment Variables — Rate Limiting](/self-hosting/kubernetes/environment-variables#rate-limiting).

### Workspace APIs (gateway ConfigMap)

In addition to the env-var-driven auth limits, the gateway applies four **per-user** rate limits on native workspaces routes, defined in the `gateway.config.yml` of the `core-prismeai-api-gateway-config` ConfigMap. All four use `key: userId` and `window: 60s`.

| Limit name        | Routes                                                                                                                                                                                  | Default      |
| ----------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------ |
| `searchEvents`    | `GET /v2/workspaces/:workspaceId/events`, `/search`, `/usage` (and `/v2/search`)                                                                                                        | **40 / min** |
| `uploadFile`      | `POST /v2/workspaces/:workspaceId/files`                                                                                                                                                | **50 / min** |
| `createWorkspace` | `POST /v2/workspaces/`                                                                                                                                                                  | **3 / min**  |
| `importWorkspace` | `POST /v2/workspaces/import`, `/v2/workspaces/:workspaceId/import`, `/v2/workspaces/:workspaceId/versions/:versionId/pull`, `/v2/workspaces/:workspaceId/versions/:versionId/duplicate` | **3 / min**  |

Override by editing the ConfigMap directly. These are platform-level guardrails — they apply to every user, including super-admins, so raise them carefully when scripting bulk operations.

### Automations (`prismeai-runtime` env vars)

`RATE_LIMIT_*` env vars on the runtime protect the automation engine. **Unlike the gateway, these do not break execution** — automations that exceed the threshold are deliberately **slowed down** rather than failed. The intent is fair-share execution under load, not to reject work. See [API Reference — Rate Limits](/api-reference/rate-limits#configuration-options) for the full list and per-workspace overrides.

***

## Secrets encryption keys

Prisme.ai encrypts workspace secrets at rest with **envelope encryption** (AES-256-GCM): a master key (KEK) wraps per-workspace data keys, and short-lived **reference keys** sign secret references. Both live in a single Kubernetes Secret — `<release>-secrets-encryption` by default — and are exposed to the services as the `SECRETS_MASTER_KEYS` / `SECRETS_REF_KEYS` environment variables.

<Warning>
  If the master keys are lost, **all encrypted workspace data becomes permanently unrecoverable.** Back them up the moment they exist and store them in a vault or password manager.
</Warning>

<Info>
  **Recommended:** pre-create the encryption Secret and reference it with `existingSecret`. That is the only deterministic path for `helm template` / GitOps (Argo CD, Flux), and it is documented as an install step in [Install with Helm → Secrets encryption keys](/self-hosting/kubernetes/helm#secrets-encryption-keys). The **auto-generation** option below is for quick, non-GitOps `helm install`.
</Info>

### Option — auto-generation (live `helm install` only)

On a live `helm install`, the chart auto-generates the keys into an immutable Secret and preserves them across every `helm upgrade` by reading the live Secret through Helm's `lookup`. No pre-create step is needed — but this only works when Helm actually talks to the cluster.

<Warning>
  `helm template`, client-side `--dry-run`, `helm diff`, and **GitOps tools that render with `helm template` (Argo CD, Flux)** cannot run `lookup` — it returns empty. The chart would then generate **new** keys on every render, silently breaking decryption of all previously encrypted data. If you use any `helm template`-based pipeline, do **not** rely on auto-generation — [pre-create the Secret instead](/self-hosting/kubernetes/helm#secrets-encryption-keys).
</Warning>

Back up the generated keys right after install:

```bash theme={null}
kubectl get secret prismeai-core-secrets-encryption -n prismeai-core \
  -o jsonpath='{.data.masterKeys}' | base64 -d > masterKeys.json
kubectl get secret prismeai-core-secrets-encryption -n prismeai-core \
  -o jsonpath='{.data.refKeys}'    | base64 -d > refKeys.json
```

<Tip>
  For upgrade preflight in this mode, use **`helm upgrade --dry-run=server`** rather than `helm template` — server-side dry-run lets Helm read the live Secret through `lookup`, so the keys are preserved instead of appearing empty.
</Tip>

### Value reference

| Field                                        | Default               | Description                                                                                                                                                                                                    |
| -------------------------------------------- | --------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `global.secretsEncryption.existingSecret`    | `""`                  | Reference a pre-existing Secret (must contain `masterKeys` and `refKeys`). The recommended path for GitOps / `helm template` — see [Install with Helm](/self-hosting/kubernetes/helm#secrets-encryption-keys). |
| `global.secretsEncryption.masterKeys`        | `""` (auto-generated) | Explicit KEK. Format: `[{"kid":"kek-v1","key":"<64-hex>","active":true}]`. Must be set **together with** `refKeys`. Only applied when the Secret does not yet exist.                                           |
| `global.secretsEncryption.refKeys`           | `""` (auto-generated) | Explicit reference key, same format. Must be set together with `masterKeys`.                                                                                                                                   |
| `global.secretsEncryption.allowAutoGenerate` | `false`               | **Dangerous.** Allow key generation on upgrade when `lookup` fails and no Secret is found. Ignored when live keys exist.                                                                                       |

<Note>
  `masterKeys` and `refKeys` must always be provided **together** — supplying only one is rejected, because mixing an explicit key with a freshly generated one would break either encrypted data or secret references. The Secret is immutable; to rotate keys you delete and recreate it with a new `active` key (keep the old key in the array so existing data still decrypts). See [Workspace secrets](/products/ai-builder/module-secrets) for how secrets are used at the product level.
</Note>

***

## Trusting an extra CA bundle

When Prisme.ai services call an HTTPS endpoint signed by a private PKI or a self-signed certificate — an internal API, an on-prem LLM gateway, a Prisme.ai app behind an in-cluster TLS terminator — the calling runtime refuses the handshake unless the signing CA is in its trust store. `global.extraCABundle` lets you mount one PEM bundle into **every Prisme.ai pod in one shot**, on both the `prismeai-core` and `prismeai-apps` charts.

The chart only references a Secret or ConfigMap that **you create out-of-band** — it never reads or writes the bundle itself, so rotations stay independent of helm upgrades.

| Chart           | Services covered                                                       | Env vars set on each pod                                                                                                                                                                     |
| --------------- | ---------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `prismeai-core` | api-gateway, workspaces, runtime, events, console, pages (all Node.js) | `NODE_EXTRA_CA_CERTS` (additive)                                                                                                                                                             |
| `prismeai-apps` | functions, crawler, searchengine, nlu, llm                             | `NODE_EXTRA_CA_CERTS` (additive — Node), `SSL_CERT_FILE` (OpenSSL — Python `ssl`, httpx, aiohttp, Scrapy, curl, Go), `REQUESTS_CA_BUNDLE` (Python `requests`, which ignores `SSL_CERT_FILE`) |

<Info>
  **`SSL_CERT_FILE` and `REQUESTS_CA_BUNDLE` replace** (not augment) the default trust store. To keep public TLS working out of the box, the `prismeai-apps` chart runs a tiny init container (`extra-ca-merge`, reusing the service's own image) that concatenates the system bundle with your custom one into an `emptyDir`, and points the env vars at the merged file. This is **enabled by default** via `global.extraCABundle.mergeWithSystem: true`. Your bundle can contain only your private CAs — public CAs come from the service's own distro.

  Set `mergeWithSystem: false` if your bundle already contains the public CAs, or if you explicitly want to restrict the trust store to your private CAs only (no init container runs and the env vars point at the raw bundle).

  On `prismeai-core`, `NODE_EXTRA_CA_CERTS` is additive natively, so there's no init container and no merge toggle.
</Info>

### Step 1 — Create the Secret (or ConfigMap) holding the bundle

Concatenate every CA certificate you want to trust into a single PEM file, then create the Secret in **each namespace** where you install a Prisme.ai chart (typically `core` and `apps`):

```bash theme={null}
kubectl -n core create secret generic prismeai-extra-ca \
  --from-file=ca-bundle.crt=./bundle.crt

kubectl -n apps create secret generic prismeai-extra-ca \
  --from-file=ca-bundle.crt=./bundle.crt
```

A `ConfigMap` works equally well if the bundle is not sensitive:

```bash theme={null}
kubectl -n core create configmap prismeai-extra-ca \
  --from-file=ca-bundle.crt=./bundle.crt
```

The **key name inside the resource** (`ca-bundle.crt` above) is what the chart mounts — pick anything, just remember it for step 2.

### Step 2 — Reference it from your values

Identical block in both `prismeai-core` and `prismeai-apps` values files:

```yaml theme={null}
global:
  extraCABundle:
    existingSecret: prismeai-extra-ca        # name of the Secret created at step 1
    # existingConfigMap: prismeai-extra-ca   # OR a ConfigMap — set only one of the two
    key: ca-bundle.crt                       # file name inside the Secret/ConfigMap
    mountPath: /etc/ssl/prismeai-extra-ca    # where the file is mounted in each pod
```

| Field                                              | Default                      | Description                                                                                                                                                   |
| -------------------------------------------------- | ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `global.extraCABundle.existingSecret`              | `""`                         | Name of a Secret holding the bundle. Mutually exclusive with `existingConfigMap`.                                                                             |
| `global.extraCABundle.existingConfigMap`           | `""`                         | Name of a ConfigMap holding the bundle. Mutually exclusive with `existingSecret`.                                                                             |
| `global.extraCABundle.key`                         | `ca-bundle.crt`              | Key inside the Secret/ConfigMap holding the PEM-concatenated bundle.                                                                                          |
| `global.extraCABundle.mountPath`                   | `/etc/ssl/prismeai-extra-ca` | Directory where the bundle is mounted inside each pod. The full file path becomes `<mountPath>/<key>`.                                                        |
| `global.extraCABundle.mergeWithSystem` (apps only) | `true`                       | Run an init container that merges the service image's system CA bundle with yours. Disable to point env vars at the raw bundle (and skip the init container). |

### Step 3 — Upgrade and verify

```bash theme={null}
helm upgrade -n core core prismeai/prismeai-core -f core-values.yaml
helm upgrade -n apps apps prismeai/prismeai-apps -f apps-values.yaml
```

Every deployment / statefulset is rolled out with the mount and env vars wired in. Confirm on one pod per chart:

```bash theme={null}
# Core (Node.js)
kubectl -n core exec deploy/core-prismeai-runtime -- \
  sh -c 'echo $NODE_EXTRA_CA_CERTS && head -1 $NODE_EXTRA_CA_CERTS'
# /etc/ssl/prismeai-extra-ca/ca-bundle.crt
# -----BEGIN CERTIFICATE-----

# Apps (Python)
kubectl -n apps exec deploy/apps-prismeai-crawler -- \
  sh -c 'echo $SSL_CERT_FILE && head -1 $SSL_CERT_FILE'
```

Then call your private HTTPS endpoint from an automation (`fetch` instruction or a Custom Code function) — it should succeed without `UNABLE_TO_VERIFY_LEAF_SIGNATURE` / `SELF_SIGNED_CERT_IN_CHAIN` / `CERTIFICATE_VERIFY_FAILED`.

<Info>
  Rotating the bundle is a `kubectl` operation on the Secret/ConfigMap you own — no helm upgrade required. Pods pick up the new file automatically (mounted secrets refresh within \~60s); restart the deployment if you need the change immediately.
</Info>

***

## HTTP Proxy

When the cluster has no direct egress to the internet — or when corporate policy forces every external call through a forward proxy — `global.proxy` propagates the standard env vars (`HTTP_PROXY` / `HTTPS_PROXY` / `NO_PROXY` plus lowercase variants) to every Prisme.ai pod, on both `prismeai-core` and `prismeai-apps`.

| Chart           | Services impacted                                        | What honors the env vars                                                                                    |
| --------------- | -------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- |
| `prismeai-core` | api-gateway, workspaces, runtime, events, console, pages | Node.js (with `NODE_USE_ENV_PROXY=1`, set by the chart for Node 24+)                                        |
| `prismeai-apps` | functions (Node.js), crawler, searchengine, nlu, llm     | Python (`requests`, `httpx`, `aiohttp`, `urllib`, Scrapy) honors them natively; Node functions same as core |

### Step 1 — Configure the proxy values

Identical block on both charts:

```yaml theme={null}
global:
  proxy:
    httpProxy:  "http://proxy.corp.example.com:8080"
    httpsProxy: "http://proxy.corp.example.com:8080"   # usually same as httpProxy
    # Comma-separated. Chart defaults already include cluster-internal services —
    # APPEND every external host that must skip the proxy (managed DBs,
    # internal LLM endpoint, OIDC IdP, …).
    noProxy: "localhost,127.0.0.1,.cluster.local,mongo.corp.example.com,oidc.corp.example.com"
```

| Field                     | Default                                | Description                                                                                                                                  |
| ------------------------- | -------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
| `global.proxy.httpProxy`  | `""`                                   | HTTP proxy URL (`http://host:port`, optionally `http://user:pass@host:port`). Sets `HTTP_PROXY` + `http_proxy`.                              |
| `global.proxy.httpsProxy` | `""`                                   | HTTPS proxy URL — almost always the same value as `httpProxy` since a single forward proxy handles both. Sets `HTTPS_PROXY` + `https_proxy`. |
| `global.proxy.noProxy`    | `"localhost,127.0.0.1,.cluster.local"` | Comma-separated host/CIDR list that bypasses the proxy. Keep the cluster defaults and append your own.                                       |

<Warning>
  `HTTP_PROXY` only affects HTTP/HTTPS clients. **Binary-protocol stores (MongoDB, PostgreSQL, Redis) bypass it natively** — no need to add them to `noProxy`. But the chart also talks HTTP to several externally-reachable services that the proxy *will* try to intercept; if they're directly reachable from the cluster, add them to `noProxy` explicitly:

  * **Elasticsearch or OpenSearch** (`storage.events.url`, crawler's `storage.documents.url`) — Python ES clients honor `HTTPS_PROXY`.
  * **S3 / Azure Blob / GCS** (`storage.workspaces.*`, `storage.uploads.*`) — SDKs honor `HTTPS_PROXY`.
  * **OIDC IdP, LLM gateway, internal HTTP APIs** reached from `prismeai-runtime` / `prismeai-api-gateway`.

  Intra-cluster traffic addressed by FQDN (`*.svc.cluster.local`) and `localhost` is already covered by the chart's default `noProxy`. **`NO_PROXY` matching is suffix-based** (curl/Go/Python/Node all behave the same way: "host ENDS WITH entry"), so short-form service names like `core-prismeai-api-gateway.core` will NOT match `.cluster.local` — either use FQDN in your internal URLs (e.g. `internalApiUrl: "http://core-prismeai-api-gateway.core.svc.cluster.local/v2"`), or append the short forms to `noProxy` explicitly.
</Warning>

### Step 2 — Upgrade and verify

```bash theme={null}
helm upgrade -n core core prismeai/prismeai-core -f core-values.yaml
helm upgrade -n apps apps prismeai/prismeai-apps -f apps-values.yaml
```

Confirm the env vars are wired in:

```bash theme={null}
kubectl -n core exec deploy/core-prismeai-runtime -- printenv | grep -i proxy
```

Then trigger an outbound call from an automation (a `fetch` instruction to a public URL) and watch your proxy access logs — the request should appear there.

<Info>
  Proxy auth credentials embedded in `httpProxy` / `httpsProxy` will be visible in pod env vars and in plaintext YAML on the filesystem. For sensitive credentials, keep the password out of the chart values and inject the full URL via `existingSecret` on a per-service `envFrom` instead.
</Info>

***

## Offline or private-network deployments

For restricted environments, verify these points:

* `prismeai-functions` only needs an npm registry if you plan to write Custom Code that pulls in extra packages beyond the ones bundled in the image. See [Custom Code Functions — NPM Registry Access](/self-hosting/entreprise/functions#optional-npm-registry-access).
* If internal or self-signed certificates are used to sign HTTPS endpoints that the platform calls, propagate the CA bundle to every service via [Trusting an extra CA bundle](#trusting-an-extra-ca-bundle) — one helm value covers both `prismeai-core` and `prismeai-apps`.
* LLM providers, vector stores, and crawler targets must be reachable from the relevant pods.

***

## Security context

Every Prisme.ai service supports the standard [Kubernetes Security Context](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/) fields. Set them per service to enforce non-root execution, drop Linux capabilities, and prevent privilege escalation.

```yaml theme={null}
prismeai-api-gateway:           # repeat the same block under each service
  securityContext:
    runAsUser: 1000
  containerSecurityContext:
    allowPrivilegeEscalation: false
    privileged: false
    capabilities:
      drop:
        - ALL
```

Applies as-is to `prismeai-api-gateway`, `prismeai-workspaces`, `prismeai-runtime`, `prismeai-events`, `prismeai-console`, `prismeai-pages` (core) and `prismeai-crawler`, `prismeai-searchengine`, `prismeai-nlu`, `prismeai-llm` (apps).

<Note>
  **`prismeai-functions` is the exception.** Its pod runs a root supervisor that forks each Custom Code execution into an isolated sandbox with its own UNIX user, network namespace and resource limits — that's the actual isolation layer. Hardening the parent container's security context is allowed but **does not** further restrict the sandboxes, so the gain is marginal. Don't block root on the functions pod unless you've verified the supervisor still starts.
</Note>

***

## Where to go next

* [Install products](/self-hosting/install-products) — once the readiness check is green, import the platform products (Agent Creator, LLM Gateway, Storage, Governe, …).
* [Resources & Autoscaling](/self-hosting/kubernetes/resources) — picking Balanced vs Performance, HPA targets.
* [Environment Variables](/self-hosting/kubernetes/environment-variables) — exhaustive per-service reference.
* [Operations / Scaling](/self-hosting/operations/scaling) — runtime tuning under load.
