HelixML

Linux & Kubernetes

Install Helix on a Linux server or Kubernetes cluster.

Install Helix on a Linux server or Kubernetes cluster. Developer license $199/year — no sales call required.

Licensing

A license is required to run Helix on Linux or Kubernetes.

  • Developer license — $199/year: For individuals, testing, and businesses with less than $10M annual revenue or fewer than 250 employees. Buy a developer license →
  • Enterprise license: For larger organizations with full RBAC, SSO, SOC 2 Type II, and dedicated onboarding. Enterprise licensing →

Helix runs on any Kubernetes cluster — whether that's on your own bare metal, a European cloud provider like Hetzner or OVH, or a major cloud platform like AWS (EKS), Google Cloud (GKE), or Azure (AKS). If you can run containers, you can run Helix.

For organisations focused on digital sovereignty, we also offer a turnkey Sovereign Server — a 4U rack server with Helix pre-installed, shipped to your data centre.

Local Setup

To install Helix on your own Linux server with Nvidia/AMD GPU support, run the following command:

curl -sL -O https://get.helixml.tech/install.sh && bash install.sh

Kubernetes Setup

Prerequisites

  • A Kubernetes cluster (1.28+). Managed control planes (AKS/EKS/GKE) are fine; the sandbox chart requires privileged pods, so AKS/EKS/GKE Autopilot is not supported.
  • kubectl and helm 3.x on your workstation.
  • A Helix license key from your account.
  • A StorageClass that supports ReadWriteOnce persistent volumes. The control plane chart provisions several PVCs (main Postgres, pgvector, kodit-vectorchord, controlplane data).
  • For a minimal control-plane-only install, budget ~8 vCPU / 24 GiB RAM of worker capacity. The control plane pod ships with a Haystack sidecar that loads a ~4 GB embedding model on first start.
  • An LLM provider (OpenAI, Anthropic, or a self-hosted helix-runner with GPUs). Without one, there will be no models available after first login.

Cloud quotas

On a fresh Azure/AWS/GCP subscription, most GPU SKU families have quota 0 by default. Before starting:

  • AWS: g5/p4d EC2 quotas per region.
  • Azure: NVadsV710v5 (AMD V710) or NC*/ND* (NVIDIA) families, plus "Total Regional vCPUs".
  • GCP: nvidia-* GPU quotas per region.

Create secrets

Replace <paste-your-license-key> with the key from your account. Generate real random values for the postgres password and runner token; the example values below are placeholders.

# Create namespace and secrets
kubectl create namespace helix
kubectl config set-context --current --namespace=helix
 
# Use a random value here. This is the Postgres admin password.
kubectl create secret generic postgresql-auth-secret \
  --from-literal=postgres-password="$(openssl rand -hex 16)" \
  --from-literal=username="helix" \
  --from-literal=password="" \
  --from-literal=database="helix"
 
kubectl create secret generic pgvector-auth-secret \
  --from-literal=username="postgres" \
  --from-literal=password="" \
  --from-literal=database="postgres"
 
kubectl create secret generic helix-pgvector-creds \
  --from-literal=dsn="postgresql://postgres:@my-helix-controlplane-pgvector:5432/postgres"
 
kubectl create secret generic helix-license \
  --from-literal=license-key="<paste-your-license-key>"
 
# Random token, used by sandbox/runner charts to auth back to the control plane
kubectl create secret generic helix-runner-secrets \
  --from-literal=api-token="$(openssl rand -hex 32)"

Configure values.yaml

Save this as values.yaml for the chart:

# Production-ready configuration for helix-controlplane
# For more options: https://github.com/helixml/helix/blob/main/charts/helix-controlplane/values-example.yaml
 
global:
  # Public URL of your Helix deployment. Used for OAuth redirects, email
  # links, and agent callbacks. If you are behind an ingress + TLS, set
  # this to your real hostname (e.g. https://helix.example.com).
  # For kubectl port-forward, the default below is fine.
  serverUrl: http://localhost:8080
 
image:
  tag: ""
 
searxng:
  enabled: true
 
chrome:
  enabled: true
 
pgvector:
  enabled: true
  auth:
    existingSecret: "pgvector-auth-secret"
    usernameKey: "username"
    passwordKey: "password"
    databaseKey: "database"
  persistence:
    enabled: true
    size: 50Gi
    storageClass: ""
    annotations: {}
    accessModes:
      - ReadWriteOnce
 
controlplane:
  licenseKeyExistingSecret: "helix-license"
  licenseKeyExistingSecretKey: "license-key"
 
  runnerTokenExistingSecret: "helix-runner-secrets"
  runnerTokenExistingSecretKey: "api-token"
 
  admin:
    userSource: "env"
    userIds: "all"
 
  haystack:
    enabled: true
    existingSecret: "helix-pgvector-creds"
    existingSecretDsnKey: "dsn"
    embeddingsModel: "MrLight/dse-qwen2-2b-mrl-v1"
    embeddingsDim: "1536"
    chunkSize: "1000"
    chunkOverlap: "50"
    chunkUnit: "word"
 
  rag:
    defaultProvider: "haystack"
    embeddingsProvider: "helix"
 
  inference:
    defaultProvider: "helix"
 
  fineTuning:
    defaultProvider: "helix"
 
  # Configure at least one LLM provider. Without this, there will be
  # no models available after first login. Provide an API key inline,
  # or reference a Kubernetes secret via controlplane.providers.<name>.apiKeyExistingSecret.
  # providers:
  #   anthropic:
  #     apiKey: "sk-ant-..."
  #   openai:
  #     apiKey: "sk-..."
 
persistence:
  enabled: true
  size: 100Gi
  storageClass: ""
  accessModes:
    - ReadWriteOnce
 
volumes:
  - name: data
 
postgresql:
  enabled: true
  auth:
    existingSecret: "postgresql-auth-secret"
    postgresPasswordKey: "postgres-password"
    usernameKey: "username"
    passwordKey: "password"
    databaseKey: "database"
  architecture: standalone
 
tika:
  enabled: false
 
typesense:
  enabled: false

External Postgres

The chart can use an existing managed Postgres instead of the bundled one, but the bundled pgvector sidecar requires the vectorchord and vectorchord-bm25 extensions. Managed services that ship stock Postgres (Azure Flexible Server, AWS RDS, Cloud SQL) do not include these extensions out of the box, so keep pgvector.enabled: true. That pod will host the RAG vector index independently of wherever your main Postgres lives.

Install the control plane

# Add Helix Helm repository
helm repo add helix https://charts.helixml.tech
helm repo update
 
# Install the control plane with your generated values.yaml and secrets
export HELIX_VERSION="latest"
helm upgrade --install my-helix-controlplane helix/helix-controlplane \
  -f values.yaml \
  --set image.tag="${HELIX_VERSION}"

First boot pulls the embedding model (~4 GB) into the Haystack sidecar; budget 5 to 10 minutes before the main pod becomes Ready.

Install the runner (optional, GPU inference)

Skip this section if you're using OpenAI/Anthropic/another hosted LLM provider configured via controlplane.providers.

The runner image tag has a GPU-class suffix:

  • -small (single consumer GPU: T4, L4, A10, RTX 4090)
  • -large (larger GPU: A100/H100)
export HELIX_VERSION="latest"
helm upgrade --install my-helix-runner helix/helix-runner \
  --set runner.host="http://my-helix-controlplane:8080" \
  --set runner.tokenExistingSecret="helix-runner-secrets" \
  --set runner.tokenExistingSecretKey="api-token" \
  --set replicaCount=1 \
  --set image.tag="${HELIX_VERSION}-small"

Install the sandbox chart (cloud desktops / Zed agent)

The helix-sandbox chart powers Helix's cloud desktop and in-browser Zed IDE features. It is optional; install it only if you want to run spec tasks or open the IDE in the browser.

The sandbox runs a Docker-in-Docker daemon which needs privileged pods, a GPU node pool (for desktop rendering), and large persistent volumes.

helm upgrade --install my-helix-sandbox helix/helix-sandbox \
  --namespace helix \
  --set image.tag="${HELIX_VERSION}" \
  --set sandbox.apiUrl="http://my-helix-controlplane.helix.svc.cluster.local" \
  --set sandbox.runnerTokenExistingSecret=helix-runner-secrets \
  --set sandbox.runnerTokenExistingSecretKey=api-token

Per-cloud override values are shipped with the chart: values-aks.yaml, values-eks.yaml, values-gke.yaml, values-bare-metal.yaml.

Access the control plane

kubectl port-forward -n helix svc/my-helix-controlplane 8080:80

Then open http://localhost:8080. The first registered user becomes an admin (because of controlplane.admin.userIds: "all").

For a production deployment you should configure an ingress with TLS termination and set global.serverUrl to the public URL. See the values-example.yaml for nginx + cert-manager, GKE managed-certificate, and cert-manager + DNS-01 examples.

AKS-specific notes (AMD V710)

If you're running the sandbox chart on Azure AKS with the AMD Radeon Pro V710 (Standard_NV8ads_V710_v5), four things trip up first-time deployments:

  1. Pass --gpu-driver none when adding the GPU node pool. AKS otherwise tries to install NVIDIA drivers on an AMD card:

    az aks nodepool add \
      --resource-group $RG --cluster-name $AKS --name gpupool \
      --node-count 1 --node-vm-size Standard_NV8ads_V710_v5 \
      --labels gpu=amd gpu-type=v710 \
      --node-taints "amd.com/gpu=present:NoSchedule" \
      --os-sku Ubuntu --gpu-driver none
  2. Install amdgpu-dkms on the GPU node. Stock AKS Ubuntu 22.04 (kernel 5.15) does not ship the amdgpu module for V710. Without it, /dev/dri is absent inside pods and the desktop container silently fails to render. Install via a one-shot privileged pod with nsenter into the host namespace; see charts/helix-sandbox/values-aks.yaml for the complete recipe.

  3. Disable exec probes on the sandbox pod. AKS's cgroup v2 layout conflicts with Docker-in-Docker's cgroup manipulation and makes kubectl exec (and exec-based liveness/readiness probes) fail inside the sandbox. Set probes.liveness.enabled=false and probes.readiness.enabled=false on the sandbox chart.

  4. V710 is a visualization GPU, not a ROCm compute GPU. It exposes /dev/dri but no /dev/kfd, so the ROCm device plugin won't advertise amd.com/gpu. Set gpu.amd.resourceName="" on the sandbox chart so it doesn't request that resource; the privileged pod already has direct /dev/dri access.

All four are covered by the shipped values-aks.yaml.