{
  "id": "install",
  "title": "Install Context Retriever",
  "url": "https://redis.io/docs/latest/develop/ai/context-engine/context-retriever/install/",
  "summary": "Install and run Redis Context Retriever on a self-managed Kubernetes cluster using Helm.",
  "tags": [
    "docs",
    "develop",
    "ai"
  ],
  "last_updated": "2026-07-17T17:01:49-05:00",
  "children": [],
  "page_type": "content",
  "content_hash": "3a44af0178d5ac200dc4e8579918856725695a7e5e0843ddd86d5386cb3d0f9a",
  "sections": [
    {
      "id": "overview",
      "title": "Overview",
      "role": "overview",
      "text": "Context Retriever is distributed as container images on Docker Hub plus a Helm chart shipped in the Redis Enterprise Helm repository. Installation pulls the images from Docker Hub (or your own mirror) and deploys the chart against a Redis database you provide.\n\n\nThis guide is for system administrators deploying Context Retriever on a self-managed Kubernetes cluster."
    },
    {
      "id": "what-you-need",
      "title": "What you need",
      "role": "content",
      "text": "| Item | Where it comes from |\n| ---- | ------------------- |\n| Container images | Docker Hub: `redislabs/context-retriever` (MCP) and `redislabs/context-retriever-admin` (Admin) |\n| Helm chart | `redis-context-retriever` chart in the Redis Enterprise Helm repository (`ai/charts/redis-context-retriever`) |\n| Redis database | **You provide it** — see prerequisites below |\n| License key | Contact your Redis representative or [contact sales](https://redis.io/contact/). The key starts with `CS-LICENSE.` |"
    },
    {
      "id": "prerequisites",
      "title": "Prerequisites",
      "role": "content",
      "text": ""
    },
    {
      "id": "required-software",
      "title": "Required software",
      "role": "content",
      "text": "| Software | Minimum version | Purpose |\n| -------- | --------------- | ------- |\n| Kubernetes | 1.28+ | Orchestration |\n| kubectl | 1.28+ | Kubernetes CLI |\n| Helm | 3.x | Package manager |"
    },
    {
      "id": "redis-database-bring-your-own",
      "title": "Redis database (bring your own)",
      "role": "content",
      "text": "Context Retriever connects to a Redis database that you provide; it does not ship one. The database must have the Search and JSON capabilities enabled (RediSearch and RedisJSON)."
    },
    {
      "id": "network-access",
      "title": "Network access",
      "role": "content",
      "text": "- **Connected install:** the cluster must be able to pull from `docker.io`.\n- **Air-gapped install:** mirror the two images into your internal registry first — see [Air-Gapped Installation](#air-gapped-installation)."
    },
    {
      "id": "system-requirements",
      "title": "System requirements",
      "role": "content",
      "text": "| Component | CPU | Memory |\n| --------- | --- | ------ |\n| Admin Server | 250m – 1 core | 256Mi – 1Gi |\n| MCP Server | 250m – 1 core | 256Mi – 1Gi |"
    },
    {
      "id": "installation",
      "title": "Installation",
      "role": "setup",
      "text": ""
    },
    {
      "id": "add-the-helm-repository",
      "title": "Add the Helm repository",
      "role": "content",
      "text": "Add the Redis Enterprise Helm repository (the same source as the other Redis Enterprise AI charts) and list the available chart versions:\n\n[code example]\n\nSet the version you want to install:\n\n[code example]"
    },
    {
      "id": "create-a-namespace",
      "title": "Create a namespace",
      "role": "content",
      "text": "[code example]"
    },
    {
      "id": "create-secrets",
      "title": "Create secrets",
      "role": "content",
      "text": "#### Admin database secret\n\n[code example]\n\n#### License key secret\n\n[code example]"
    },
    {
      "id": "install-the-chart",
      "title": "Install the chart",
      "role": "setup",
      "text": "Install the chart, pointing it at your Redis database with `--set redis.addr` — **this is required; the chart will not render without it.**\n\n[code example]\n\nThe chart's image repositories default to `redislabs/context-retriever-admin` and `redislabs/context-retriever`; the images are pulled from Docker Hub."
    },
    {
      "id": "retrieve-the-admin-api-key",
      "title": "Retrieve the admin API key",
      "role": "content",
      "text": "On first startup an admin API key is generated and written to a file in the admin pod:\n\n[code example]\n\n\nSave this key immediately. It is only available on first startup and cannot be recovered if lost (see [Troubleshooting](#lost-admin-api-key))."
    },
    {
      "id": "install-the-cli-optional",
      "title": "Install the CLI (optional)",
      "role": "setup",
      "text": "The CLI ships on PyPI:\n\n[code example]"
    },
    {
      "id": "verify",
      "title": "Verify",
      "role": "content",
      "text": "Check that both services are healthy:\n\n[code example]\n\nIf you installed the CLI, you can also list the configured surfaces:\n\n[code example]"
    },
    {
      "id": "air-gapped-installation",
      "title": "Air-Gapped Installation",
      "role": "content",
      "text": "Context Retriever supports air-gapped clusters by mirroring the published images into your own OCI registry and installing from a locally downloaded copy of the Helm chart — there is no separate air-gapped bundle.\n\nMirror the images and download the chart (steps 1 and 2) on a host with internet access, then transfer them into your air-gapped environment before installing (step 3).\n\n\nThese commands assume the image tag matches the chart version (`$CR_VERSION`). If the images use a different tag, check the chart defaults with `helm show values redis-ai/redis-context-retriever` and set `admin.image.tag` and `mcp.image.tag` accordingly.\n\n\n1. Mirror both images to your internal registry:\n\n   [code example]\n\n2. Download and unpack the Helm chart for the version you are installing:\n\n   [code example]\n\n3. In the air-gapped environment, create an image pull secret for your registry and install from the local chart directory, pointing the image repositories at your registry:\n\n   [code example]\n\n\nIf your registry allows unauthenticated pulls, skip creating `regcred` and remove the `--set 'imagePullSecrets[0].name=regcred'` line from the command above.\n\n\nYour Redis database is separate and must likewise be reachable from the air-gapped cluster."
    },
    {
      "id": "production-notes",
      "title": "Production notes",
      "role": "content",
      "text": "| Area | Recommendation |\n| ---- | -------------- |\n| Redis | Use a highly available Redis database. Set `redis.addr` to its endpoint, and `redis.tlsEnabled=true` if it terminates TLS. |\n| Replicas | Run more than one replica of each service: `--set admin.replicaCount=2 --set mcp.replicaCount=2`. |\n| Encryption key | Store `SECRET_ENCRYPTION_KEY` securely. It is required to decrypt stored credentials and has no recovery path. |"
    },
    {
      "id": "trust-a-custom-redis-ca-certificate",
      "title": "Trust a custom Redis CA certificate",
      "role": "content",
      "text": "If your Redis presents a TLS certificate signed by a private or self-signed certificate authority (CA) — common with Redis Enterprise — Context Retriever must trust that CA, or the connection fails certificate verification. Use `redis.tlsCA.existingSecrets` to mount one or more CA certificates; the chart adds them to the system trust store of both the Admin and MCP services, so they are trusted automatically with no application configuration. The image's built-in public CA bundle stays trusted — your CAs are added on top.\n\n\nThis requires `redis.tlsEnabled: true`, and each CA Secret must already exist in the release namespace before you install or upgrade."
    },
    {
      "id": "create-a-secret-with-the-ca-certificate",
      "title": "Create a Secret with the CA certificate",
      "role": "content",
      "text": "[code example]\n\nThe Secret key is the file's basename, so `--from-file=ca.crt=...` produces the key `ca.crt`. If you use a different key (for example, `--from-file=root.pem=...`), set `key` accordingly in the values below."
    },
    {
      "id": "reference-the-secret-in-your-values",
      "title": "Reference the Secret in your values",
      "role": "related",
      "text": "[code example]"
    },
    {
      "id": "values",
      "title": "Values",
      "role": "content",
      "text": "| Key | Default | Description |\n| --- | --- | --- |\n| `redis.tlsCA.existingSecrets` | `[]` | CA certificates to trust for Redis TLS. Empty mounts nothing (the default). |\n| `redis.tlsCA.existingSecrets[].secretName` | — | **Required.** Name of a pre-created Secret holding the CA certificate in PEM format. |\n| `redis.tlsCA.existingSecrets[].key` | `ca.crt` | Key within the Secret whose value is the PEM certificate. |\n\nCertificates are mounted read-only and picked up automatically; the default empty list mounts nothing, so existing installs are unaffected. This affects only Context Retriever's own connection to Redis."
    },
    {
      "id": "configuration-reference",
      "title": "Configuration reference",
      "role": "configuration",
      "text": ""
    },
    {
      "id": "environment-variables-set-by-the-chart",
      "title": "Environment variables (set by the chart)",
      "role": "content",
      "text": "| Variable | Description | Required |\n| -------- | ----------- | -------- |\n| `AUTH_MODE` | `local` for self-managed (API-key auth only) | Yes |\n| `REDIS_ADDR` | Redis database endpoint | Yes |\n| `REDIS_USERNAME` | Redis ACL username (Redis 6+). Omit to authenticate as the default user. | No |\n| `REDIS_PASSWORD` | Redis password | If your DB requires auth |\n| `SECRET_ENCRYPTION_KEY` | AES-256 key (base64) for stored secrets | Yes |\n| `LICENSE_KEY` | License key string (`CS-LICENSE...`) | Yes |\n| `LOG_LEVEL` | `debug`, `info`, `warn`, `error` | No |"
    },
    {
      "id": "key-helm-values",
      "title": "Key Helm values",
      "role": "content",
      "text": "[code example]"
    },
    {
      "id": "troubleshooting",
      "title": "Troubleshooting",
      "role": "errors",
      "text": ""
    },
    {
      "id": "pod-not-starting",
      "title": "Pod not starting",
      "role": "content",
      "text": "[code example]\n\nCommon causes: license secret missing/invalid; Redis unreachable or missing the Search/JSON capabilities; `SECRET_ENCRYPTION_KEY` not set; `redis.addr` not provided (the chart fails to render with a clear error if it is empty)."
    },
    {
      "id": "license-validation-failed",
      "title": "License validation failed",
      "role": "content",
      "text": "[code example]"
    },
    {
      "id": "lost-admin-api-key",
      "title": "Lost admin API key",
      "role": "content",
      "text": "There is no recovery mechanism by design.\n\n\nIf the key is lost and the pod has restarted, wipe and reinstall:\n\n[code example]"
    },
    {
      "id": "cleanup",
      "title": "Cleanup",
      "role": "content",
      "text": "[code example]"
    },
    {
      "id": "support",
      "title": "Support",
      "role": "compatibility",
      "text": "Contact Redis support with your license ID, the release version, `kubectl version`, and sanitized diagnostic logs:\n\n[code example]"
    }
  ],
  "examples": [
    {
      "id": "add-the-helm-repository-ex0",
      "language": "bash",
      "code": "helm repo add redis-ai https://helm.redis.io/ai\nhelm repo update redis-ai\nhelm search repo redis-ai/redis-context-retriever --versions",
      "section_id": "add-the-helm-repository"
    },
    {
      "id": "add-the-helm-repository-ex1",
      "language": "bash",
      "code": "export CR_VERSION=\"<version-from-the-helm-search-output>\"",
      "section_id": "add-the-helm-repository"
    },
    {
      "id": "create-a-namespace-ex0",
      "language": "bash",
      "code": "export NS=context-retriever\nkubectl create namespace $NS",
      "section_id": "create-a-namespace"
    },
    {
      "id": "create-secrets-ex0",
      "language": "bash",
      "code": "# SECRET_ENCRYPTION_KEY encrypts stored credentials at rest. It must be a\n# base64-encoded 32-byte (AES-256) key. Generate one and back it up — if lost,\n# encrypted data cannot be recovered.\nSECRET_ENCRYPTION_KEY=$(openssl rand -base64 32)\nADMIN_REDIS_PASSWORD=\"<the password of the default user for the admin database>\"\n\nkubectl create secret generic cr-config \\\n  --namespace $NS \\\n  --from-literal=REDIS_PASSWORD=\"$ADMIN_REDIS_PASSWORD\" \\\n  --from-literal=SECRET_ENCRYPTION_KEY=\"$SECRET_ENCRYPTION_KEY\"",
      "section_id": "create-secrets"
    },
    {
      "id": "create-secrets-ex1",
      "language": "bash",
      "code": "export LICENSE_KEY_FILE_PATH=\"<the path to your license key>\"\n\n# License key from Redis (starts with CS-LICENSE.)\nkubectl create secret generic cr-license \\\n  --namespace $NS \\\n  --from-file=LICENSE_KEY=\"$LICENSE_KEY_FILE_PATH\"",
      "section_id": "create-secrets"
    },
    {
      "id": "install-the-chart-ex0",
      "language": "bash",
      "code": "helm install cr redis-ai/redis-context-retriever \\\n  --version $CR_VERSION \\\n  --namespace $NS \\\n  --set redis.addr=\"<your-redis-host>:<port>\" \\\n  --set secrets.existingSecret=cr-config \\\n  --set license.existingSecret=cr-license\n\nkubectl wait --for=condition=ready pod \\\n  -l app.kubernetes.io/name=redis-context-retriever \\\n  -n $NS \\\n  --timeout=180s",
      "section_id": "install-the-chart"
    },
    {
      "id": "retrieve-the-admin-api-key-ex0",
      "language": "bash",
      "code": "ADMIN_POD=$(kubectl get pods -n $NS \\\n  -l app.kubernetes.io/component=admin \\\n  -o jsonpath='{.items[0].metadata.name}')\n\nkubectl exec -n $NS \"$ADMIN_POD\" -- cat /opt/initialAdminKey.txt",
      "section_id": "retrieve-the-admin-api-key"
    },
    {
      "id": "install-the-cli-optional-ex0",
      "language": "bash",
      "code": "pip install redis-context-retriever\n\nctxctl config set default_output_format table --profile onprem\nexport CTX_PROFILE=onprem\n\nctxctl config set api_url \"<admin_service_ingress_url>\"\nctxctl config set mcp_url \"<mcp_service_ingress_url>\"",
      "section_id": "install-the-cli-optional"
    },
    {
      "id": "verify-ex0",
      "language": "bash",
      "code": "curl -sf http://<admin_service_ingress_url>/health | jq\ncurl -sf http://<mcp_service_ingress_url>/health | jq",
      "section_id": "verify"
    },
    {
      "id": "verify-ex1",
      "language": "bash",
      "code": "ctxctl surface list",
      "section_id": "verify"
    },
    {
      "id": "air-gapped-installation-ex0",
      "language": "bash",
      "code": "for img in context-retriever context-retriever-admin; do\n     docker pull \"redislabs/${img}:${CR_VERSION}\"\n     docker tag  \"redislabs/${img}:${CR_VERSION}\" \"registry.internal.example.com/${img}:${CR_VERSION}\"\n     docker push \"registry.internal.example.com/${img}:${CR_VERSION}\"\n   done",
      "section_id": "air-gapped-installation"
    },
    {
      "id": "air-gapped-installation-ex1",
      "language": "bash",
      "code": "helm repo add redis-ai https://helm.redis.io/ai\n   helm repo update redis-ai\n   helm pull redis-ai/redis-context-retriever --version \"$CR_VERSION\" --untar\n   # unpacks to ./redis-context-retriever/",
      "section_id": "air-gapped-installation"
    },
    {
      "id": "air-gapped-installation-ex2",
      "language": "bash",
      "code": "kubectl create secret docker-registry regcred \\\n     --namespace $NS \\\n     --docker-server=registry.internal.example.com \\\n     --docker-username=\"<user>\" --docker-password=\"<pass>\"\n\n   helm install cr ./redis-context-retriever \\\n     --namespace $NS \\\n     --set redis.addr=\"<your-redis-host>:<port>\" \\\n     --set secrets.existingSecret=cr-config \\\n     --set license.existingSecret=cr-license \\\n     --set admin.image.repository=registry.internal.example.com/context-retriever-admin \\\n     --set mcp.image.repository=registry.internal.example.com/context-retriever \\\n     --set admin.image.tag=\"${CR_VERSION}\" \\\n     --set mcp.image.tag=\"${CR_VERSION}\" \\\n     --set 'imagePullSecrets[0].name=regcred'",
      "section_id": "air-gapped-installation"
    },
    {
      "id": "create-a-secret-with-the-ca-certificate-ex0",
      "language": "bash",
      "code": "kubectl create secret generic my-redis-ca \\\n  --from-file=ca.crt=/path/to/redis-ca.pem \\\n  --namespace $NS",
      "section_id": "create-a-secret-with-the-ca-certificate"
    },
    {
      "id": "reference-the-secret-in-your-values-ex0",
      "language": "yaml",
      "code": "redis:\n  tlsEnabled: true\n  tlsCA:\n    existingSecrets:\n      - secretName: my-redis-ca          # key defaults to \"ca.crt\"\n      - secretName: another-redis-ca     # list as many CAs as you need\n        key: tls.crt                     # override when the Secret uses another key",
      "section_id": "reference-the-secret-in-your-values"
    },
    {
      "id": "key-helm-values-ex0",
      "language": "yaml",
      "code": "## the defaults are commented\n# authMode: local\n#\n# admin:\n#   replicaCount: 1\n#   image:\n#     repository: redislabs/context-retriever-admin\n#     tag: '' # set to the release version\n#   service: { type: NodePort, port: 8080, nodePort: 30080 }\n#\n# mcp:\n#   replicaCount: 1\n#   image:\n#     repository: redislabs/context-retriever\n#     tag: '' # set to the release version\n#   service: { type: NodePort, port: 8081, nodePort: 30081 }\n\nredis:\n  addr: '<admin db address>'\n  # username: ''      # optional Redis ACL username (Redis 6+); omit to use the default user\n  tlsEnabled: false\n\nsecrets:\n  existingSecret: cr-config\n\nlicense:\n  existingSecret: cr-license\n\n# imagePullSecrets: [] # set for a private/mirror registry",
      "section_id": "key-helm-values"
    },
    {
      "id": "pod-not-starting-ex0",
      "language": "bash",
      "code": "kubectl describe pod -n $NS -l app.kubernetes.io/component=admin\nkubectl logs -n $NS -l app.kubernetes.io/component=admin",
      "section_id": "pod-not-starting"
    },
    {
      "id": "license-validation-failed-ex0",
      "language": "bash",
      "code": "kubectl get secret cr-license -n $NS\nkubectl logs -n $NS -l app.kubernetes.io/component=admin | grep -i license",
      "section_id": "license-validation-failed"
    },
    {
      "id": "lost-admin-api-key-ex0",
      "language": "bash",
      "code": "kubectl delete namespace $NS\n# then reinstall from the beginning and save the new key",
      "section_id": "lost-admin-api-key"
    },
    {
      "id": "cleanup-ex0",
      "language": "bash",
      "code": "helm uninstall cr -n $NS\nkubectl delete namespace $NS",
      "section_id": "cleanup"
    },
    {
      "id": "support-ex0",
      "language": "bash",
      "code": "kubectl get pods -n $NS\nkubectl logs -n $NS -l app.kubernetes.io/component=admin --tail=100\ncurl -s http://<admin-host>:8080/health | jq '.license'",
      "section_id": "support"
    }
  ]
}
