Setup and configuration guide
A guide to configuring services and environments
How to configure
You can configure our services using configuration files, environment variables, or a combination of both. You define the files to use and in which order. When you start the service the system merges these elements together following precedence rules to build the runtime configuration.
Example setup
Here's an example setup in which we have multiple configuration files and an environment variables file for two services.
procivis-one-deployment
├── conf
│ └── core
│ ├── core_config_1.yml
│ ├── core_config_2.yml
│ ├── core_config_3.yml
│ └── bff
│ ├── bff_config_1.yml
│ ├── bff_config_2.yml
├── env
│ └── core.env
│ └── bff.env
.
If you are starting the services using Docker Compose, you can set command
line tags to define which configuration files to use, and define env_file
to set which environment files to use:
services:
core:
env_file:
- ./env/.core.env # Defines where to find env variables
command:
- --config # Define a configuration
- ./conf/core_config_1.yml # This one is merged first
- --config # Define another configuration
- ./conf/core_config_2.yml # This one is merged next
At startup the system builds the runtime configuration by starting with the configuration files you specify, in the order you specify them, and continuing with the environment variables files you specify, also in the order you specify, always overriding values with the latest value. Below is a diagram showing the order of precedence with a generic setup that uses multiple configuration and environment variable files:
Example merge
Let's look at an example of a single configuration object — the app
entry of Core configuration — being merged across two configuration
files and an environment variables file to produce a runtime configuration.
core_config_1
app
is used for configuring deployment. In this example we decide to focus
the first configuration file on the basic elements of formats and protocols
and reserve deployment settings for later in the process:
// does not appear
core_config_2
Next we decide to use this second configuration file to set up our local
development environment. Here we configure app
for local domain resolution,
use a placeholder authentication token, enable all endpoints, and allow
insecure HTTP:
app:
databaseUrl: "mysql://core:{{DB_PASSWORD}}@localhost/core"
authToken: "test"
coreBaseUrl: "http://0.0.0.0:3000"
serverIp: "0.0.0.0"
serverPort: 3000
traceJson: false
traceLevel: "debug,hyper=error,sea_orm=info,sqlx::query=error,reqwest=error"
allowInsecureHttpTransport: true
insecureVcApiEndpointsEnabled: true
enableOpenApi: true
enableExternalEndpoints: true
enableManagementEndpoints: true
.core.env
Now we want to define variables for a productive environment, and let us
suppose we do this using environment variables. For app
this means we
want to turn off insecure transport and endpoints, set a real authentication
token, point to our live domain, and set the server's IP address:
ONE_app__authToken="{{32-BYTE-RAND-HEX}}"
ONE_app__coreBaseUrl="http://example.domain"
ONE_app__serverIp="1.234.5.678"
ONE_app__allowInsecureHttpTransport="false"
ONE_app__insecureVcApiEndpointsEnabled="false"
Resulting runtime configuration:
If the Docker Compose looks like this:
services:
core:
env_file:
- ./env/.core.env # Defines where to find env variables
command:
- --config # Define a configuration
- ./conf/core_config_1.yml # This one is merged first
- --config # Define another configuration
- ./conf/core_config_2.yml # This one is merged next
then the resulting runtime configuration of app
is:
app:
databaseUrl: "mysql://core:{{DB_PASSWORD}}@localhost/core"
authToken: "{{32-BYTE-RAND-HEX}}"
coreBaseUrl: "http://example.domain"
serverIp: "1.234.5.678"
serverPort: 3000
traceJson: false
traceLevel: "debug,hyper=error,sea_orm=info,sqlx::query=error,reqwest=error"
allowInsecureHttpTransport: false
insecureVcApiEndpointsEnabled: false
enableOpenApi: true
enableExternalEndpoints: true
enableManagementEndpoints: true
Environment variable pathing
- Core
- BFF
To override any configuration value using environment variables, convert the YAML path to environment variable format using these rules:
-
Add the prefix
ONE_
-
Convert dots to double underscore: replace each
.
in the flattened path with__
-
End the path with an
=
Given this configuration:
app:
authToken: "abc123"
keyStorage:
AZURE_VAULT:
params:
private:
vaultUrl: "https://example.com"
The corresponding environment variables would be:
ONE_app__authToken="abc123"
ONE_keyStorage__AZURE_VAULT__params__private__vaultUrl="https://example.com"
To override any configuration value using environment variables, flatten
the nested structure, convert to dot notation, and end the path with an
=
.
Given this configuration:
sts:
enableManagementEndpoints: true
token:
maxTokenValidity: 2628000
The corresponding environment variables would be:
sts.enableManagementEndpoints=true
sts.token.maxTokenValidity=2628000
Environment customization
Deployments can follow one of several patterns.
Environment-specific config files:
procivis-one-deployment
├── config
│ └── base.yml # Shared defaults
│ └── development.yml # Development overrides
│ └── staging.yml # Staging overrides
│ └── prod.yml # Production overrides
.
Single config + environment variables:
procivis-one-deployment
├── config.yml
├── env
│ └── development.env
│ └── staging.env
│ └── prod.env
.
Hybrid approach
procivis-one-deployment
├── config
│ └── base.yml
│ └── development.yml
│ └── staging.yml
│ └── prod.yml
├── env
│ └── core.env
│ └── bff.env
.
With any of these setups you can run a Docker Compose for each environment:
docker-compose.dev.yml # Development overrides
docker-compose.staging.yml # Staging overrides
docker-compose.prod.yml # Production overrides
Core
The Core service provides APIs for the complete lifecycle of credentials. Core configuration consists primarily in:
- Credential protocols and formats
- Where and how the Core is available to other services
- Security settings
Key parameters are highlighted below. For all available options, see the complete reference.
Authentication token
Most endpoints require authentication using a bearer token. Set your authentication token in the configuration:
app:
authToken: "your-secure-token"
Or using an environment variable:
ONE_app__authToken="your-secure-token"
Generate a cryptographically secure token — such as with
openssl rand -hex 32
— and update this from the default for production
deployments.
API usage
Include the token in the Authorization
header for protected endpoints:
Authorization: Bearer your-secure-token
Example request:
curl -L '/api/organisation/v1' \
-H 'Accept: application/json' \
-H 'Authorization: Bearer <your-secure-token>'
Application server
These settings control your core application service - where it listens for connections and how other services find it.
Base URL
Set coreBaseUrl
to where your application is accessible from the outside.
Other services use this for API calls, and the frontend uses it for routing:
-
https://app.mycompany.com
-
http://localhost:3000
for local development
Server Configuration
The serverIp
and serverPort
control the internal network settings -
typically 0.0.0.0:3000
for both development and production.
Example configuration
Development:
app:
serverIp: "0.0.0.0"
serverPort: 3000
coreBaseUrl: "http://localhost:3000"
Production:
app:
serverIp: "0.0.0.0"
serverPort: 3000
coreBaseUrl: "https://app.mycompany.com"
Be sure to configure the corresponding security settings to match whether you're using HTTP (development) or HTTPS (production).
Required encryption keys
Encryption keys are required in several places in the Core configuration:
-
Any instance of
keyStorage.type="INTERNAL"
-
Any instance of
issuanceProtocol
that is a draft of OpenID4VCI
Keys must be a 32 byte hex-encoded value. Use openssl rand -hex 32
or another qualified tool to generate a cryptographically-secure key.
Example using environment variables:
ONE_keyStorage__INTERNAL__params__private__encryption="533c29f3942d824bc163dc91079d209566dff1b30679188d0f2317e6fa2c3bac"
ONE_issuanceProtocol__OPENID4VCI_DRAFT13__params__private__encryption="5874564335f8b0865df744d86c8e2a7c90f223474c52a692953e1182a2b3457a"
ONE_issuanceProtocol__OPENID4VCI_DRAFT13_SWIYU__params__private__encryption="aec38cbd853fe1ffaadbc7f6b25cb1701910ee4af39cfade18c4bd19e1c9fd13"
Security settings
Configure authentication, transport security, and endpoint access controls to protect your application in different environments.
Control HTTP vs. HTTPS transport
Set allowInsecureHttpTransport
to true
only for development environments
or controlled internal networks. Keep this false
in production to enforce
TLS/SSL encryption for all communication.
Restrict endpoint access by zone
Use these settings to control which API endpoints are available in different network zones. The Core has two kinds of endpoints:
-
/api
are "management" endpoints. These endpoints control internal resources such as organizations, cryptographic keys, credentials and proofs. SetenableManagementEndpoints
totrue
for internal zone deployments;false
for public zones. -
/ssi
are "external" endpoints. These endpoints include lower-level, protocol specific endpoints for credential exchange and public-facing resource retrieval. SetenableExternalEndpoints
totrue
for public- facing deployments.
Enable VC-API benchmarking (optional)
Turn on insecureVcApiEndpointsEnabled
only if you need /vc-api
endpoints
for benchmarking with canivc.com. Keep disabled otherwise.
Example configuration
Development:
app:
authToken: "dev-token-change-me"
allowInsecureHttpTransport: true
enableExternalEndpoints: true
enableManagementEndpoints: true
insecureVcApiEndpointsEnabled: false
Production (public zone):
app:
authToken: "your-secure-production-token"
allowInsecureHttpTransport: false
enableExternalEndpoints: true
enableManagementEndpoints: false
insecureVcApiEndpointsEnabled: false
Production (internal zone):
app:
authToken: "your-secure-production-token"
allowInsecureHttpTransport: false
enableExternalEndpoints: false
enableManagementEndpoints: true
insecureVcApiEndpointsEnabled: false
Database configuration
Configure a database using a MySQL connection string:
app:
databaseUrl: "mysql://core:{{DB-PASSWORD}}@localhost/core"
Debugging and error handling
Configure how your application handles errors and provides debugging information to help you troubleshoot issues effectively.
Hide error details in production
Set hideErrorResponseCause
to true
in production to prevent exposing
internal implementation details to clients. Keep it false
in development
so you can see full error information for debugging.
Enable JSON tracing for API debugging
Turn on traceJson
to get detailed request and response information in
JSON format. This helps when debugging API call flows, but generates
verbose output.
Control logging verbosity by component
Use traceLevel
to set different log levels for specific parts of your
applicatioin. Specify namespace=level pairs separated by commas:
traceLevel: "database=debug,auth=info,api=warn"
Set up error monitoring with Sentry
Configure sentryDsn
with your Sentry project's Data Source Name to
automatically track errors. Set sentryEnvironment
to label errors by
deployment environment — for example "production" or "staging".
Example configuration
Development:
app:
hideErrorResponseCause: false
traceJson: true
traceLevel: "database=debug,api=debug"
sentryEnvironment: "development"
Production:
app:
hideErrorResponseCause: true
traceJson: false
traceLevel: "database=warn,api=error"
sentryDsn: "https://your-sentry-dsn@sentry.io/project"
sentryEnvironment: "production"