Alexandria
Getting Started

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:

  1. CLI flag: --config <path>
  2. Current working directory: ./config.yaml
  3. Repository configuration path: ./config/config.yaml
  4. 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_port

2. 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 degraded

3. 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 .env

4. 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 listener

5. 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 types

Hierarchical 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/alexandria

Secrets 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:bootstrap writes generated secrets (Zitadel client credentials and the 32-byte session sealing key) to .env, which is loaded automatically by Taskfile.yaml and 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

On this page