Helm Chart (Gateway)

Deploy the PraisonAI gateway to Kubernetes with the official Helm chart

Deploy the PraisonAI gateway (WebSocket + REST on port 8765) to Kubernetes with the official Helm chart.

Diagram

Helm Deployment

📦 Helm Chart

🔐 Auth Secret

🚀 Deployment

🌐 Service :8765

🔗 Ingress
WebSocket

Quick Start

  1. Create the auth token Secret

    Pre-create the Secret out-of-band (GitOps-friendly) instead of putting a token in Git.

    bash
    kubectl create secret generic praisonai-gateway-auth \
      --from-literal=GATEWAY_AUTH_TOKEN="$(openssl rand -hex 16)"
  2. Install the chart from a local checkout

    Point the release at the pre-created Secret. The same chart is also installable via praisonai deploy helm --chart gateway (see the Helm CLI Wrapper).

    bash
    helm install praisonai ./src/praisonai-bot/infra/helm/praisonai-gateway \
      --set auth.existingSecret=praisonai-gateway-auth \
      --set image.tag=latest
  3. Verify with a port-forward

    Forward the Service and hit the health endpoint.

    bash
    kubectl port-forward svc/praisonai-praisonai-gateway 8765:8765
    curl http://127.0.0.1:8765/health

How It Works

Helm renders the templates into Kubernetes objects, then the gateway container starts and reads its auth token from the Secret.

Diagram
SecretGateway PodKubernetesHelmSecretGateway PodKubernetesHelm(+ optional Ingress + HPA)Render ServiceAccount + Secret + Deployment + ServiceStart containerpraisonai gateway start –host 0.0.0.0Read GATEWAY_AUTH_TOKEN (secretKeyRef)Token valueListen on :8765GET /health (liveness/readiness)200 OK
ObjectCreatedPurpose
ServiceAccountwhen serviceAccount.create=truePod identity
Secretwhen auth.token is set (no existingSecret)Holds GATEWAY_AUTH_TOKEN
DeploymentalwaysRuns the gateway container on port 8765
ServicealwaysExposes the pod on port 8765
Ingresswhen ingress.enabled=trueWebSocket-aware external access
HPAwhen autoscaling.enabled=trueCPU-based scaling

Configuration Options

Every key below is from src/praisonai-bot/infra/helm/praisonai-gateway/values.yaml.

KeyTypeDefaultDescription
replicaCountint1Gateway replicas. See WebSocket note before scaling beyond 1.
image.repositorystringghcr.io/mervinpraison/praisonaiOfficial GHCR image.
image.tagstring"" (falls back to Chart appVersion)Pin a released tag in production (e.g. "4.6.157").
image.pullPolicystringIfNotPresentStandard Kubernetes image pull policy.
imagePullSecretslist[]Image pull secrets for private registries.
commandlist["praisonai","gateway","start","--host","0.0.0.0"]Container entrypoint.
auth.enabledbooltrueInject GATEWAY_AUTH_TOKEN into the pod.
auth.existingSecretstring""Reference a pre-created Kubernetes Secret (preferred / GitOps-friendly).
auth.secretKeystringGATEWAY_AUTH_TOKENData key inside the Secret whose value becomes the env var. The env var itself is always named GATEWAY_AUTH_TOKEN — this key only selects which entry in the Secret to read.
auth.tokenstring""Inline token; chart creates a Secret for you. Avoid in Git.
envlist[]Extra env vars (e.g. OPENAI_API_KEY via valueFrom.secretKeyRef). See example below.
service.typestringClusterIPKubernetes Service type.
service.portint8765Gateway listen port (also exported to the container as GATEWAY_PORT).
ingress.enabledboolfalseExpose via Ingress with WebSocket annotations.
ingress.classNamestringnginxIngressClass name.
ingress.annotationsmapNGINX WebSocket-friendly (see below)Ingress annotations; adjust for Traefik/other controllers.
ingress.hostslist[{host: agents.example.com, paths: [{path: /, pathType: Prefix}]}]Ingress hosts and paths.
ingress.tlslist[]Ingress TLS blocks.
probes.enabledbooltrueEnable liveness/readiness probes.
probes.pathstring/healthProbe path (must match the gateway’s health endpoint).
resourcesmap{}Kubernetes resource requests/limits.
autoscaling.enabledboolfalseOptional CPU-based HPA. See the WebSocket sticky-sessions warning before enabling.
autoscaling.minReplicasint1HPA minimum replicas.
autoscaling.maxReplicasint3HPA maximum replicas.
autoscaling.targetCPUUtilizationPercentageint80HPA target CPU utilization.
serviceAccount.createbooltrueCreate a dedicated ServiceAccount.
serviceAccount.namestring"" (derived from fullname)Override the ServiceAccount name.
podAnnotationsmap{}Annotations added to each pod.
podSecurityContextmap{}Pod-level securityContext.
securityContextmap{}Container-level securityContext.
nodeSelectormap{}Pod nodeSelector.
tolerationslist[]Pod tolerations.
affinitymap{}Pod affinity.

Default ingress.annotations:

yaml
nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
nginx.ingress.kubernetes.io/proxy-send-timeout: "3600"

Security — Auth Is Fail-Fast by Default

When auth.enabled=true (the default), the chart refuses to render unless a token source is provided.

Without a token source, the render fails:

  • auth.enabled=true only (no ingress):
  • > auth.enabled is true but no auth.existingSecret or auth.token was provided. Set one of them, or disable auth with auth.enabled=false.
  • auth.enabled=true and ingress.enabled=true:
  • > auth.enabled and ingress.enabled are true but no auth.existingSecret or auth.token was provided. Refusing to expose the gateway without a GATEWAY_AUTH_TOKEN.

To run without a token (e.g. local testing behind trusted networking) set auth.enabled=false.

The injected env var is always named GATEWAY_AUTH_TOKEN — that is the only name the gateway reads. auth.secretKey selects which data key in the Secret to read, not the env var name. Renaming auth.secretKey does not rename the env var.


Passing Other Secrets (LLM Keys) via env

Pass provider keys with the valueFrom.secretKeyRef pattern.

yaml
env:
  - name: OPENAI_API_KEY
    valueFrom:
      secretKeyRef:
        name: praisonai-llm
        key: OPENAI_API_KEY

WebSocket Ingress — Sticky Sessions

The gateway is stateful per WebSocket connection, so multi-replica setups need sticky sessions.

The default NGINX annotations set long read/send timeouts. Add a cookie affinity annotation for sticky sessions:

yaml
ingress:
  annotations:
    nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
    nginx.ingress.kubernetes.io/proxy-send-timeout: "3600"
    nginx.ingress.kubernetes.io/affinity: "cookie"

Ingress + TLS Example

Expose the gateway on a real hostname with TLS.

bash
helm install praisonai ./src/praisonai-bot/infra/helm/praisonai-gateway \
  --set auth.existingSecret=praisonai-gateway-auth \
  --set ingress.enabled=true \
  --set ingress.hosts[0].host=agents.example.com \
  --set ingress.hosts[0].paths[0].path=/ \
  --set ingress.hosts[0].paths[0].pathType=Prefix \
  --set ingress.tls[0].secretName=agents-tls \
  --set ingress.tls[0].hosts[0]=agents.example.com

Autoscaling (HPA)

Enable CPU-based scaling with an HPA.

bash
helm install praisonai ./src/praisonai-bot/infra/helm/praisonai-gateway \
  --set auth.existingSecret=praisonai-gateway-auth \
  --set autoscaling.enabled=true \
  --set autoscaling.minReplicas=2 \
  --set autoscaling.maxReplicas=5

Scope


Best Practices

Prefer auth.existingSecret over auth.token

Inline tokens end up in Git. Pre-created Secrets don’t — create the Secret out-of-band and reference it with auth.existingSecret.

Pin image.tag to a released version in production

The default image.tag falls back to Chart appVersion ("latest"), which drifts. Pin a released tag such as "4.6.157" for reproducible deployments.

Keep replicaCount: 1 until sticky sessions are configured

WebSocket state is per-pod. Scale beyond one replica only after enabling sticky sessions or a shared session backend.

Set resources requests/limits

The chart ships resources: {} by default, so the pod has no guaranteed CPU/memory. Set requests and limits — commented-out example values are in values.yaml.


Related