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:
Each configuration file passed with
--config, in the order givenEnvironment 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 layer | Later layer | Result |
|---|---|---|
x: 1 | x: 2 | x: 2 |
x: "a" | x: "" | x: "" |
x: "a" | x: null | x: 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.
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:
globalSettingsand thepublicparameters 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.appsettings and theprivateparameters 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:
Start with the prefix
ONE_.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:
| Type | Syntax | Example |
|---|---|---|
| String | Text in double quotes | ONE_app__traceLevel="info" |
| Boolean | true or false, no quotes | ONE_app__enableMetrics=true |
| Number | Digits, no quotes | ONE_app__databasePool__maxConnections=10 |
| List | Values in [ ], wrapped in single quotes | ONE_issuanceProtocol__OPENID4VCI_FINAL1__params__public__redirectUri__allowedSchemes='["https", "myapp"]' |
| Object | key=value pairs in { }, wrapped in single quotes | ONE_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:
| Service | JAR |
|---|---|
| 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:
| Service | Configuration |
|---|---|
| Core | config/config-procivis-base.yml (in the image), then conf/core/core-config.yml, then env/.core.env |
| BFF | application.yml (in the image), then env/.bff.env |
| Bridge | application.yml (in the image), then env/.bridge.env |
| WRPR | application.yml and config.json (in the image), then env/.wrpr.env |
| oauth2-proxy | conf/oauth2_proxy/oauth2-proxy.cfg, conf/oauth2_proxy/alpha-config.yml |
| Keycloak | env/.keycloak.env, master-realm.json |
| Databases | env/.*_mariadb.env, env/.keycloak_postgres.env |
| Traefik | command and labels in docker-compose.yml |