Configuration
Introduction
CitrineOS uses environment variables represented by the Zod schema in packages/types/src/config/types.ts
to define its behavior. This document describes the structure of this object, how to access and modify it, and
provides low-level details about each available configuration.
Scope
The configuration object controls the information needed for the specific technologies that fill a role in the application (
database, queue, cache, etc.) as well as optional OCPP features and certain values which can be different from network
to network (heartbeat interval, message timeout, etc.).
Websocket Servers
Setting up websocket servers doesn't happen from environment variables, but rather through the websocket-servers.json
file. You may change what file CitrineOS reads websocket servers from by setting CITRINEOS_WEBSOCKETSERVERCONFIGFILE.
Websocket Server Configurations
| Field |
Type |
Required |
Default |
What it does |
id |
string |
Yes |
— |
Identifies this server. Must be unique across the array; used as the key for the server's certificate manager and stored on the ServerNetworkProfile row. |
host |
string |
Yes |
— |
Bind address for this websocket listener. |
port |
integer >= 1 |
Yes |
— |
Port for this listener. Each entry is its own HTTP/HTTPS server, so ports must not collide. |
protocols |
array of ocpp1.6 / ocpp2.0.1 / ocpp2.1 |
Yes |
— |
The OCPP subprotocols this listener will negotiate. A station offering none of them is rejected at upgrade. |
securityProfile |
integer 0–3 |
Yes |
— |
OCPP security profile. 0 = plain ws, no auth; 1 = ws + HTTP Basic; 2 = TLS + Basic; 3 = mTLS (client cert). Drives whether an http or https server is created, and whether client certs are requested and verified. |
tenantId |
positive integer |
One of |
— |
Pins the whole listener to a single tenant. Mutually exclusive with dynamicTenantResolution — exactly one must be set. |
dynamicTenantResolution |
boolean |
One of |
false |
Resolves the tenant per connection from the request path segment, matched against Tenant.tenantWebsocketServerPath, instead of pinning one tenant to the listener. |
pingInterval |
integer >= 1 |
No |
60 |
Seconds between websocket pings (jitter applied on the first). Also sets the connection's cache TTL at pingInterval × 3, so it doubles as the liveness timeout. |
allowUnknownChargingStations |
boolean |
No |
false |
Lets a station with no matching DB row connect and be provisioned ad hoc. Development and testing only — do not use in production!! |
ignoreAuthenticationHeaders |
boolean |
No |
false |
Skips the HTTP Basic auth filter that security profiles 1 and 2 would otherwise enforce. An escape hatch for stations that cannot send credentials; it removes the authentication the profile implies. |
forceProtocol |
ocpp1.6 / ocpp2.0.1 / ocpp2.1 |
No |
— |
Pins negotiation to one version instead of picking from the station's offered list. If the station or this server does not support it, the upgrade fails with an explicit error. |
tlsKeyFilePath |
string |
Profiles 2, 3 |
— |
Server private key. |
tlsCertificateChainFilePath |
string |
Profiles 2, 3 |
— |
Server certificate chain, served via SNI for any profile above 1. |
mtlsCertificateAuthorityKeyFilePath |
string |
Profile 3 |
— |
CA key for mTLS client-certificate handling. |
rootCACertificateFilePath |
string |
No |
— |
Root CA used as the TLS ca bundle to verify client certificates. Only read when securityProfile > 2. |
Environment Variables
You won't need to set anything if you are happy with the default values found in the Zod schema packages/types/src/config/types.ts.
Otherwise, follow the sections below to learn how to set the values you need.
Setting values
To set an environment variable, prefix it with CITRINEOS_ and append the path to the field, uppercased, with one
underscore per level, not per word. A camelCase field name stays one segment:
logLevel → CITRINEOS_LOGLEVEL
database.host → CITRINEOS_DATABASE_HOST
timeouts.maxCallLengthSeconds → CITRINEOS_TIMEOUTS_MAXCALLLENGTHSECONDS
fileAccess.local.defaultFilePath → CITRINEOS_FILEACCESS_LOCAL_DEFAULTFILEPATH
Matching is case-insensitive. Values are parsed as JSON when possible and used as a raw string otherwise, so numbers and
booleans need no special handling, and an empty object switches a whole optional block on with its defaults:
CITRINEOS_LOGLEVEL: '1'
CITRINEOS_OCPP_AUTOACCEPT: 'false'
CITRINEOS_INTEGRATIONS_V2GCA: '{}' # opt in to the Hubject test PKI
Top level
| Variable |
Type |
Default |
What it does |
CITRINEOS_ENV |
development | production |
development |
Runtime mode; affects log formatting. |
CITRINEOS_HOST |
string |
0.0.0.0 |
HTTP bind address for the server. |
CITRINEOS_PORT |
integer > 0 |
8080 |
HTTP port for the server. |
CITRINEOS_LOGLEVEL |
integer 0–6 |
2 |
Log verbosity; 2 is debug. |
CITRINEOS_WEBSOCKETSERVERCONFIGFILE |
string |
websocket-servers.json |
Path (relative to the fileAccess root) of the JSON file listing the websocket servers this instance hosts. |
DATABASE
The DATABASE block is optional — every field has a default, so an unset database still resolves to a local Postgres.
| Variable |
Type |
Default |
What it does |
CITRINEOS_DATABASE_HOST |
string |
localhost |
Database host. |
CITRINEOS_DATABASE_PORT |
integer > 0 |
5432 |
Database port. |
CITRINEOS_DATABASE_DATABASE |
string |
citrine |
Database name. Note the doubled segment — the field is database.database. |
CITRINEOS_DATABASE_DIALECT |
string |
postgres |
Sequelize dialect. |
CITRINEOS_DATABASE_USERNAME |
string |
citrine |
Database user. |
CITRINEOS_DATABASE_PASSWORD |
string |
citrine |
Database password. |
CITRINEOS_DATABASE_SYNC |
boolean |
false |
Sync models to the schema on boot. |
CITRINEOS_DATABASE_ALTER |
boolean |
false |
Alter existing tables to match models when syncing. |
CITRINEOS_DATABASE_FORCE |
boolean |
false |
Drop and recreate tables when syncing. Destructive. |
CITRINEOS_DATABASE_MAXRETRIES |
integer > 0 |
3 |
Connection attempts before giving up at startup. |
CITRINEOS_DATABASE_RETRYDELAY |
integer > 0 |
1000 |
Milliseconds between connection attempts. |
DATABASE_POOL — optional
| Variable |
Type |
Default |
What it does |
CITRINEOS_DATABASE_POOL_MAX |
integer > 0 |
unset |
Maximum pooled connections. |
CITRINEOS_DATABASE_POOL_MIN |
integer >= 0 |
unset |
Minimum pooled connections held open. |
CITRINEOS_DATABASE_POOL_ACQUIRE |
integer > 0 |
unset |
Milliseconds to wait for a connection before erroring. |
CITRINEOS_DATABASE_POOL_IDLE |
integer > 0 |
unset |
Milliseconds a connection may sit idle before release. |
DATABASE_SSL — optional
| Variable |
Type |
Default |
What it does |
CITRINEOS_DATABASE_SSL_REQUIRE |
boolean |
unset |
Require a TLS connection to the database. |
CITRINEOS_DATABASE_SSL_REJECTUNAUTHORIZED |
boolean |
unset |
Verify the server certificate. Set false only for self-signed setups. |
CITRINEOS_DATABASE_SSL_CA |
string |
unset |
CA certificate used to verify the database server. |
CACHE
| Variable |
Type |
Default |
What it does |
CITRINEOS_CACHE_TYPE |
memory | redis |
memory |
Cache backend. memory is per-process, so multi-instance deployments want redis. |
CITRINEOS_CACHE_URL |
string |
— |
Required when type is redis. Must start with redis:// or rediss://. |
MESSAGEBROKER_AMQP
| Variable |
Type |
Default |
What it does |
CITRINEOS_MESSAGEBROKER_AMQP_URL |
string |
amqp://guest:guest@localhost:5672 |
AMQP connection URL. |
CITRINEOS_MESSAGEBROKER_AMQP_EXCHANGE |
string |
citrineos |
Exchange modules publish to and subscribe from. |
CITRINEOS_MESSAGEBROKER_AMQP_INSTANCEIDENTIFIER |
string |
unset |
Identifies this instance on the broker; useful when several instances share an exchange. |
CITRINEOS_MESSAGEBROKER_AMQP_MAXRECONNECTDELAYSECONDS |
integer >= 1 |
30 |
Ceiling on the reconnect backoff. |
FILEACCESS
Storage the server reads its runtime files through — the websocket servers file, TLS material, the ACME account key, RBAC rules.
| Variable |
Type |
Default |
What it does |
CITRINEOS_FILEACCESS_TYPE |
local | s3 | gcp |
local |
Selects the storage backend. |
When FILEACCESS_TYPE is local
| Variable |
Type |
Default |
What it does |
CITRINEOS_FILEACCESS_LOCAL_DEFAULTFILEPATH |
string |
src/assets from the block default (data if you set local yourself without it) |
Root directory, resolved from the process working directory — which differs between pnpm (apps/ocpp-server) and Docker (repo root). |
When FILEACCESS_TYPE is s3
| Variable |
Type |
Default |
What it does |
CITRINEOS_FILEACCESS_S3_REGION |
string |
unset |
AWS region. |
CITRINEOS_FILEACCESS_S3_ENDPOINT |
string |
unset |
Custom endpoint URL, e.g. for MinIO. |
CITRINEOS_FILEACCESS_S3_DEFAULTBUCKETNAME |
string |
citrineos-s3-bucket |
Bucket used when a key carries no bucket of its own. |
CITRINEOS_FILEACCESS_S3_S3FORCEPATHSTYLE |
boolean |
true |
Path-style addressing, required by MinIO and most S3-compatible servers. |
CITRINEOS_FILEACCESS_S3_ACCESSKEYID |
string |
unset |
Access key. The AWS SDK's own AWS_* variables also work. |
CITRINEOS_FILEACCESS_S3_SECRETACCESSKEY |
string |
unset |
Secret key. |
When FILEACCESS_TYPE is gcp
| Variable |
Type |
Default |
What it does |
CITRINEOS_FILEACCESS_GCP_PROJECTID |
string |
— |
Required. GCP project ID. |
CITRINEOS_FILEACCESS_GCP_DEFAULTBUCKETNAME |
string |
citrineos-s3-bucket |
Bucket name. |
CITRINEOS_FILEACCESS_GCP_CREDENTIALS |
JSON object |
unset |
Service account credentials inline. If unset, Application Default Credentials are used. |
AUTH
Guards the HTTP API. At least one of oidc or localBypass must be active; the block defaults to localBypass: true for local development.
| Variable |
Type |
Default |
What it does |
CITRINEOS_AUTH_LOCALBYPASS |
boolean |
true (from the block default) |
Skips authentication entirely. Development only. |
CITRINEOS_AUTH_OIDC_JWKSURI |
string |
— |
Required within the oidc block. Where the signing keys are fetched from. |
CITRINEOS_AUTH_OIDC_ISSUER |
string |
— |
Required. Expected iss claim. |
CITRINEOS_AUTH_OIDC_AUDIENCE |
string |
— |
Required. Expected aud claim. |
CITRINEOS_AUTH_OIDC_CACHETIMESECONDS |
integer >= 1 |
unset |
How long fetched JWKS keys are cached. |
CITRINEOS_AUTH_OIDC_RATELIMIT |
boolean |
true |
Rate-limits JWKS fetches. |
OIDCCLIENT — optional
Credentials the server uses as an OIDC client when calling out. All four are required if the block is set.
| Variable |
Type |
Default |
What it does |
CITRINEOS_OIDCCLIENT_TOKENURL |
string |
— |
Token endpoint. |
CITRINEOS_OIDCCLIENT_CLIENTID |
string |
— |
Client ID. |
CITRINEOS_OIDCCLIENT_CLIENTSECRET |
string |
— |
Client secret. |
CITRINEOS_OIDCCLIENT_AUDIENCE |
string |
— |
Audience requested in the token. |
INTEGRATIONS
Both CAs are opt-in and off by default, but zero-config once enabled — '{}' is enough to accept every default.
INTEGRATIONS_V2GCA
For Plug & Charge PKI.
| Variable |
Type |
Default |
What it does |
CITRINEOS_INTEGRATIONS_V2GCA |
JSON object |
unset |
Set to '{}' to enable with the Hubject test PKI. |
CITRINEOS_INTEGRATIONS_V2GCA_NAME |
hubject |
hubject |
Provider. Hubject is the only implementation. |
CITRINEOS_INTEGRATIONS_V2GCA_HUBJECT_BASEURL |
string |
Hubject test base URL |
API base URL. |
CITRINEOS_INTEGRATIONS_V2GCA_HUBJECT_TOKENURL |
string |
Hubject test token URL |
Where the bearer token is obtained. |
CITRINEOS_INTEGRATIONS_V2GCA_HUBJECT_CLIENTID |
string |
YOUR_CLIENT_ID |
Client ID — the default is a placeholder, so real use requires setting it. |
CITRINEOS_INTEGRATIONS_V2GCA_HUBJECT_CLIENTSECRET |
string |
YOUR_CLIENT_SECRET |
Client secret — likewise a placeholder. |
INTEGRATIONS_CHARGINGSTATIONCA
For station certificates via ACME.
| Variable |
Type |
Default |
What it does |
CITRINEOS_INTEGRATIONS_CHARGINGSTATIONCA |
JSON object |
unset |
Set to '{}' to enable ACME against the Let's Encrypt staging directory. |
CITRINEOS_INTEGRATIONS_CHARGINGSTATIONCA_NAME |
acme |
acme |
Provider. ACME is the only implementation. |
CITRINEOS_INTEGRATIONS_CHARGINGSTATIONCA_ACME_ENV |
staging | production |
staging |
Which ACME directory to use. staging issues untrusted certs but has generous rate limits. |
CITRINEOS_INTEGRATIONS_CHARGINGSTATIONCA_ACME_ACCOUNTKEYFILEPATH |
string |
certificates/acme_account_key.pem |
ACME account key, resolved against the fileAccess root. |
CITRINEOS_INTEGRATIONS_CHARGINGSTATIONCA_ACME_EMAIL |
string (email) |
test@citrineos.com |
Contact address registered with the ACME account. |
RBAC — optional
Set CITRINEOS_RBAC='{}' to enable with defaults.
| Variable |
Type |
Default |
What it does |
CITRINEOS_RBAC_RULESDIR |
string |
unset |
Directory holding the rules file. |
CITRINEOS_RBAC_RULESFILENAME |
string |
rbac-rules.json |
Rules file mapping tenant → URL pattern → HTTP method → required roles. |
SWAGGER
| Variable |
Type |
Default |
What it does |
CITRINEOS_SWAGGER_ENABLED |
boolean |
true |
Serves the API docs. Set false in production if you do not want them exposed. |
CITRINEOS_SWAGGER_PATH |
string |
/docs |
Mount path for the docs UI. |
CITRINEOS_SWAGGER_LOGOPATH |
string |
src/assets/logo.png |
Logo shown in the docs. Resolved from the process working directory, not from fileAccess. |
CITRINEOS_SWAGGER_EXPOSEDATA |
boolean |
true |
Includes response data schemas in the docs. |
CITRINEOS_SWAGGER_EXPOSEMESSAGE |
boolean |
true |
Includes message schemas in the docs. |
TIMEOUTS
TIMEOUTS_MAXCACHINGSECONDS must be greater than or equal to TIMEOUTS_MAXCALLLENGTHSECONDS, or startup fails.
| Variable |
Type |
Default |
What it does |
CITRINEOS_TIMEOUTS_MAXCALLLENGTHSECONDS |
integer >= 1 |
20 |
How long an OCPP call may remain outstanding before it is considered timed out. |
CITRINEOS_TIMEOUTS_MAXCACHINGSECONDS |
integer >= 1 |
30 |
How long call state is cached. Cannot be lower than maxCallLengthSeconds. |
CITRINEOS_TIMEOUTS_STALECALLMAXAGESECONDS |
integer >= 1 |
unset |
Age past which a pending call is discarded as stale. |
CITRINEOS_TIMEOUTS_SHUTDOWNGRACEPERIODSECONDS |
integer >= 1 |
30 |
How long shutdown waits for in-flight work before forcing exit. |
CITRINEOS_TIMEOUTS_REALTIMEAUTHDEFAULTTIMEOUTSECONDS |
integer >= 1 |
15 |
How long a real-time authorization request waits for a decision. |
CITRINEOS_TIMEOUTS_NOTREADYTHRESHOLDSECONDS |
integer >= 1 |
60 |
How long the instance may be unhealthy before it reports not-ready. |
OCPP
These apply to every OCPP version — there is no per-protocol split.
| Variable |
Type |
Default |
What it does |
CITRINEOS_OCPP_HEARTBEATINTERVAL |
integer >= 1 |
60 |
Heartbeat interval in seconds sent to stations on boot. |
CITRINEOS_OCPP_BOOTRETRYINTERVAL |
integer >= 1 |
15 |
Retry interval in seconds sent when a boot is Pending or Rejected. |
CITRINEOS_OCPP_UNKNOWNCHARGERSTATUS |
Accepted | Pending | Rejected |
Accepted |
Boot status returned to a station with no BootConfig row. |
CITRINEOS_OCPP_GETBASEREPORTONPENDING |
boolean |
true |
Requests a base report from stations left in Pending. |
CITRINEOS_OCPP_BOOTWITHREJECTEDVARIABLES |
boolean |
false |
Allows a boot to proceed even when some variables were rejected. |
CITRINEOS_OCPP_AUTOACCEPT |
boolean |
true |
Promotes boot status automatically. When false, a station stays where it is until something changes it explicitly. |
TRANSACTIONS
Exactly one of TRANSACTIONS_COSTUPDATEDINTERVAL or TRANSACTIONS_SENDCOSTUPDATEDONMETERVALUE must be set — setting both,
or neither, fails startup.
| Variable |
Type |
Default |
What it does |
CITRINEOS_TRANSACTIONS_COSTUPDATEDINTERVAL |
integer >= 1 |
60 (from the block default) |
Sends a cost update on a fixed interval, in seconds. |
CITRINEOS_TRANSACTIONS_SENDCOSTUPDATEDONMETERVALUE |
boolean |
unset |
Sends a cost update on each meter value instead of on an interval. |
CITRINEOS_TRANSACTIONS_RECEIPTBASEURL |
string (URL) |
unset |
Base URL used to build receipt links for completed transactions. |
CITRINEOS_TRANSACTIONS_SIGNEDMETERVALUES_PUBLICKEYFILEID |
string |
— |
Required within the block. File ID of the public key used to verify signed meter values. |
CITRINEOS_TRANSACTIONS_SIGNEDMETERVALUES_SIGNINGMETHOD |
RSASSA-PKCS1-v1_5 | ECDSA | SECP192R1 |
— |
Required within the block. Signature algorithm to verify against. |
CITRINEOS_TRANSACTIONS_SIGNEDMETERVALUES_REJECTUNSUPPORTEDSIGNEDMETERVALUES |
boolean |
false |
Rejects signed meter values that do not match the configured method rather than accepting them unverified. |
EVDRIVER
| Variable |
Type |
Default |
What it does |
CITRINEOS_EVDRIVER_ENABLEGETCHARGINGPROFILESONSTARTTRANSACTION |
boolean |
false |
Requests the station's charging profiles when a transaction starts. |