Skip to main content
The Helm chart is published as an OCI artifact at oci://ghcr.io/nt3-io/charts/entri. Chart versions match Entri releases: chart 1.2.3 deploys image ghcr.io/nt3-io/entri:1.2.3. The source is in deploy/helm/entri.

Requirements

  • Kubernetes 1.25+ and Helm 3.10+
  • MongoDB 6+ running as a replica set (recommended; Atlas or a single-node replica set work). A standalone mongod works only with MONGO_TRANSACTIONS=false, which weakens the guarantees of auth writes.
  • Redis 6+
  • An ingress controller. The examples use ingress-nginx.
The chart can run MongoDB and Redis for you as single-pod StatefulSets. That suits small installs and evaluation. For production, use managed services or an operator.
GitOps and helm template users (Argo CD, Flux with client-side rendering, Kustomize, plain manifests): the chart reuses generated secrets through Helm’s lookup, which returns nothing when the chart is rendered client-side. BETTER_AUTH_SECRET, ENCRYPTION_KEY and the bundled MongoDB/Redis passwords would then be regenerated on every render, logging everyone out, making encrypted data unreadable and locking Entri out of its own MongoDB. You must create these Secrets yourself and set existingSecret, plus mongodb.auth.existingSecret and redis.auth.existingSecret when the bundled databases are enabled. See Plain manifests.

Quick install (bundled databases)

Replace 1.2.3 with the latest release. publicUrl sets BETTER_AUTH_URL and APP_HOST. It must be the URL users open, without a trailing slash. Then open https://entri.example.com and sign up. The first account on an empty instance can always sign up. Afterwards, set config.DISABLE_SIGNUP=true so that only invited users can join.
Keep your settings in a values file (-f values.yaml) rather than --set flags. You need the same file for every upgrade.

Production install (external databases)

Create a Secret with the secret environment variables, then point the chart at it with existingSecret:
values.yaml
MONGO_URI must include the database name in its path (/entri). See Database settings.

Configuration and secrets

The chart turns values into environment variables: When you use existingSecret:
  • The Secret must exist before helm install, because the migration hook reads MONGO_URI from it.
  • Put every secret variable you need in it: MONGO_URI, REDIS_URI (unless the bundled databases are enabled), BETTER_AUTH_SECRET, ENCRYPTION_KEY, plus API keys, SMTP_PASS, OAuth secrets and so on.
  • With the bundled MongoDB or Redis, the chart sets MONGO_URI / REDIS_URI itself, overriding any value in your Secret.

Generated secrets

Without existingSecret, the chart generates BETTER_AUTH_SECRET and ENCRYPTION_KEY on first install if you leave them empty. They are stored in the release Secret (named entri for a release called entri), reused on every upgrade, and the Secret carries helm.sh/resource-policy: keep, so it survives helm uninstall.
Back up ENCRYPTION_KEY. Without it, Entri cannot decrypt the AI keys organizations have stored.
The bundled MongoDB and Redis passwords are generated the same way, in the Secrets entri-mongodb (keys mongodb-root-password, mongodb-keyfile) and entri-redis (key redis-password), also kept on uninstall. To manage them yourself, create those Secrets and set mongodb.auth.existingSecret / redis.auth.existingSecret. Passwords must be URL-safe. MongoDB applies the root password only when it first initializes its data volume. If you later pass a different mongodb.auth.rootPassword, the chart fails with an explanation instead of locking Entri out. Rotate it manually: change it inside MongoDB (db.getSiblingDB("admin").changeUserPassword(...)), update the mongodb-root-password key of the Secret, then upgrade. Changing the Redis password is safe: Redis and Entri restart together.

Bundled databases

Back up the bundled MongoDB with mongodump:
Redis holds only short-lived caches, locks and progress messages, so it needs no backup.

Ingress, WebSockets and SSE

Entri needs two things from the ingress:
  • WebSockets for the progress channel at /ws/progress. ingress-nginx supports them out of the box.
  • Unbuffered Server-Sent Events with long timeouts, for import, AI batch-translation and GitHub sync progress.
The annotations for ingress-nginx (also listed in values.yaml):
For other controllers, configure the equivalent settings. TRUST_PROXY is unset by default. Entri then trusts X-Forwarded-For from proxies on loopback and private networks, which covers in-cluster ingress controllers. Set config.TRUST_PROXY to a hop count or CIDR list only if a load balancer with a public IP forwards to Entri directly. See Server settings.

Replicas and sticky sessions

Keep replicaCount: 1. AI batch-translation progress streams live in process memory, so the request that opens a stream must reach the pod that runs the job. The autoscaler (autoscaling.enabled) is off by default for the same reason. If you run more than one replica, enable cookie affinity on the ingress:
Import progress over WebSockets is shared between pods through Redis pub/sub and does not need affinity.

Network policies

With networkPolicy.enabled: true (default), the chart adds NetworkPolicies for the bundled MongoDB and Redis: only Entri pods and the migration job can connect to them. Nothing is rendered for external databases. The Entri pods themselves are not restricted, because ingress controllers differ. To lock them down, add your own policy that selects app.kubernetes.io/name: entri and allows traffic from your ingress controller’s namespace on the http port (3333).

Database migrations

With migrations.enabled: true (default), every helm install and helm upgrade runs a Job named entri-migrate that executes migrate with the new image:
  • External MongoDB: the Job is a pre-install,pre-upgrade hook. It runs before the new pods start. If it fails, the upgrade fails and the old pods keep running.
  • Bundled MongoDB: on first install the Job is a post-install hook, because the database does not exist before install. On upgrades it is a pre-upgrade hook.
The Job retries up to migrations.backoffLimit (10) times, which covers a database that is still starting, with a deadline of migrations.activeDeadlineSeconds (900). Successful Jobs are deleted. A failed Job is kept, so you can read its log:

Security defaults

  • Pods run as non-root (UID 1000) with a read-only root filesystem, all capabilities dropped and the RuntimeDefault seccomp profile. /tmp is an emptyDir.
  • Probes: startup and liveness on /api/v1/health/liveness, readiness on /api/v1/health/readiness (checks MongoDB and Redis).
  • Default resources: requests of 250m CPU and 512Mi memory, with a 1Gi memory limit.
The full list of values is in the chart README and values.yaml.

Plain manifests (helm template)

If you deploy with Kustomize, Argo CD without Helm, or kubectl apply, render the chart once and commit the output:
Things to know:
  • Always use existingSecret. helm template cannot read the cluster, so it writes secret values, or newly generated random ones, into the YAML, and they change on every render.
  • Bundled databases need their own Secrets. For the same reason, set mongodb.auth.existingSecret and redis.auth.existingSecret to Secrets you created yourself. Otherwise each render generates a new MongoDB password, and MongoDB, which keeps the password it was first initialized with, starts rejecting Entri.
  • Migrations. kubectl apply ignores Helm hooks, so run the migration Job yourself, as above: on every upgrade, delete the old Job, apply the new one, and wait for it to complete before applying the new Deployment. If the Job fails (kubectl -n entri logs job/entri-migrate), do not apply entri.yaml; the old version keeps running.
  • Bundled MongoDB, first install only: the database must exist before the Job can run, so apply entri.yaml first (it contains the MongoDB StatefulSet), then the Job. On upgrades, always run the Job first.

Upgrading

The migration hook runs before the new pods start. See Upgrading for backups and rollback.

Uninstalling

By design, some resources stay behind:
  • The Secrets entri, entri-mongodb and entri-redis (helm.sh/resource-policy: keep). They hold ENCRYPTION_KEY and the database passwords that match the data on the volumes.
  • The PersistentVolumeClaims of the bundled databases (data-entri-mongodb-0, data-entri-redis-0). Kubernetes never deletes StatefulSet volumes automatically.
If you install again with the same release name and namespace, the chart picks up the kept Secrets and volumes, and your data is still there. To remove everything permanently: