Requirements
What LutraID needs from you, and the choices worth making before you start rather than after.
Tools
| Tool | For | Notes |
|---|---|---|
| Docker Engine 25+ with the Compose v2 plugin | The Compose package | docker compose version |
kubectl and Helm 3.8+ | The Helm package | Helm pulls the chart straight from the registry |
oras 1.x | Downloading the release bundle | Uses the same login as Docker |
cosign v2.5+ and crane | Verifying a release, mirroring it | Recommended, not required to run LutraID |
openssl, curl | Generating secrets, talking to the API | Present on almost every Linux host |
Infrastructure
| Kubernetes | Docker Compose | |
|---|---|---|
| PostgreSQL 18 | External. A CloudNativePG example ships with the chart | Runs on the host |
| Valkey / Redis 7+ | External. A StatefulSet example ships with the chart | Runs on the host |
| Ingress + TLS | Your controller and cert-manager | Bundled Caddy, or your own proxy |
| SMTP relay | Required | Required |
| Object storage | Optional — local disk otherwise | Optional — local disk otherwise |
The chart bundles nothing stateful. That is deliberate: your DBA team already knows how to run PostgreSQL, and a database hidden inside a vendor chart is a database nobody backs up.
Sizing
| Deployment | vCPU | RAM | Disk |
|---|---|---|---|
| Evaluation | 2 | 4 GB | 20 GB |
| Small production — under 50k credentials | 4 | 8 GB | 100 GB SSD |
| Busier single host | 8 | 16 GB | 250 GB SSD |
The database and uploaded images dominate disk growth. PostgreSQL wants fast storage.
Mail is not optional
LutraID sends account mail (verification, sign-in links, password reset, email change, invitations), credential offers and check requests. EMAIL_TRANSPORT=smtp is the default and the application refuses to start without a relay configured — an internal Postfix, Exchange, or a corporate smarthost.
Resend is supported as an alternative (EMAIL_TRANSPORT=resend), but it sends your users' addresses to a third party, which is usually the reason an installation is self-hosted in the first place.
Do not disable SMTP_REQUIRE_TLS or SMTP_REJECT_UNAUTHORIZED without writing down why. Credential-offer links and sign-in links travel on this channel (offer PINs never do), and LutraID refuses to start with an unencrypted relay. For a relay with a private CA, add the CA to the container trust store instead.
Signing keys — decide before you go live
Issuer private keys sign the credentials your users receive.
| Backend | Use |
|---|---|
dev_file | The default. Keys are files on a volume — right for an evaluation, not suitable for production: anyone with access to that volume or to a backup of it has your issuer keys. Requires an explicit acknowledgement, which both packages set, and warns at every boot |
aws_kms | AWS KMS. Configurable in both packages |
vault_transit | HashiCorp Vault or OpenBao Transit. Supported by the application, but neither package exposes its settings yet — contact us if you need it |
vault_transit cannot perform ECDH, so OID4VCI encrypted credential requests are unavailable on it. Issuance and verification are unaffected, and LutraID refuses to start if you enable that feature on a backend that cannot support it — rather than failing later inside a citizen-facing flow.
You cannot switch KEY_BACKEND on a live deployment and expect existing keys to resolve. Migration means creating new keys in the new backend, rotating issuers onto them, and retiring the old ones. Choose before you go live.
The one value you cannot change later
PUBLIC_BASE_URL — host in the Helm chart — becomes the issuer identifier embedded in every credential you issue. Changing it invalidates credentials already in the field.
Decide the hostname before the first credential is issued. LutraID refuses a localhost address; for an evaluation on a machine with no public DNS name, see Evaluating on one machine.