Skip to content

Architecture

Tommi Grönlund edited this page Oct 23, 2026 · 3 revisions

Documentation for the image tag 1.0.0-rc1. See Versions for the documentation of a release.

Architecture

Services

Qertum is a set of small services that share one data directory.

Service Role Listens on
webfrontend Blazor web UI; signs users in through OpenID Connect 8080
identityservice Built-in OpenID Connect provider (users, clients, roles). Replaceable by any OIDC provider 8081
apiservice REST API under /v1; also serves the CRL (/crl) and OCSP responder (/ocsp). The only service that creates or migrates the database schema 8082
acmeservice ACME server (RFC 8555) at /acme/* 8083
estservice EST server (RFC 7030) at /.well-known/est/*. Multi-container only. Always serves HTTPS 8084
queueconsumer Background worker: signs approved requests, finalizes revocations, auto-renews, delivers webhooks, refreshes the CRL. No port none
Redis Shared cache for the published CRL and ACME nonces. Safe to lose; rebuilt on demand 6379, internal

The qca command-line client talks to the API over REST, like the web UI does.

How requests flow

 browser ──► webfrontend ──┐
 qca CLI ──────────────────┼──► apiservice ──┐
                           │                 │
 ACME client ──► acmeservice ────────────────┼──► shared /data
 EST client  ──► estservice  ────────────────┤    (SQLite DB, CA keys,
                                             │     key ring, audit logs)
                    queueconsumer ───────────┘
  • The web UI and qca call the API with bearer tokens. The API validates the tokens locally against the identity provider's published signing keys (JWKS); it does not call the provider for every request.
  • ACME and EST clients authenticate by protocol (signed JWS requests for ACME; HTTP Basic or a client certificate for EST), not by bearer token.
  • API, ACME, EST and the queue consumer share one SQLite database and one encryption key ring. Approved requests are signed by the queue consumer.

The data volume

Everything that matters lives under one directory, /data inside the containers:

/data/certificate-requests.db       application database
/data/CaData/                       CA key material and certificates
/data/DataProtection-Keys/          encryption key ring (must persist)
/data/secret-storage/               key that wraps the key ring
/data/audit-logs/*.clef             tamper-evident audit log
/data/identity/                     identity provider store (users, clients, roles, keys)
/data/recovery/                     status files written by the backup scripts

Private keys are encrypted at rest with the key ring and are never returned by list endpoints. The CA signing key and the key ring are the two things to protect and back up.

Sizing and limits

  • Run exactly one of each service. Qertum is not scale-out: the services share one SQLite file and in-process channels. Redundancy comes from backups, not from running more copies.
  • Single container: one failure domain, intended for small installations and labs.
  • Multi container: still one host and one volume, but ACME and EST can be exposed without exposing the API, identity or web UI.

Choosing a deployment

Single container Multi container
Containers 1 (all services plus Redis inside) 7 (one per service, plus Redis)
ACME yes yes
EST no yes
Expose ACME without exposing the UI/API no (separate ports, one container) yes
Effort lowest moderate

Both use the same /data layout, so a volume can move from one to the other. See Multi Container.

Identity

The built-in identity service is fine for small installs. To use your own provider (Keycloak, Entra ID, and so on), point the API at its issuer URL and make its tokens carry the claims Qertum needs: iss, aud, sub, a name, roles and scopes. Requiring a second factor for the most sensitive operations (private-key download, CA changes, bulk operations) additionally needs acr and auth_time claims and an external provider that can emit them.

Clone this wiki locally