A node is configured entirely through environment variables. The engine repository’s .env.example is the template: copy it to .env and fill it in. This page lists every variable, grouped by what it controls.
| Variable |
What it is |
DATABASE_URL |
PostgreSQL connection for the node’s application role. The node refuses to start if this connects as a superuser, because the append-only audit trigger cannot bind one |
KEY_STORE_PATH |
Where the encrypted signing-key file is written (a path, not a secret) |
KEY_STORE_PASSPHRASE |
Protects the key store. Generate it (openssl rand -base64 32); an empty value or the old template value stops the node |
DID_WEB_BASE_URL |
The public origin your did:web identity is served from |
RESOLVER_BASE_URL |
The resolver’s public origin, printed onto products. Required by the node and the resolver, with no default |
With the bundled compose file, DATABASE_POSTGRES_PASS (superuser, used for container setup and migrations) and DATABASE_APP_PASS (the node’s role) are set once and the connection URLs are built from them.
Read by Docker Compose when it starts the stack, not by the node.
| Variable |
Default |
What it does |
ODAL_VERSION |
latest |
Which release of the node and resolver images to run, written without the leading v: the release tagged v1.4.2 is image 1.4.2. The ready-made images are not public yet, so for now a node runs from a clone of the engine: the images are built from its source, and this only names the result |
| Variable |
Default |
What it does |
NODE_PROFILE |
development |
sandbox or production: how strict the node is about the services it depends on for trust. See Node profiles |
ALLOW_DEV_CREDENTIALS |
false |
true accepts the old sample passwords. Development only; logs a warning |
ALLOW_UNSIGNED_PLUGINS |
false |
true loads plugins without a signature. Development only; logs a warning |
| Variable |
What it does |
ADMIN_USERNAME, ADMIN_PASSWORD |
A full-admin Basic login, used by odal bootstrap to mint the first API key and as the lock-out recovery path. Leave both unset in normal running; with either unset, the node accepts no Basic login at all. admin/admin stops the node |
| Variable |
Default |
What it does |
DATABASE_MIGRATE_URL |
unset |
A privileged connection; if set, the node runs migrations at start-up and never keeps this connection open |
NODE_PORT |
8001 |
The node’s port, serving /vault, /identity and /integrator |
LOG_LEVEL |
info |
Log filter |
LOG_FORMAT |
JSON |
pretty for human-readable logs |
METRICS_ADDR |
127.0.0.1:9100 |
Private Prometheus endpoint, off the public port. Empty disables it |
CORS_ALLOWED_ORIGINS |
empty |
Comma-separated browser origins allowed to call the API. Empty means server-side access only |
NATS_URL |
empty |
Optional event bus. Empty discards events; if set, the node fails fast when it cannot connect |
BATCH_CONCURRENCY |
20 |
Rows processed concurrently during bulk import |
| Variable |
Default |
What it does |
PLUGINS_DIR |
./plugins |
Where plugins are loaded from |
PLUGIN_SIGNING_KEY |
unset |
Hex-encoded Ed25519 public key plugins must be signed with. Required when plugins are present, unless the development override is on |
RULESET_BUNDLE_PATH, RULESET_PUBLISHER_PUBKEY |
unset |
The signed ruleset channel. Set both or neither; unset runs the built-in baseline |
RULESET_POLL_INTERVAL_SECS |
300 |
How often the channel is re-read; 0 leaves odal ruleset reload as the only trigger |
A node trusts no credential issuer until you name one. See Access credentials.
| Variable |
What it does |
CREDENTIAL_ISSUERS_LEGITIMATE_INTEREST |
Comma-separated issuer DIDs trusted to attest a legitimate interest |
CREDENTIAL_ISSUERS_AUTHORITY |
Comma-separated issuer DIDs trusted to attest an authority |
CREDENTIAL_ISSUERS_SELF |
true trusts the node’s own operator DID for a legitimate interest, and nothing above it. Needed for credentials the node issues itself |
| Variable |
Default |
What it does |
WEBHOOK_ALLOW_PRIVATE_TARGETS |
false |
Allow deliveries to private or loopback addresses. Off, only public HTTPS receivers are accepted |
See Electronic seals.
| Variable |
Default |
What it does |
SEAL_PROVIDER |
unset |
local for the node’s own sealer, or unset/none for no sealing. An unrecognised value stops the node |
SEAL_CONFORMANCE_LEVEL |
LTA |
B, T, LT or LTA. An unrecognised value stops the node |
SEAL_LOCAL_KEY_PATH |
./.seal-local |
Where the local sealer keeps its key and certificate |
SEAL_AUDIT_BATCH, SEAL_AUDIT_INTERVAL_SECS |
200, 60 |
How many stored seals the background check opens per pass, and how often |
TRUSTED_LIST_REFRESH |
off |
on makes the node fetch and verify the EU trusted lists daily (around thirty hosts, tens of megabytes). Anything else is off |
| Variable |
Default |
What it does |
EU_REGISTRY_CLIENT_ID, EU_REGISTRY_CLIENT_SECRET |
unset |
Unset, registrations are queued but not submitted. Both set activates the registry’s sandbox adapter |
EU_REGISTRY_ALLOW_INVALID_PAYLOADS |
false |
Submit registrations that fail the node’s own checks. For false positives only |
SNAPSHOT_PUBLIC_BASE_URL |
unset |
Where your continuity snapshots are publicly served; declared to the registry as each passport’s back-up link |
The operator’s legal name and country for a registration come from odal operator, not from here.
The node’s container image includes object-storage support; any S3-compatible service works.
| Variable |
What it does |
BACKUP_S3_BUCKET, BACKUP_S3_ACCESS_KEY_ID, BACKUP_S3_SECRET_ACCESS_KEY |
The back-up copy: a private copy of every passport version, kept apart from the node. Unset, the back-up copy is off and the trust posture says so |
BACKUP_S3_ENDPOINT, BACKUP_S3_REGION |
Optional; default AWS and us-east-1 |
SNAPSHOT_S3_BUCKET, SNAPSHOT_S3_ACCESS_KEY_ID, SNAPSHOT_S3_SECRET_ACCESS_KEY |
A separate, public-read bucket for continuity snapshots. Never the back-up bucket |
SNAPSHOT_S3_ENDPOINT, SNAPSHOT_S3_REGION |
Optional; default AWS and us-east-1 |
The node’s internal routes (scan-count ingest, and signing when identity runs on its own) require mutual TLS, terminated at a proxy.
| Variable |
What it does |
MTLS_PROXY_SHARED_SECRET |
Binds the client-certificate headers to your terminating proxy |
MTLS_REQUIRED_ISSUER_CN |
The issuer CN client certificates must carry |
MTLS_ALLOW_INSECURE |
true disables the check. Local development and CI only |
The resolver is deployed separately and reads its own environment.
| Variable |
Default |
What it does |
RESOLVER_PORT |
8003 |
The resolver’s port |
REDIS_URL |
required |
Response cache |
VAULT_BASE_URL |
|
The node’s vault address, e.g. http://node:8001/vault |
RESOLVER_BASE_URL |
required |
Its own public origin; the same value the node has |
CACHE_TTL_SECS |
30 |
How long a response is cached. It is also the worst-case delay before a recall or suspension is visible |
RATE_LIMIT_RPM |
120 |
Requests per minute per IP |
TRUST_FORWARDED_FOR |
false |
Trust X-Forwarded-For. Only behind a proxy that sets and sanitises it |
OPERATOR_DID_URL |
derived |
Defaults from the vault’s host |
METRICS_ADDR |
127.0.0.1:9101 |
Private metrics endpoint |
SCAN_INGEST_URL |
unset |
Where scan counts are flushed. Unset, the resolver counts nothing |
SCAN_FLUSH_INTERVAL_SECS |
300 |
How often counts are flushed |
SCAN_FLUSH_CLIENT_IDENTITY |
|
PEM bundle presented for mTLS on the flush |