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
mongodworks only withMONGO_TRANSACTIONS=false, which weakens the guarantees of auth writes. - Redis 6+
- An ingress controller. The examples use ingress-nginx.
Quick install (bundled databases)
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.
Production install (external databases)
Create a Secret with the secret environment variables, then point the chart at it withexistingSecret:
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 readsMONGO_URIfrom 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_URIitself, overriding any value in your Secret.
Generated secrets
WithoutexistingSecret, 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.
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:
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.
values.yaml):
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
KeepreplicaCount: 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:
Network policies
WithnetworkPolicy.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
Withmigrations.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-upgradehook. 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-installhook, because the database does not exist before install. On upgrades it is apre-upgradehook.
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
RuntimeDefaultseccomp profile./tmpis anemptyDir. - 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.
values.yaml.
Plain manifests (helm template)
If you deploy with Kustomize, Argo CD without Helm, orkubectl apply, render the chart once and commit the output:
- Always use
existingSecret.helm templatecannot 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.existingSecretandredis.auth.existingSecretto 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 applyignores 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 applyentri.yaml; the old version keeps running. - Bundled MongoDB, first install only: the database must exist before the Job can run, so apply
entri.yamlfirst (it contains the MongoDB StatefulSet), then the Job. On upgrades, always run the Job first.
Upgrading
Uninstalling
- The Secrets
entri,entri-mongodbandentri-redis(helm.sh/resource-policy: keep). They holdENCRYPTION_KEYand 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.