Documentation Index
Fetch the complete documentation index at: https://docs.neuraltrust.ai/llms.txt
Use this file to discover all available pages before exploring further.
This guide walks you end-to-end through a fully self-hosted deployment on any Kubernetes 1.24+ cluster — Control Plane API, UI, and Scheduler run in your cluster alongside the Data Plane, TrustGate, and Firewall.
This is the recommended path for on-prem, bare metal, air-gapped, and sovereign-cloud deployments.
For the SaaS-hosted Control Plane alternative, see Vanilla Kubernetes hybrid.
What you’ll end up with
| Component | Location | Replicas |
|---|
| Control Plane API, UI, Scheduler | Your cluster | 2, 2, 1 |
| Data Plane API, worker, Kafka Connect | Your cluster | 2, 1, 1 |
| TrustGate admin / gateway / actions | Your cluster | 2 each |
| Firewall gateway + 5 workers | Your cluster | 2 + 5 |
| ClickHouse, Kafka, PostgreSQL, Redis | Your cluster (or external) | 1 each |
Sizing baseline: ~21–23 vCPU / 45–50 GiB RAM / 80 GiB PVC. See Image catalog.
Prerequisites
| Resource | Recommended |
|---|
| Kubernetes version | 1.24+ |
| CPU pool | ≥ 5 × (8 vCPU / 32 GiB) for HA. Drop to 4 if Firewall workers run on GPU nodes. |
| GPU pool (optional, for GPU Firewall) | 4 vCPU / 16 GiB + 1 × NVIDIA GPU per node — 5 nodes (one per default Firewall worker) |
| Sizing baseline | ~23.1 vCPU / 61.8 GiB requests / 80 GiB PVC (defaults, CPU Firewall) |
| Storage | Default StorageClass with ReadWriteOnce PVs (SSD-backed recommended for ClickHouse + Postgres) |
| Ingress | NGINX, Traefik, HAProxy, or any conformant controller |
| TLS | cert-manager with Let’s Encrypt or internal CA |
| DNS | A control over a base domain (e.g. platform.example.com) |
| Image pull | gcr-keys.json from NeuralTrust OR a mirrored internal registry for air-gapped |
Step 1 — Cluster prep
Same as hybrid — see Vanilla Kubernetes hybrid › Step 1. Add cluster components:
- Ingress controller (NGINX/Traefik/HAProxy).
- cert-manager (or your own cert workflow).
- Storage class with
ReadWriteOnce.
- (Bare metal) MetalLB or an external LB.
- (GPU Firewall) NVIDIA device plugin.
Step 2 — Namespace and image pull secret
kubectl create namespace neuraltrust
kubectl create secret docker-registry gcr-secret \
--docker-server=europe-west1-docker.pkg.dev \
--docker-username=_json_key \
--docker-password="$(cat path/to/gcr-keys.json)" \
[email protected] \
-n neuraltrust
For air-gapped installs, mirror the chart images first (see Air-gapped).
Step 3 — Write your values overlay
Save as my-values.yaml:
# Self-hosted deployment on vanilla Kubernetes
global:
platform: "kubernetes"
domain: "platform.example.com"
storageClass: "longhorn" # or your cluster default
autoGenerateSecrets: true
# Control Plane in your cluster
neuraltrust-control-plane:
controlPlane:
enabled: true # ← key difference from hybrid
components:
api:
enabled: true
ingress:
enabled: true
className: "nginx"
annotations: &nginx
cert-manager.io/cluster-issuer: "letsencrypt-prod"
nginx.ingress.kubernetes.io/ssl-redirect: "true"
app:
enabled: true
ingress:
enabled: true
className: "nginx"
annotations: *nginx
scheduler:
enabled: true
ingress:
enabled: true
className: "nginx"
annotations: *nginx
infrastructure:
postgresql:
deploy: true
# Data Plane
neuraltrust-data-plane:
dataPlane:
enabled: true
components:
api:
ingress:
enabled: true
className: "nginx"
annotations: *nginx
# TrustGate
trustgate:
enabled: true
global:
env:
SERVER_BASE_DOMAIN: "platform.example.com"
ingress:
controlPlane:
className: "nginx"
annotations: *nginx
dataPlane:
className: "nginx"
annotations: *nginx
actions:
className: "nginx"
annotations: *nginx
# Firewall
neuraltrust-firewall:
firewall:
enabled: true
# Infrastructure
infrastructure:
clickhouse:
deploy: true
persistence:
storageClass: "longhorn"
size: 200Gi
kafka:
deploy: true
Using external infrastructure
neuraltrust-control-plane:
infrastructure:
postgresql:
deploy: false
controlPlane:
components:
postgresql:
secrets:
host: "<external-postgres>"
port: "5432"
user: "neuraltrust"
password: ""
database: "neuraltrust"
infrastructure:
clickhouse:
deploy: false
external:
host: "your-tenant.clickhouse.cloud"
port: "8443"
user: "neuraltrust"
password: ""
database: "neuraltrust"
kafka:
deploy: false
external:
bootstrapServers: "<bootstrap>:9092"
Step 4 — Install
helm upgrade --install neuraltrust-platform \
oci://europe-west1-docker.pkg.dev/neuraltrust-app-prod/helm-charts/neuraltrust-platform \
--version <VERSION> \
--namespace neuraltrust \
-f my-values.yaml
kubectl get pods -n neuraltrust -w
Step 5 — DNS
Get the ingress controller’s external IP / hostname and add A / CNAME records:
| Host | Component |
|---|
app.platform.example.com | Control Plane UI |
api.platform.example.com | Control Plane API |
scheduler.platform.example.com | Control Plane Scheduler |
data-plane-api.platform.example.com | Data Plane API |
admin.platform.example.com | TrustGate admin |
gateway.platform.example.com | TrustGate proxy |
actions.platform.example.com | TrustGate actions |
Step 6 — First login to the Control Plane
kubectl logs -n neuraltrust deploy/control-plane-app -c init-db | grep -i bootstrap
Sign in at https://app.platform.example.com, configure SSO (Platform › SSO), rotate the bootstrap admin password, configure LLM providers and policies.
Step 7 — Send traffic through TrustGate
Point your AI applications at https://gateway.platform.example.com.
Verification
kubectl get pods -n neuraltrust
kubectl get ingress -n neuraltrust -o wide
kubectl get certificate -n neuraltrust
curl https://api.platform.example.com/health
curl https://app.platform.example.com
curl https://data-plane-api.platform.example.com/health
curl https://gateway.platform.example.com/__health
Upgrading
helm upgrade neuraltrust-platform \
oci://europe-west1-docker.pkg.dev/neuraltrust-app-prod/helm-charts/neuraltrust-platform \
--version <NEW_VERSION> \
--namespace neuraltrust \
-f my-values.yaml
Watch the init-db init container on the new CP UI pod for Prisma migration errors.
Air-gapped installs
For fully disconnected clusters:
1. Mirror images
# Get the full image list for your values
helm template neuraltrust-platform \
oci://europe-west1-docker.pkg.dev/neuraltrust-app-prod/helm-charts/neuraltrust-platform \
--version <VERSION> \
-f my-values.yaml \
| yq '.. | select(has("image")) | .image' \
| sort -u
Mirror each image to your internal registry using crane, skopeo, or docker pull/push.
2. Point the chart at your mirror
global:
imageRegistry: "registry.internal.example.com/neuraltrust"
The chart strips the default GCP prefix and prepends yours.
3. Forward proxy (if applicable)
global:
proxy:
enabled: true
httpProxy: "http://proxy.corp.example:3128"
httpsProxy: "http://proxy.corp.example:3128"
noProxy: "localhost,127.0.0.1,.cluster.local,.svc"
4. Internal CA for TLS
Bring your own certificates instead of Let’s Encrypt:
neuraltrust-data-plane:
dataPlane:
components:
api:
ingress:
tls:
secretName: "wildcard-platform-example-com"
Pre-create the Secret containing the CA-signed certificate.
5. Firewall model weights
The Firewall workers fetch models from Hugging Face on first start. For air-gapped:
- Pre-bake models into a custom Firewall image, OR
- Mirror
huggingface.co internally and set the Firewall HUGGINGFACE_HUB_ENDPOINT, OR
- Provide a
HUGGINGFACE_TOKEN and allow egress just to Hugging Face.
See Firewall deployment › Air-gapped for details.
Migration to hybrid
neuraltrust-control-plane:
controlPlane:
enabled: false
Enroll the existing Data Plane with NeuralTrust SaaS — see Vanilla Kubernetes hybrid › Step 6.
Troubleshooting
| Symptom | Likely cause | Fix |
|---|
| CP UI blank | API URL wrong | Verify api.<domain> ingress and config |
| Login fails | DB migration failed | kubectl logs -c init-db on CP UI pod |
| Scheduler not running jobs | Can’t reach Data Plane API | Verify data-plane-api.<domain> and TLS |
PVC stuck Pending | No default storage class | Mark one default and re-apply |
| cert-manager challenge stuck | DNS not resolving or unreachable for HTTP-01 | kubectl describe challenge |
ImagePullBackOff (air-gapped) | Registry mirror missing images | Re-run image mirror; confirm global.imageRegistry |