Deployment
Deploy IdentityScribe on Docker, Kubernetes, or bare metal. This page covers installation, verification, and platform-specific setup.
Instance topology
Section titled “Instance topology”Run one non-readonly instance that performs LDAP transcription, maintenance, and reconciliation. That instance owns all writes to the identity history.
You may run additional read-only replicas (readonly = true, or -r / SCRIBE_READONLY=true) behind a load balancer for query channels only — REST, GraphQL, LDAP read paths, and the Operator UI. Read-only replicas do not run sync, maintenance, or reconciliation tasks.
Do not run multiple non-readonly instances against the same database. Each writer would schedule maintenance and reconciliation independently, process LDAP changes in parallel, and rely on in-process locking that does not coordinate across JVMs — which can corrupt identity history without surfacing an error. Coordinated multi-writer deployment is not available in this release.
Quick install
Section titled “Quick install”-
Download the executable for your platform
-
Create
identity-scribe.conf:database {url = "jdbc:postgresql://localhost:5432/identity_scribe"user = "identity_scribe"password = ${DB_PASSWORD}}ldap {url = "ldap://your-ldap-server:389"bind-dn = "cn=admin,ou=sa,o=system"bind-password = ${LDAP_BIND_PASSWORD}}transcribes {user {ldap {base = "ou=users,o=data"filter = "(objectClass=Person)"}}}channels.rest.enabled = trueThe distribution includes three starter templates:
minimal.conf,recommended.conf, andproduction.conf. See Starter templates for what each one provides. -
Run:
./identity-scribe -
Verify traffic readiness:
curl http://localhost:8080/readyz
Docker Compose
Section titled “Docker Compose”services: identity-scribe: image: identity-scribe:latest environment: SCRIBE_LDAP_URL: "ldap://ldap:389" SCRIBE_LDAP_BIND_DN: "cn=admin,dc=example,dc=com" SCRIBE_LDAP_BIND_PASSWORD: "${LDAP_ADMIN_PASSWORD}" SCRIBE_DATABASE_URL: "jdbc:postgresql://postgres:5432/identity_scribe" SCRIBE_DATABASE_USER: "scribe" SCRIBE_DATABASE_PASSWORD: "${DB_PASSWORD}" SCRIBE_HTTP_PORT: "8080" SCRIBE_LOG_LEVEL: "info"Kubernetes
Section titled “Kubernetes”apiVersion: v1kind: ConfigMapmetadata: name: identity-scribe-configdata: SCRIBE_LDAP_URL: "ldap://ldap-service:389" SCRIBE_DATABASE_URL: "jdbc:postgresql://postgres-service:5432/identity_scribe" SCRIBE_HTTP_PORT: "8080" SCRIBE_LOG_LEVEL: "info" SCRIBE_CONCURRENCY: "16"---apiVersion: v1kind: Secretmetadata: name: identity-scribe-secretstype: OpaquestringData: SCRIBE_LDAP_BIND_DN: "cn=admin,dc=example,dc=com" SCRIBE_LDAP_BIND_PASSWORD: "secret" SCRIBE_DATABASE_USER: "scribe" SCRIBE_DATABASE_PASSWORD: "secret"---apiVersion: apps/v1kind: Deploymentmetadata: name: identity-scribespec: template: spec: containers: - name: identity-scribe envFrom: - configMapRef: name: identity-scribe-config - secretRef: name: identity-scribe-secrets # Add startup, liveness, and readiness probes — see the # "Kubernetes probes" section below for the full safe block # (default Kubernetes startup-probe thresholds restart the pod # before service initialization, database setup, and migrations finish).Keep container output on stdout and stderr. Kubernetes and your cluster logging pipeline should capture those streams,
apply retention, and export incident windows. SCRIBE_LOG_FILE only changes where the application logger stream writes;
it is not a complete process-output capture setting.
Kubernetes probes
Section titled “Kubernetes probes”Configure startup, liveness, and readiness probes for Kubernetes. The default example below uses the same socket as the
ConfigMap above: SCRIBE_HTTP_PORT=8080.
startupProbe: httpGet: path: /startedz port: 8080 initialDelaySeconds: 5 periodSeconds: 10 failureThreshold: 90 # 15min max for services + DB init
livenessProbe: httpGet: path: /livez port: 8080 initialDelaySeconds: 0 periodSeconds: 10 failureThreshold: 3
readinessProbe: httpGet: path: /readyz port: 8080 initialDelaySeconds: 0 periodSeconds: 5 failureThreshold: 1 successThreshold: 1If you want probes on a dedicated monitoring socket, configure and expose that socket first, then change the probe and convergence examples to the monitoring port:
http.sockets.monitoring { port = 8081 host = "0.0.0.0"}
monitoring.socket = "monitoring"Expose port 8081 only to the cluster paths that need health, metrics, and Observe access.
Use /readyz only for Kubernetes Service routing. It reports when the pod can safely receive traffic; it is not a "wait until every sync and index build is finished" gate.
Use /observe/convergence for deployment scripts or manual checks that must wait for all initial ingest and required index work to finish. Observe JSON endpoints require an operator session or accepted credential by default; the example below uses a bearer token. For trusted local evaluation only, you may opt out with monitoring.observe.auth.enabled=false.
until curl -fsS -H "Authorization: Bearer <token>" http://identity-scribe:8080/observe/convergence >/dev/null; do sleep 10doneThe startup probe has a high failureThreshold for service initialization, database connection setup, and migrations. Once the startup probe passes, liveness and readiness probes take over.
For the full list of health endpoints, see the Endpoints Reference.
Database setup
Section titled “Database setup”Database collation
Section titled “Database collation”Choose database ordering before the first IdentityScribe startup and keep it identical across production, standby, and restore environments.
For multilingual directories, use stable Unicode ordering so names and attributes sort consistently across platforms. For ASCII-only deployments where locale-aware ordering is not needed, byte-wise ordering can reduce comparison overhead.
Changing ordering after data exists requires a database rebuild and full resync; do not switch it in place.
Recommended multi-language production database:
CREATE DATABASE "identity_scribe" TEMPLATE template0 ENCODING = 'UTF8' LC_COLLATE = 'und-x-icu' LC_CTYPE = 'und-x-icu' CONNECTION LIMIT = -1;Performance-focused ASCII-only database:
CREATE DATABASE "identity_scribe" TEMPLATE template0 ENCODING = 'UTF8' LC_COLLATE = 'C' LC_CTYPE = 'C' CONNECTION LIMIT = -1;pg_stat_statements (optional)
Section titled “pg_stat_statements (optional)”For slow query analysis, enable the query statistics extension through your PostgreSQL configuration or managed-service control plane. Managed PostgreSQL services (AWS RDS, Azure, GCP) typically provide a UI setting for this.
Enabling it takes two ordered steps: add pg_stat_statements to shared_preload_libraries and restart, then enable the pg_stat_statements extension in the IdentityScribe database. In development and staging, set database.auto-create-query-stats-extension = true to have IdentityScribe enable it for you once the library is preloaded — it stays off in production by default.
Once enabled, IdentityScribe's monitoring UI and /observe/stats/queries show slow query statistics automatically. See Enabling query statistics for provider-specific instructions.
Startup banner
Section titled “Startup banner”When IdentityScribe starts, a banner displays runtime information:
identity-scribe v1.2.3 ready in 847ms
┃ Mode production┃ License ACME Corp — expires 2027-01-15 (365d)
┃ Config┃ /etc/scribe/identity-scribe.conf┃ environment variables
┃ Auth┃ Methods bearer┃ Anonymous deny┃ default https://auth.example.com
┃ Database postgresql://db.example.com:5432/scribe (ssl)┃ LDAP ldaps://dc01.example.com:636
┃ Transcribes┃ users ou=users,dc=example,dc=com (objectClass=person)┃ groups ou=groups,dc=example,dc=com (objectClass=group) [disabled]
┃ Channels┃ REST API http://localhost:8080/api┃ LDAP ldap://localhost:10389The sections shown depend on your configuration. Credentials are never displayed — database and LDAP URLs are sanitized to show only scheme, host, port, and path.
Command line options
Section titled “Command line options”usage: identity-scribe-c,--config <file> use config file (default: 'identity-scribe.conf')-d,--debug print debugging information-D <arg> key=value to set as property-f,--logfile <file> application logger output destination (default: System.out)-h,--help print this message-k,--license <file> use license file (default: 'identity-scribe.lic')-l,--loglevel <level> trace, debug, info, warn, error, fatal (default: info)-m,--mode <mode> set application mode: dev, development, local, test, production, staging, etc.-p,--printconfig print the resolved config and exit-q,--quiet be extra quiet-r,--readonly Readonly mode — only channels are started-s,--sync Force re-sync of all entries-t,--trace print tracing information-v,--version print the version information and exitSystem requirements
Section titled “System requirements”Operating system
Section titled “Operating system”- Linux: Ubuntu, Debian, RHEL, CentOS, Amazon Linux, Oracle Linux, SLES, OpenSUSE, Alpine
- macOS: Big Sur, Catalina, Mojave, Monterey
- Windows: Server 2019/2016/2012/2008 R2, Windows 11/10/8/7 SP1+
Database
Section titled “Database”- PostgreSQL 18 (primary) or 17 (supported)
- Supports plain, SSL, and mutual-SSL connections
CPU compatibility
Section titled “CPU compatibility”The distribution binary is built for compatibility mode: it runs on a wide range of x64 and ARM64 CPUs. If you see illegal instruction or similar errors on older hardware, see CPU Compatibility.
Resources
Section titled “Resources”- Memory: Uses up to 80% of available physical memory (4 GB RAM = 3.2 GB max)
- CPU: I/O-bound; multiple cores benefit parallel processing
Verification
Section titled “Verification”After starting, verify the deployment:
# Readinesscurl -fsS http://localhost:8080/readyz
# Strict ingest/index convergencecurl -s -H "Authorization: Bearer <token>" http://localhost:8080/observe/convergence | jq
# Metrics availablecurl -fsS http://localhost:8080/metrics | head
# System healthcurl -fsS -H "Authorization: Bearer <token>" http://localhost:8080/observe/doctor | jqRelated
Section titled “Related”- Configuration — HOCON, env vars, inheritance patterns
- API & Networking — HTTP sockets, TLS, named sockets
- Health and Monitoring — Health checks, dashboards, monitoring bundle
- Signals — Golden signals and error classification
- PromQL Recipes — Alert queries and dashboards
- Upgrading — Version migration and PostgreSQL upgrade paths