Skip to main content

Configuration Mechanics

This page explains how each service builds its configuration from several layers, and the ways you can supply configuration beyond environment variables. Use it when you build your own deployment.

For the quick way to make changes after the quick start, see Configuring Your Installation.

Core configuration layers​

Core builds its runtime configuration from layers, applied in order:

  1. Each configuration file passed with --config, in the order given

  2. Environment variables beginning with ONE_

When a setting appears in more than one layer, the later layer wins, following the merge rules below.

With Docker Compose, configuration files are set in the service's command and environment variables in env_file:

services:
core:
env_file:
- ./env/.core.env # Applied last
command:
- --config
- config/config-procivis-base.yml # Applied first
- --config
- /config/my-config.yml # Applied second
volumes:
- ./conf/core/my-config.yml:/config/my-config.yml:ro

Files inside the image are referenced by a path relative to the image's working directory, /app. For example, config/config-procivis-base.yml is /app/config/config-procivis-base.yml. Your own files must be mounted into the container. In the example above they are mounted under /config, which is a separate directory from the image's /app/config.

Starting configurations​

The Core image includes configuration files to start from, in /app/config:

  • Base configuration: defaults for all deployments. Always load it first.
  • Deployment configuration: settings for a type of deployment, such as a server. Load it after the base configuration.
  • Examples: configurations for specific use cases, in config/examples. Each example has been tested for its use case and is a reasonable place to start, but it is not guaranteed to fit your requirements.

To see the files included in your image, copy them out of the running Core container:

docker compose cp core:/app/config ./core-config-from-image

Ways to configure Core​

You can combine these approaches. Whatever you choose, keep your own changes out of the files in the image, so they stay in one place and upgrades do not overwrite them.

Environment variables only​

Set every change as an ONE_ environment variable on top of the base configuration. This is the approach used in Configuring Your Installation. Core can be configured entirely this way. See Environment variable pathing.

Provider instance parameters include public or private in their path. Both work; private keeps the value out of the configuration API.

Your own configuration file​

For many settings, a YAML file is easier to read and review than environment variables. Mount the file into the container and pass it with an additional --config after the base configuration, as in the Compose example above.

When you change a mounted file, restart the service to apply it. docker compose up -d does not detect changes to mounted files:

docker compose restart core

Starting from an example​

To use an example, load it after the base configuration, then add your own changes in a later layer. Files in the image do not need to be mounted:

command:
- --config
- config/config-procivis-base.yml
- --config
- config/examples/<example>.yml
- --config
- /config/my-config.yml

Several environments​

To run the same installation in several environments, such as development, staging, and production, keep shared settings in one layer and environment-specific settings in another. Common patterns:

  • One configuration file with shared settings, plus one file per environment passed as an additional --config
  • One configuration file with shared settings, plus one environment file per environment
  • A combination of both, for example with environment-specific secrets in environment variables

Merge and override rules​

Core uses Figment2 to load configuration, with its merge strategy for combining layers:

  • Values are replaced. Strings, numbers, and booleans take the value from the later layer. This includes empty strings: a later "" replaces an earlier value.
  • Lists are replaced. A later list replaces the earlier list entirely; it is not appended to.
  • Objects are merged. Nested settings, such as a provider instance, are merged key by key. A later layer only needs to contain the keys it changes.
  • Omitted settings are kept. A setting missing from a later layer keeps its value from the earlier layer.
Earlier layerLater layerResult
x: 1x: 2x: 2
x: "a"x: ""x: ""
x: "a"x: nullx: null, usually rejected at startup
x: 1(not set)x: 1
x: [a, b]x: [c]x: [c]
x: {y: 1}x: {z: 2}x: {y: 1, z: 2}
x: {y: 1}x: {}x: {y: 1}
x: ""x: {y: 1}x: {y: 1}

To keep an earlier value, remove the setting from the later layer or comment it out. Do not leave it empty, and do not set it to null: most settings expect a specific type, and Core fails to start if it receives null instead.

warning

Core ignores settings it does not recognize. A misspelled key, or a key with the wrong capitalization, has no effect and produces no error. If a change does not take effect, check the key against the configuration reference.

The configuration API shows how your layers were merged, but not whether a setting is valid:

  • globalSettings and the public parameters of provider instances are returned, including parameters Core does not recognize. Use the API to confirm that a value reached the right instance, then check its name against the reference.
  • app settings and the private parameters of provider instances are never returned.

Example​

If Docker Compose passes the following layers to Core:

services:
core:
env_file:
- ./env/.core.env
command:
- --config
- config/config-procivis-base.yml

and the base configuration contains:

format:
MDOC:
type: MDOC
params:
public:
leewaySeconds: 60

and .core.env contains:

ONE_format__MDOC__params__public__leewaySeconds=120

the result is an MDOC instance with type: MDOC and leewaySeconds: 120.

Turning off an instance​

A later layer cannot remove an instance defined by an earlier layer. Omitting it, or setting it to an empty object, leaves it unchanged. To turn off an instance, set enabled: false. This works for all provider instances:

format:
MDOC:
enabled: false

Or as an environment variable:

ONE_format__MDOC__enabled=false

In general, assets created with the instance remain available, but the instance cannot be used for new operations. The exact behavior depends on the provider type.

Environment variable pathing​

To set a Core configuration value with an environment variable:

  1. Start with the prefix ONE_.

  2. Write the YAML path, replacing each level separator with __ (double underscore).

Given this configuration:

app:
auth:
staticToken: "abc123"
keyStorage:
AZURE_VAULT:
params:
private:
vaultUrl: "https://example.com"

the equivalent environment variables are:

ONE_app__auth__staticToken="abc123"
ONE_keyStorage__AZURE_VAULT__params__private__vaultUrl="https://example.com"

Variable names are case-sensitive. The path must match the YAML path exactly: ONE_app__coreBaseUrl sets app.coreBaseUrl, while ONE_APP__COREBASEURL is ignored.

Environment variables follow the same merge rules as configuration files.

Value syntax​

Environment variable values are parsed using TOML-like syntax:

TypeSyntaxExample
StringText in double quotesONE_app__traceLevel="info"
Booleantrue or false, no quotesONE_app__enableMetrics=true
NumberDigits, no quotesONE_app__databasePool__maxConnections=10
ListValues in [ ], wrapped in single quotesONE_issuanceProtocol__OPENID4VCI_FINAL1__params__public__redirectUri__allowedSchemes='["https", "myapp"]'
Objectkey=value pairs in { }, wrapped in single quotesONE_app__auth='{mode="UNSAFE_STATIC", staticToken="abc123"}'

Inside lists and objects, put strings in double quotes and leave numbers and booleans unquoted. Objects can be nested:

ONE_globalSettings='{httpClient={insecureHttpTransportAllowed=true, maxRedirects=3}}'

An object set this way is merged like any other layer: it adds to and overrides the earlier object, but does not replace it. Setting one value per variable is easier to read and less error-prone; use objects when you need to set many related values at once.

For the full parsing rules, see the Figment2 Env provider documentation.

Java services​

BFF, Bridge, and WRPR are Spring Boot applications. Each service's image includes a default configuration file, application.yml, packaged inside the service's JAR file. Override its values with environment variables, using the property names from each service's configuration reference:

frontend.url="https://example.com"
sts.token.iss="https://example.com"

Some properties are derived from others. For example, the BFF builds login.url from frontend.url. When you change the base property, the derived properties follow. Set a derived property only if it must differ from the derived value.

To see the default configuration of a service, copy its JAR out of the running container and print the file:

ServiceJAR
BFF/app/desk.jar
Bridge/app/<!!!>.jar
WRPR/app/<!!!>.jar
docker compose cp bff:/app/desk.jar ./desk.jar
unzip -p desk.jar BOOT-INF/classes/application.yml

For precedence details and other ways to supply properties, see the Spring Boot documentation on externalized configuration.

Configuration references:

Example: the quick start bundle​

The Full Stack Quick Start bundle configures each service as follows:

ServiceConfiguration
Coreconfig/config-procivis-base.yml (in the image), then conf/core/core-config.yml, then env/.core.env
BFFapplication.yml (in the image), then env/.bff.env
Bridgeapplication.yml (in the image), then env/.bridge.env
WRPRapplication.yml and config.json (in the image), then env/.wrpr.env
oauth2-proxyconf/oauth2_proxy/oauth2-proxy.cfg, conf/oauth2_proxy/alpha-config.yml
Keycloakenv/.keycloak.env, master-realm.json
Databasesenv/.*_mariadb.env, env/.keycloak_postgres.env
Traefikcommand and labels in docker-compose.yml