Skip to main content

Self-hosted runs every plane in your environment: the console, the product control planes, the data planes and the analytics stack. Nothing depends on NeuralTrust SaaS. The one connection that leaves your network by default is TrustGuard’s scoring call to the inference plane, and you can bring that in-cluster too.

The chart calls this mode External (global.deploymentMode: external), and the values, file names and log lines on this page use that name. Choose Self-hosted for strict data-residency mandates, air-gapped environments, or when policy forbids any outbound dependency on NeuralTrust SaaS. There are no console-issued tokens: the platform is its own configuration source. Decide one thing up front — where the ML detectors run: Both are the same install with two settings changed, and both are described in Reference architectures. The Inference plane page explains the trade-off in full. This page is the whole install, written to be followed from top to bottom: architecture, prerequisites, datastores, the step-by-step install, and high availability.

Before you start

  • The variant: hosted inference plane or air-gapped
  • The firewall key from NeuralTrust, for the region you want scoring in — hosted variant only; ask before you start
  • A cluster with an ingress controller and Helm 3.8+, sized per Prerequisites
  • The console hostname, decided before install — see Decide the console hostname first
  • PostgreSQL, Redis and ClickHouse — see Datastores
  • The registry key, or a mirror of the images for an air-gapped cluster
  • An SMTP or email provider, for console invitations and password resets

Architecture

Self-hosted architecture: the platform runs in your environment. Clients call TrustGate on :8081 for LLM traffic and :8082 for MCP, and TrustGate calls TrustGuard on :8081. An in-cluster control plane — console and API on :8000, AgentGateway admin on :8080, and the TrustGuard control plane on :8080 — serves configuration to TrustGate and TrustGuard. TrustGate and TrustGuard emit OTLP to a collector on :4317 and :4318 that writes to in-cluster ClickHouse; DataCore and AlertEngine read from it. PostgreSQL and Redis are recommended datastores outside the cluster, and there is no DataAgent. The one connection that leaves your environment by default is TrustGuard calling the NeuralTrust inference plane over outbound 443: a hosted, stateless Firewall of ML detectors at firewall.neuraltrust.ai (EU) or firewall.us.neuraltrust.ai (US) that scores text and stores nothing. A note shows the Firewall can run in-cluster instead with global.firewall.deploy: true. Self-hosted architecture: the platform runs in your environment. Clients call TrustGate on :8081 for LLM traffic and :8082 for MCP, and TrustGate calls TrustGuard on :8081. An in-cluster control plane — console and API on :8000, AgentGateway admin on :8080, and the TrustGuard control plane on :8080 — serves configuration to TrustGate and TrustGuard. TrustGate and TrustGuard emit OTLP to a collector on :4317 and :4318 that writes to in-cluster ClickHouse; DataCore and AlertEngine read from it. PostgreSQL and Redis are recommended datastores outside the cluster, and there is no DataAgent. The one connection that leaves your environment by default is TrustGuard calling the NeuralTrust inference plane over outbound 443: a hosted, stateless Firewall of ML detectors at firewall.neuraltrust.ai (EU) or firewall.us.neuraltrust.ai (US) that scores text and stores nothing. A note shows the Firewall can run in-cluster instead with global.firewall.deploy: true. Three properties shape everything else on this page:
  • Configuration comes from PostgreSQL, not from a config-sync stream. Each product’s data plane reads its configuration directly from that product’s database, which its own in-cluster control plane owns and migrates.
  • DataCore replaces DataAgent. There is no SaaS pushing queries over an outbound stream, so an in-cluster HTTP API serves tenant-scoped queries from ClickHouse instead, plus deployment metadata from its own datacore database.
  • The Firewall is NeuralTrust-hosted by default. TrustGuard sends the text its ML detectors score to the NeuralTrust inference plane and gets a score back; nothing is stored there. Ask NeuralTrust for the install’s firewall key before you deploy, or run the Firewall in your cluster with global.firewall.deploy: true — see Firewall.

What runs

A complete platform install. Every table below is deployed by the same umbrella chart in one release.

Request path

Control plane

Analytics

Every product deploys unless you turn it off, and DataAgent never runs.

TrustGuard only

Turn TrustGate off to run TrustGuard on its own:
The chart ships this as values-external-trustguard-only.yaml.example. It removes TrustGate’s workloads, hosts and Secrets, plus what only TrustGate uses: the in-cluster Firewall’s complexity worker, MCP OAuth and the Admin API machine credentials. Leave dataPlane on: the console reads runtime activity from the data-plane API. The audit trail does not depend on it; audit events are sent as OTLP logs and shown under Telemetry → Logs.

Prerequisites

  • A Kubernetes cluster with an ingress controller, and Helm 3.8+
  • 3 nodes of 8 vCPU / 16 GiB with the NeuralTrust-hosted Firewall, or 4 of 8 vCPU / 32 GiB with the Firewall in your cluster — the console and analytics stack on top of the data path — as the minimum of an autoscaled node pool; GPU options are in Capacity
  • The firewall key NeuralTrust issues for this install, unless you run the Firewall in your cluster — ask for it before you start
  • A base domain you can point at the cluster ingress
  • PostgreSQL, Redis, and ClickHouse — see Datastores
  • The registry key NeuralTrust sends you, or a mirror of the images for an air-gapped cluster — Container images
  • An SMTP or email provider, for console invitations and password resets

Decide the console hostname first

APP_URL and NEXTAUTH_URL drive email links, SSO redirects, and OAuth callbacks. Changing them later invalidates in-flight invitations and breaks configured SSO redirect URIs, so pick the hostname before installing. One limitation to know about: a handful of console values are NEXT_PUBLIC_*, which Next.js inlines into the JavaScript bundle at image build time. Helm cannot set them. In practice two matter, and both are cosmetic rather than blocking — the SCIM tenant URL shown to administrators and the meta.location returned to your IdP will show app.neuraltrust.ai. Enter your own host in your IdP rather than copying what the screen displays.

Network

Self-hosted’s only outbound connection to NeuralTrust is the hosted Firewall: firewall.neuraltrust.ai (EU) or firewall.us.neuraltrust.ai (US) on 443, or the same host over Google Cloud Private Service Connect. With the Firewall in your cluster (global.firewall.deploy: true) a self-hosted install needs no outbound connectivity to NeuralTrust at all. There is no inbound source IP to admit. What you do need reachable: Inbound, clients reach the TrustGate LLM and MCP hosts, and your operators reach the console — see Public routing. Air-gapped installs cannot reach the hosted Firewall: set global.firewall.deploy: true, mirror the images into an internal registry and set global.imageRegistry with global.imageRegistryScope: all, so the collector and Firewall images follow — see Mirror to your own registry.

Datastores

Recommended for production: managed PostgreSQL and Redis outside the cluster, with ClickHouse in-cluster. The chart defaults to in-cluster PostgreSQL and Redis (deploy: true) so a proof of concept can helm install without provisioning anything first — that is convenience, not the production shape. ClickHouse is mandatory here, unlike a Hybrid data plane where analytics stay on the hosted path. Nearly everyone runs the in-cluster subchart, because it is telemetry storage the platform owns end to end. Each service owns its own PostgreSQL database and migrations. The endpoint is shared: an empty per-service host, port or sslMode (and Redis host / port / username / tls) inherits from global.postgresql / global.redis before falling back to the in-cluster Service names. Declare a managed datastore once on the global blocks; add a per-service database: / redis: block only to send one service somewhere else.

In-cluster PostgreSQL (proof of concept)

Leave global.postgresql.deploy: true. A control-plane-postgresql-bootstrap Job creates each service role and database using the password already in that service’s Secret, so you run no SQL by hand. Expect a few restarts on the Postgres-backed workloads while the Job waits for PostgreSQL, then they become Ready.

Managed PostgreSQL and Redis (production)

Name the endpoints once, disable the in-cluster stores you are replacing, and leave ClickHouse alone:
Every service needs its own role and database. Either create them yourself, or let the chart create them — see Let the chart create the roles. The pairs: The trustguard database needs the pgcrypto extension: TrustGuard’s migrations create it and fail without it. The control-plane database uses it when it is available. The owner of a database may create it, since pgcrypto is a trusted extension. On Azure Database for PostgreSQL, first allow-list it in the azure.extensions server parameter.

Let the chart create the roles

With managedBootstrap on, the chart runs a Job after install and after every upgrade that creates any missing role and database in the table above, using the passwords the services read, and creates pgcrypto in each database. Roles and databases that already exist are kept, except that each role’s password is set to the one in its service’s Secret, so the two cannot drift and a password rotated in the Secret reaches the database on the next upgrade. Re-running it is safe, so leave it on. Application tables stay with each service’s own migrations. It logs in with an administrator you name in a Secret. That login needs CREATEROLE and CREATEDB, not superuser:
The administrator’s password stays in that Secret: it never appears in values, manifests or the Job’s logs. The Job needs password authentication; with authMode: iam the roles are principals your cloud tooling creates, and the chart refuses to render with both set. The Job is a Helm post-install and post-upgrade hook, which Argo CD runs as a PostSync hook. Until it finishes, the services restart while they wait for their databases. No datastore password belongs in the values file. Point each service at a Secret you created, including the control-plane role through global.postgresql.passwordSecret — see External per-service datastore credentials. For minimum sizes see Managed stores and values-managed-datastores.yaml.example, which ships with the chart. For RDS, Entra ID, Cloud SQL or AlloyDB IAM authentication instead of passwords, see IAM database authentication. Running ClickHouse outside the cluster is supported but uncommon. Only if your policy requires it, add:

Install

Self-hosted needs no console setup, no config-sync tokens, and no DataAgent enrollment. The platform is its own configuration source. The one credential you get from NeuralTrust is the firewall key, unless the Firewall runs in your cluster.
Upgrading a self-hosted install that runs the Firewall in your cluster? The Firewall is now NeuralTrust-hosted by default. To keep yours, add global.firewall.deploy: true to your values before upgrading. Otherwise ask NeuralTrust for the firewall key and create trustguard-firewall first. With neither, helm upgrade stops with an error that names both options.
1

Create the namespace and image pull secret

Turn the registry key NeuralTrust sent you into the pull Secret every component expects, using the script from the chart sources:
2

Create the bootstrap administrator Secret

There is no hosted console to sign in from and no sign-up flow, so seed the first super-admin. A pre-created Secret keeps the credentials out of Helm release history:
The feature activates only when DEPLOYMENT_MODE=external and both values are non-empty. On password login the console checks these before normal user authentication, and on a match upserts the user with a verified email and grants OWNER on every team.Treat it as a break-glass account: it bypasses the normal user table by design. Create a personal administrator through the UI afterwards.
3

Create the firewall key Secret

TrustGuard calls the NeuralTrust-hosted Firewall with the key NeuralTrust issues for this install. Ask NeuralTrust for it before installing; it is sent to you over a secure channel. It is a FIREWALL_JWT: a per-install client that carries the Firewall URL and can be revoked on its own. The URL decides the region your text is scored in — firewall.neuraltrust.ai (EU) or firewall.us.neuraltrust.ai (US) — so say which one you want when you ask; see Inference plane.
To run the Firewall in your cluster instead, skip this step and set global.firewall.deploy: true in the next one.
4

Write your values file

The chart ships values-external.yaml.example. Copy it and set your platform and domain:
With the defaults above, PostgreSQL and Redis stay in-cluster and need no extra Secrets beyond the pull secret, onprem-superadmin and trustguard-firewall. For the production shape, start from values-managed-datastores.yaml.example and follow Managed PostgreSQL and Redis.
5

Install, and watch the ordering

Two things must complete before the console serves traffic:
  1. A pre-install Helm hook Job generates the MCP OAuth RSA signing key into a Secret. It checks for an existing key first, so upgrades do not rotate it and invalidate live access tokens. It only ever writes its own Secret — the Role is name-scoped.
  2. An init container runs prisma migrate deploy followed by the seed.
The console Deployment rolls with maxUnavailable: 0, so a failed migration blocks the rollout rather than serving against a half-migrated schema. control-plane-api reads the same schema and runs no migrations of its own — it assumes the console has already applied them.The chart registry is public; only the container images are private. Always pass --version so the release is reproducible.
On OpenShift the install is the same but the chart renders native Routes instead of Ingress — see OpenShift. Provider-specific ingress, certificate, and managed-store choices are in Cloud notes.

Verify

You should see the full inventory: the request path (agentgateway-proxy, agentgateway-mcp, trustguard-data-plane, data-plane-api, plus firewall and its workers with global.firewall.deploy: true), the in-cluster control plane (agentgateway-admin, trustguard-control-plane, control-plane-api, control-plane-app), and the analytics stack (clickstack-collector, clickhouse, datacore, alertengine-api, alertengine-worker). No dataagent pod appears. In-cluster control-plane-postgresql and redis appear only while deploy: true. Data-plane readiness has no snapshot gate here, so Running and Ready track each other closely. Point DNS at the ingress address, sign in with the super-admin credentials, and create the organization.

Configuration comes from PostgreSQL

Config sync is off by default in External mode, and each product’s data plane reads configuration from its own database. Practical consequences:
  • There is no config-sync token to create and no snapshot cache to reason about
  • Each product needs its own database and role, not one shared credential
The chart still generates gRPC TLS material for the product control planes: a self-signed CA and a server certificate whose SANs cover the control-plane Service DNS name, preserved across upgrades. Nothing consumes it while config sync is off, but it means you can enable config sync later without provisioning certificates. If your policy requires your own PKI, supply a kubernetes.io/tls Secret including ca.crt through configSync.grpcTls.existingSecret; setting autoGenerate: false without one is rejected at render time. DataCore is reached by the console at DATACORE_URL with a JWT signed by a secret that must equal DataCore’s AUTH_JWT_HS256_SECRET. The chart wires both ends from a single generated value. If you override one by hand you must override the other, or every dashboard returns an authorization error. The checks above confirm the install came up. Before handing it over, work through the validation checklist — it covers what kubectl cannot see: DNS and TLS from the caller’s network, MCP tested separately from the LLM route, policy decisions, backup ownership, and a rehearsed restore.

Telemetry

Product telemetry stays in your in-cluster ClickHouse. To run with no outbound NeuralTrust telemetry — the air-gapped default — disable hosted export:
Disabling hosted export does not disable the in-cluster ClickStack pipeline; it only stops optional egress to NeuralTrust. TrustGuard exports its own health traces and metrics (evaluation latency and errors) to your in-cluster collector by default. TrustGate does the same for request rate, errors and latency once you set global.observability.operationalTelemetry: true, which is off by default. In a self-hosted install, both stay in your environment. See Operational telemetry.

Public routing

AgentGateway exposes three surfaces in External mode: admin, proxy, and MCP. global.domain combines with default prefixes to render hostnames, and the chart can auto-add wildcard hosts (*.llm.<domain> / *.mcp.<domain>) for slug-based discovery. DNS, certificates, and cloud controller settings remain operator prerequisites — see Ingress.

What you have taken on

Worth stating plainly, since it is the real cost of running Self-hosted:
  • Database migrations are yours to run and to roll back
  • Backups of PostgreSQL and ClickHouse are yours
  • Certificate rotation for anything you supplied yourself
  • The bootstrap credential is a standing break-glass path into every team
  • Email deliverability — invitations and password resets stop working silently if it breaks

Known rough edges

Self-hosted is newer than Hybrid, and these are the issues you are most likely to meet. Each has a workaround in Troubleshooting.
  • Login lockout after repeated failed password attempts
  • SCIM setup screens display the SaaS host instead of yours
  • Alert evaluation does not currently run
  • An in-cluster Firewall’s complexity state silently disables itself without a Redis URL
  • Trace export returns 404 when the OTLP endpoint includes a signal path

High availability

The availability ladder is the same for every self-hosted model, so it lives on one page: what each tier survives, the replica and disruption settings the chart does and does not expose, the failure table, and the promotion runbook.

High availability

The four tiers, from one cluster across zones to two active regions, the two invariants, and exactly what you change in the chart.
Four things are specific to Self-hosted.

Configuration lives in PostgreSQL

Self-hosted keeps its entire configuration state in the database rather than pulling it from anywhere, so a second cluster is already looking at the same policies the moment it starts. Nothing pulls configuration from NeuralTrust (the hosted Firewall, if you use it, is stateless and both clusters call it alike), and there is no last-known-good cache to worry about — the trade is that the database is now the thing that must not be lost.

ClickHouse does not follow a promotion

ClickHouse is in-cluster, and therefore per cluster. Each cluster holds only the telemetry its own collector received. After a failover the console works and enforcement is unaffected, but dashboards show the promoted cluster’s history rather than the failed one’s. Either accept that, or configure ClickHouse replication between the two clusters.

Console sessions live in the region that issued them

A promotion signs operators out. They sign in again against the same PostgreSQL and everything is there — but plan for it in the runbook rather than discovering it mid-incident.

Upgrades and migrations with two clusters

Both consoles run prisma migrate deploy in an init container against the same database. Upgrade one cluster at a time, active first, and let its rollout complete before starting the second. A migration is applied once and the second cluster’s init container no-ops, but running both simultaneously against one schema is worth avoiding — and the console rolls with maxUnavailable: 0, so a failed migration blocks that cluster rather than serving a half-migrated schema.

Self-hosted at tier 3

Self-hosted in active/passive across two regions. A traffic manager you operate points the gateway, MCP and console hostnames at the active cluster. Each cluster holds a full copy of every component: the request path, both product control planes, the console and API, its own region-local Redis, and its own in-cluster ClickHouse. Both clusters read and write one shared PostgreSQL primary, which holds configuration, console data, payloads and detections, with a cross-region read replica promoted on failover. Four consequences of a promotion: ClickHouse does not follow it, so each cluster only has the telemetry its own collector received; rate limits are counted per region; console sessions live in the region that issued them; and nothing dials NeuralTrust, because both clusters are self-contained. The NeuralTrust-hosted Firewall does not move on a promotion: both clusters call it over 443. Self-hosted in active/passive across two regions. A traffic manager you operate points the gateway, MCP and console hostnames at the active cluster. Each cluster holds a full copy of every component: the request path, both product control planes, the console and API, its own region-local Redis, and its own in-cluster ClickHouse. Both clusters read and write one shared PostgreSQL primary, which holds configuration, console data, payloads and detections, with a cross-region read replica promoted on failover. Four consequences of a promotion: ClickHouse does not follow it, so each cluster only has the telemetry its own collector received; rate limits are counted per region; console sessions live in the region that issued them; and nothing dials NeuralTrust, because both clusters are self-contained. The NeuralTrust-hosted Firewall does not move on a promotion: both clusters call it over 443.

Next steps

Configuration

Managed stores, ingress, TLS, and every values switch.

Secrets

Per-service datastore credentials and what the chart generates.

Requirements

Dependencies, ports, and capacity.

Cloud notes

Ingress, certificates, and managed stores per provider.

Validation checklist

What to prove before the install counts as done.

Troubleshooting

Login, migration, and telemetry failures.