Configuration¶
Everything is environment-driven, so the same images run on a laptop or in production. The essentials:
Database¶
| Variable | Purpose |
|---|---|
DB_HOST / DB_PORT / DB_NAME |
PostgreSQL location |
DB_USERNAME / DB_PASSWORD |
credentials |
DB_SSLMODE |
TLS to PostgreSQL, the JDBC driver's sslmode: disable, allow, prefer (default: TLS when offered, certificate not verified), require, verify-ca, verify-full. Production: verify-full |
DB_SSL_ROOT_CERT |
path to the PEM CA bundle that signed the PostgreSQL server certificate; needed for verify-ca / verify-full. A SPRING_DATASOURCE_URL with its own ?sslmode= still wins |
DB_ENCRYPTION |
required — 32-char hex key encrypting secrets at rest (TOTP seeds, signing keys, IdP secrets). Immutable after first boot. A stored secret that cannot be decrypted with it fails the read |
HELIX_ALLOW_PLAINTEXT_SECRETS |
false. Accepts running without DB_ENCRYPTION outside the dev profile (secrets then stored in plaintext). An empty DB_ENCRYPTION means no key |
HELIX_DB_ENCRYPTION_MIGRATE_PLAINTEXT / HELIX_DB_ENCRYPTION_MIGRATE_UNTIL |
false / empty. Migration mode after adding DB_ENCRYPTION to an install that ran without it: plaintext secret rows are read as stored and encrypted on their next write. Loud (ERROR banner at startup and hourly) and time-boxed: outside dev, the server refuses to start unless …_UNTIL is a date (yyyy-MM-dd) at most 30 days ahead, and after that day (UTC) plaintext reads fail closed. See the upgrade guide |
HELIX_DB_ENCRYPTION_ALLOW_LEGACY |
false. Values in the legacy AES/ECB format are re-encrypted to AES-GCM at every startup; afterwards the legacy format is no longer read unless this is true |
Session store (Redis)¶
HelixIAM keeps HTTP sessions in Redis by default.
| Variable | Purpose |
|---|---|
REDIS_HOST / REDIS_PORT |
Redis location for the HTTP session store |
Redis is optional: set HELIX_SESSION_STORE=queue (and leave HELIX_TOKEN_STORE on its queue default) to keep everything in PostgreSQL.
Notifications (SMTP, SMS, push)¶
Message delivery isn't an environment variable — it's per-realm configuration you set from the console or admin API (SMTP/HTTP for email, Twilio/HTTP for SMS, FCM/APNs for push), so each realm/tenant can send from its own accounts. See Notifications.
External URLs¶
| Variable | Purpose |
|---|---|
IDP_BASE_URL |
the IdP's own external base URL (issuer / federation callbacks) |
SP_BASE_URL |
the primary app/console origin (CORS) |
HELIX_SAML_IDP_ENTITY_ID |
SAML IdP entity id |
Reverse proxies and host names¶
| Variable | Default | Purpose |
|---|---|---|
HELIX_TRUSTED_PROXIES |
(empty) | comma-separated IPs or CIDR ranges (IPv4/IPv6) of the proxies whose forwarded headers are honoured: X-Forwarded-For for the client IP, Forwarded / X-Forwarded-Proto / -Host / -Port / -Prefix for the scheme, host and issuer. Required behind a TLS-terminating proxy. X-Real-IP is never read. Helm: config.trustedProxies |
HELIX_ALLOWED_HOSTS |
(empty) | host names answered besides the hosts of IDP_BASE_URL and SP_BASE_URL (outside dev, any other Host gets 400); name accepts any port, name:port or [v6]:port only that port. Helm: config.allowedHosts |
HELIX_ADMIN_ALLOWED_HOSTS |
(empty) | when set, the admin REST API (/admin/**, /v3/api-docs/**, /swagger-ui/**) and the master realm answer only on these hosts (the admin console's host), 404 elsewhere. Helm: config.adminAllowedHosts. See Install |
HELIX_ADMIN_RESTRICT_MASTER_REALM |
true |
with HELIX_ADMIN_ALLOWED_HOSTS: also restrict /realms/master/** to the admin hosts. Helm: config.adminRestrictMasterRealm |
HELIX_CONSOLE_BASE_URL |
(unset) | the admin console's origin, used for the built-in helix-console client's redirect URI; the Helm chart sets it from config.spBaseUrl when the console is enabled |
HELIX_COOKIE_SECURE |
true |
secure cookies; the CSRF cookie is then __Host-XSRF-TOKEN. false (plain HTTP) is for development and demos only. Helm: config.cookieSecure |
See Security hardening — Reverse proxies and host names.
Use https in production
WebAuthn passkeys require a secure origin. Set the base URLs to real https:// hostnames.
Outbound calls (egress)¶
Server-initiated calls to admin- or client-configured URLs (webhooks, SCIM, HTTP email/SMS/push, SMTP relays, LDAP, OIDC/eID brokers, JWKS, logout, wallet status lists and CRL/OCSP) pass an egress guard: loopback, private, link-local and cloud-metadata destinations are refused, the host is resolved once and the connection goes to the checked address. These settings are deployment-wide; a realm admin cannot widen them.
| Variable / property | Default | Purpose |
|---|---|---|
HELIX_EGRESS_ALLOWED_PRIVATE_HOSTS |
(empty) | private or loopback hosts outbound calls may reach (in-cluster mailer, HTTP gateway): exact host names or IP literals, optionally host:port. Helm: config.egressAllowedPrivateHosts |
HELIX_MESSAGING_SMTP_ALLOWED_PORTS |
(empty) | SMTP ports allowed besides 25, 465, 587 and 2525, e.g. 1025,8025-8030; applies to realm relays and the global relay |
HELIX_FEDERATION_LDAP_ALLOWED_HOSTS |
(empty) | internal LDAP directories: host names (ldap.corp, ldap.corp:636) or CIDR ranges (10.20.0.0/16); empty = public directories only. Helm: config.ldapAllowedHosts |
HELIX_EGRESS_ALLOW_PRIVATE |
false |
deprecated: opens every outbound URL to private and loopback addresses; use the allowlist |
helix.outbound.fetch.<group>.max-concurrent / .per-realm-max |
32 / 8 (wallet: 16 / 16) |
concurrent outbound calls per feature group — login-admin, login-client, otp, outbound, ldap, wallet — and per realm |
helix.outbound.deliveries.max-pending |
20000 |
pending webhook / SCIM deliveries per queue across all realms (1,000 per realm) |
Bootstrap admin¶
| Variable | Purpose |
|---|---|
HELIX_ADMIN_USERNAME / HELIX_ADMIN_PASSWORD |
the master-realm admin created on first boot; the username defaults to admin |
HELIX_ADMIN_PASSWORD_FILE |
where a generated password is written (mode 0600) when HELIX_ADMIN_PASSWORD is unset; default $TMPDIR/helixiam-admin-password (/tmp/helixiam-admin-password in the image). The password is never logged, only this path |
Feature toggles¶
| Variable | Default | Purpose |
|---|---|---|
USER_REGISTRATION_ENABLED |
false |
platform-wide master switch for self-registration; each realm also has its own Allow self-registration toggle, and both must be on for that realm's /register to accept sign-ups — see Realm settings — Registration |
MFA_ENABLED |
true (false in the dev profile) |
true sends every password sign-in in every realm through TOTP; false leaves it to each realm's requireMfa |
HELIX_SESSION_STORE |
redis (queue in the dev profile) |
HTTP session store: redis, or queue to keep sessions in PostgreSQL |
HELIX_TOKEN_STORE |
queue |
queue = the built-in Postgres-backed token store; redis for the high-throughput Redis tier |
HELIX_FEDERATION_STORE_ENABLED |
true |
load identity providers created in the console / admin API into the live registry (every realm) |
HELIX_FEDERATION_STORE_POLL_INTERVAL_SECONDS |
10 |
how often each replica checks for identity-provider changes made on another replica; 0 = off |
HELIX_WALLET_TRANSACTION_STORE |
(automatic) | EU Digital Identity Wallet transaction store: jdbc, redis or memory (one replica, development only). Automatic: PostgreSQL, or Redis when the session store is Redis — see the wallet guide |
HELIX_CLUSTER_STATE_STORE |
(automatic) | where flow state (push, QR, transaction signing, enrolment, CIBA, SAML replay cache) and rate limits are shared: jdbc, redis or memory (one replica only). Automatic: Redis with the Redis session store, PostgreSQL otherwise — see High availability |
HELIX_CLUSTER_EXPECTED_REPLICAS |
0 |
expected number of replicas (the Helm chart sets it from replicaCount); above 1, keeping shared state in memory logs a WARN |
HELIX_RETENTION_ENABLED |
true |
the scheduled cleanup of expired rows — see Data retention |
HELIX_RETENTION_AUDIT_LOG_MAX_AGE |
(empty: keep) | delete audit-log rows older than this (e.g. 400d); empty keeps the audit log |
HELIX_FLOW_ENGINE_ENABLED |
false |
drive post-password steps with the flow engine |
HELIX_MIGRATIONS_ENABLED |
true |
Flyway manages the schema (see Upgrades) |
HELIX_AUDIT_ENABLED |
true |
emit the audit log |
DB_RO_HOST (and spring.readonly.datasource.url) are deprecated and ignored from 1.0.0-rc.13: the server uses one
connection pool and logs a warning at startup when either is set.
Never change DB_ENCRYPTION after first boot
Existing encrypted rows become unreadable. Back the key up and keep it stable for the life of the install.
The full list, with defaults, is in the server's application.properties and the product README's Configuration section.