{
  "schema_version": 2,
  "id": "operate/iris/lens/self-managed/configuration",
  "title": "Configure self-managed Lens",
  "url": "https://redis.io/docs/latest/operate/iris/lens/self-managed/configuration/",
  "summary": "Set the Helm values, storage Secret, retention, ingest, Identity Service connection, and TLS trust for Lens.",
  "tags": [
    "docs",
    "operate",
    "iris"
  ],
  "last_updated": "2026-11-04T01:09:56+02:00",
  "page_type": "content",
  "content_hash": "b84e58fb6e4908dce07fffe4457489ad829a981fff364a673ecfb8b1dc6f703f",
  "sections": [
    {
      "id": "overview",
      "title": "Overview",
      "role": "overview",
      "text": "You configure self-managed Lens with a Helm values file and the Secrets it references. The values file sets your tenant, instance, retention, and the Identity Service connection. The Secrets hold what shouldn't be in a values file: Redis URLs, tokens, and the license."
    },
    {
      "id": "helm-values",
      "title": "Helm values",
      "role": "content",
      "text": "This values file is the starting point for [Deploy](https://redis.io/docs/latest/operate/iris/lens/self-managed/deploy). It assumes an Identity Service release named `ids` in the same namespace. Save it as `lens-values.yaml`:\n\n[code example]\n\n| Value | Default | Purpose |\n| --- | --- | --- |\n| `tenantId` | `\"\"` | Required. The tenant the instance belongs to. Must equal the Identity Service's `runtime.apiKeyTenant.singleTenantID`. |\n| `instance.id` | `default` | The one Lens instance this installation serves. Developers use it as their instance ID. |\n| `instance.retention.streamTrim` | `24h` | Recorded on the instance. See [Retention](#retention). |\n| `instance.retention.contentTTL` | `168h` | How long Lens keeps captured content. |\n| `instance.retention.indexRetention` | `720h` | How long Lens keeps turn structure, timing, scores, and outcomes. |\n| `ingest.enabled` | `false` | Accept turns. See [Ingest](#ingest). |\n| `ingest.region` | `onprem` | Scopes the stream keys. Use one value per installation. |\n| `storage.existingSecret` | `\"\"` | Required. The [storage Secret](#storage-secret). |\n| `storage.keyPrefix` | `iris:lens` | The prefix of every key Lens writes. |\n| `license.existingSecret` | `\"\"` | Required. The license Secret, with the key `license`. |\n| `dataplane.image.repository`, `dataplane.image.tag` | `redislabs/iris-lens-data`, the chart version | The data-plane and worker image. |\n| `controlplane.image.repository`, `controlplane.image.tag` | `redislabs/iris-lens-control`, the chart version | The control-plane image. |\n| `dataplane.identityServiceBaseURL` | `\"\"` | Required. The Identity Service release's URL. Must be `https://` unless `identityService.allowInsecureTransport=true`. |\n| `identityService.allowInsecureTransport` | `false` | Accept an `http://` Identity Service URL, such as the in-cluster Service. |\n| `identityService.credential.existingSecret` | `\"\"` | Required. The data plane's runtime credential, key `token`. |\n| `controlplane.internalToken.existingSecret` | `\"\"` | The control plane's internal token, key `token`. Set it, because the Identity Service release must mount the same Secret. |\n| `controlplane.adminToken.existingSecret` | `\"\"` | Supply your own admin token. Empty, the chart generates one. |\n| `dataplane.server.replicaCount`, `dataplane.worker.replicaCount`, `controlplane.replicaCount` | `1` | Replicas for each workload. |\n| `podDisruptionBudget.enabled` | `false` | Add a PodDisruptionBudget (`maxUnavailable: 1`) for each Deployment with more than one replica. |\n| `dataplane.server.strategy` | `{}` | The data-plane Deployment's `spec.strategy`, rendered as given. |\n| `tls.caCertSecret` | `\"\"` | A certificate authority (CA) bundle every workload trusts. See [TLS trust](#tls-trust). |\n| `security.profile` | `\"\"` | `fips` runs the Federal Information Processing Standards (FIPS) profile. |\n| `imagePullSecrets` | `[]` | Pull Secrets for a private registry. |\n| `tests.enabled` | `false` | Add `helm test` readiness checks. |\n\nTo pull images from a mirror, set each `repository` to your registry. Keep each `tag` at the chart's version.\n\nEvery Secret value also has an `existingSecretChecksum`. Set it when you change the Secret's content, so the pods roll. See [Rotate credentials](https://redis.io/docs/latest/operate/iris/lens/self-managed/authentication#rotate-credentials)."
    },
    {
      "id": "storage-secret",
      "title": "Storage Secret",
      "role": "content",
      "text": "The storage Secret holds one configuration file per process. Each key is a file name:\n\n| Key | Process | Holds |\n| --- | --- | --- |\n| `lens-dataplane-storage.yaml` | Data plane and worker | `storage.streams`, `storage.index`, `storage.content`, and `storage.metadata` URLs. |\n| `lens-controlplane-storage.yaml` | Control plane | `storage.metadata` URLs, and optional `dram.urls`. |\n\nSave the data-plane file as `lens-dataplane-storage.yaml`. Here `streams` and `index` share the records database:\n\n[code example]\n\nSave the control-plane file as `lens-controlplane-storage.yaml`:\n\n[code example]\n\nUse the same `metadata` URL in both files. See [Redis databases](https://redis.io/docs/latest/operate/iris/lens/self-managed/prerequisites#redis-databases) for what each role needs."
    },
    {
      "id": "retention",
      "title": "Retention",
      "role": "content",
      "text": "Lens keeps turn structure, timing, scores, and outcomes for `instance.retention.indexRetention`, and captured content for `instance.retention.contentTTL`. The read API offers time ranges that fit these windows. The windows must satisfy `streamTrim` < `contentTTL` ≤ `indexRetention`.\n\nThe control plane records these values on the instance at its first start. The data plane stamps each content expiry from `contentTTL` as rendered by Helm. To change retention after install, see [Change retention](https://redis.io/docs/latest/operate/iris/lens/self-managed/operations#change-retention).\n\nNothing trims the span streams yet, whatever `streamTrim` is set to."
    },
    {
      "id": "ingest",
      "title": "Ingest",
      "role": "content",
      "text": "With `ingest.enabled=false`, the default, the data plane answers `POST /iris/data/v1beta1/lens/v1/traces` with `503`, and the read API still works. Set `ingest.enabled=true` when you're ready for agents to send turns, and watch the records database's memory from then on."
    },
    {
      "id": "tls-trust",
      "title": "TLS trust",
      "role": "content",
      "text": "No Lens workload terminates TLS. To use an `https://` Identity Service URL, put a TLS-terminating proxy, gateway, or service mesh in front of the Identity Service.\n\nWhen a certificate, for the Identity Service or a `rediss://` database, is signed by a private CA, create a Secret that holds the CA bundle and set `tls.caCertSecret` to its name. Every workload mounts it at `/etc/ssl/custom` and trusts it in addition to the image's system CAs. Set `tls.caCertSecretChecksum` to roll the workloads when the bundle changes."
    },
    {
      "id": "identity-service-in-another-namespace",
      "title": "Identity Service in another namespace",
      "role": "content",
      "text": "The Identity Service release can run in another namespace. Then:\n\n1. Set `dataplane.identityServiceBaseURL` to its fully qualified Service, such as `http://ids-iris-identity-service.<identity-service-namespace>.svc:9200`.\n1. Set the Identity Service's `productValidation.products.lens.baseURL` to `http://lens-redis-lens-controlplane.<namespace-name>.svc:9300`.\n1. Create the runtime credential and internal token Secrets with the same values in both namespaces. A pod mounts Secrets only from its own namespace.\n1. Allow the Identity Service pods to reach the control plane on port `9300`, and the data plane to reach the Identity Service."
    }
  ],
  "examples": [
    {
      "id": "helm-values-ex0",
      "language": "yaml",
      "code": "tenantId: default\n\ninstance:\n  id: default\n\ningest:\n  enabled: true\n\nstorage:\n  existingSecret: lens-storage\n\nlicense:\n  existingSecret: lens-license\n\ndataplane:\n  # The Identity Service release's Service. In-cluster, it speaks plain HTTP.\n  identityServiceBaseURL: http://ids-iris-identity-service:9200\n\nidentityService:\n  allowInsecureTransport: true\n  credential:\n    existingSecret: lens-dp-credential\n\ncontrolplane:\n  internalToken:\n    existingSecret: lens-internal-token\n\ntests:\n  enabled: true",
      "section_id": "helm-values"
    },
    {
      "id": "storage-secret-ex0",
      "language": "yaml",
      "code": "storage:\n  streams:\n    urls:\n      - rediss://<records-user>:<records-password>@<records-host>:<records-port>\n  index:\n    urls:\n      - rediss://<records-user>:<records-password>@<records-host>:<records-port>\n  content:\n    urls:\n      - rediss://<content-user>:<content-password>@<content-host>:<content-port>\n  metadata:\n    urls:\n      - rediss://<metadata-user>:<metadata-password>@<metadata-host>:<metadata-port>",
      "section_id": "storage-secret"
    },
    {
      "id": "storage-secret-ex1",
      "language": "yaml",
      "code": "storage:\n  metadata:\n    urls:\n      - rediss://<metadata-user>:<metadata-password>@<metadata-host>:<metadata-port>\n# Optional. The control plane checks the records database for Redis Search,\n# Redis JSON, and noeviction at startup and on each retention change.\ndram:\n  urls:\n    - rediss://<records-user>:<records-password>@<records-host>:<records-port>",
      "section_id": "storage-secret"
    }
  ]
}
