Configuration Reference
Complete reference for config.yaml, environment variable overrides with Viper, and secret management.
Configuration Reference
Alexandria implements the One Configuration Document pattern documented in ADR 0002. Rather than maintaining separate configuration documents per environment (laptop, Docker host, Kubernetes), the node reads a single baseline YAML file and overrides values through environment variables.
File Discovery & Structure Flexibility
The node automatically locates config.yaml by evaluating the following paths in order:
- CLI flag:
--config <path> - Current working directory:
./config.yaml - Repository configuration path:
./config/config.yaml - Production filesystem path:
/etc/alexandria/config.yaml
Standalone vs. Shared Dataspace Deployments
The loader supports two layouts interchangeably:
- Standalone Node: Sections sit directly at the root of
config.yaml(default in this repository). - Shared Dataspace Document: In multi-service deployments (where catalog, contracts, transfer, and gateway share a single specification), these identical sections can be nested under an
ssi_auth:key. The loader automatically detects and unpacks either structure without code changes.
Full config.yaml Reference
Below is the annotated reference of all configuration blocks and settings:
1. common_config
Network addresses, database persistence, and runtime flags.
common_config:
hosts:
http:
protocol: "https"
url: "alexandria.127.0.0.1.nip.io"
port: "8443" # Port external callers and Caddy proxy address
internal_port: "1234" # Cleartext HTTP port the Go process listens on behind Caddy
grpc: null
graphql: null
db:
db_type: Postgres # Relational database engine
url: "127.0.0.1"
port: "1500"
user: "alexandria"
password: "alexandria" # Development default; production passwords injected via env
name: "alexandria"
api:
version: "v1"
openapi_path: "./static/specs/openapi/merged_openapi.json"
connection:
is_local: true # Running in local workstation environment
is_prod: false
is_vault_real: false # Set to true when running with HashiCorp Vault
has_tls_proxy: true # Caddy terminates TLS in front of internal_port2. wallet_config
Cryptographic key custody and DID delegation.
wallet_config:
wallet: Fafnir # Pluggable backend: Fafnir | IdentityHub
api:
http:
protocol: "http"
url: "127.0.0.1"
port: "7003" # Port published by docker-compose for Fafnir
grpc: null
graphql: null
startup_link_timeout: "10s" # Grace period waiting for wallet before booting degraded3. auth_config
Authentication boundary, Zitadel OIDC settings, and session encryption.
auth_config:
enabled: true # Enforces authentication on all /api/v1 routes
issuer: "https://auth.127.0.0.1.nip.io:8443" # Must match Zitadel's discovery doc
internal_issuer: "" # Alternate container network address (e.g. http://zitadel:8080)
client_id: "" # Generated by Zitadel; injected dynamically via .env
client_secret: "" # Generated by Zitadel; injected dynamically via .env
audiences: [] # Expected audience; empty accepts any valid tenant token
scopes: ["openid", "profile", "email", "offline_access"]
redirect_url: "https://alexandria.127.0.0.1.nip.io:8443/api/v1/auth/callback"
app_url: "https://alexandria.127.0.0.1.nip.io:8443/"
post_logout_url: ""
introspect: "fallback" # never | fallback | always (validates JWT locally or queries IAM)
roles_claim: "urn:zitadel:iam:org:project:roles"
required_roles: [] # Mandatory roles required for all callers
jwks_refresh: "15m" # Frequency to refresh Zitadel public JWKS key set
http_timeout: "10s"
startup_discovery_timeout: "10s" # Boot grace period for IAM discovery
session:
name: "alexandria_session"
domain: ""
path: "/"
secure: true # Cookie requires HTTPS (enforced by Caddy)
same_site: "lax"
ttl: "12h"
key: "" # 32-byte session sealing key generated into .env4. observability
Telemetry, structured logging, and internal profiling.
observability:
log_level: "info" # debug | info | warn | error
log_format: "auto" # auto (colored text in terminal, JSON in pipes) | text | json
metrics: true # Exposes Prometheus metrics at /metrics
pprof: false # Exposes Go heap/cpu profiler at /debug/pprof
port: "2112" # Dedicated internal telemetry listener5. did_config & verify_req_config
DID format and verifiable presentation requirements.
did_config:
type: Jwk # Decentralized Identifier format (did:jwk)
verify_req_config:
is_cert_allowed: false
auto_approve_cert: false
vcs_requested:
- DataSpaceParticipant # Required Verifiable Credential typesHierarchical Environment Overrides (Viper)
Every value in config.yaml can be overridden at runtime without modifying the file. Viper builds the environment variable name using:
ALEXANDRIA_ + <DOTTED_PATH_IN_UPPERCASE> (dots replaced by underscores).
Common Examples:
# Point Alexandria to a different wallet port (e.g. IdentityHub or Eunomia):
ALEXANDRIA_WALLET_CONFIG_API_HTTP_PORT=8181 task dev
# Switch wallet provider dynamically:
ALEXANDRIA_WALLET_CONFIG_WALLET=IdentityHub task dev
# Disable authentication during headless test execution:
ALEXANDRIA_AUTH_CONFIG_ENABLED=false task dev
# Enable verbose debug logging:
ALEXANDRIA_OBSERVABILITY_LOG_LEVEL=debug task dev
# Override production database password:
ALEXANDRIA_COMMON_CONFIG_DB_PASSWORD=my_secure_prod_password ./bin/alexandriaSecrets vs. Committed Files (.env)
config/config.yaml is committed to git and must never contain secrets, private keys, or production passwords.
- In Local Development:
task auth:bootstrapwrites generated secrets (Zitadel client credentials and the 32-byte session sealing key) to.env, which is loaded automatically byTaskfile.yamland ignored by git. - In Production (Kubernetes/Docker): Secrets are mounted as environment variables or injected from secret managers (e.g., HashiCorp Vault or Kubernetes Secrets). EOF