Server Guide
Zann server provides the API, shared vaults, and token issuance for CLI access.
Overview
Section titled “Overview”- HTTP API for clients (desktop and CLI)
- Shared vault encryption and access control
- Service account tokens for automation
Running locally (Docker Compose)
Section titled “Running locally (Docker Compose)”git clone https://github.com/constXife/zanncd zanndocker compose up -dPrebuilt image
Section titled “Prebuilt image”docker pull constxife/zann-server:latestConfiguration
Section titled “Configuration”Start from config/config.example.yaml and supply required secrets via env:
ZANN_PASSWORD_PEPPERZANN_TOKEN_PEPPERZANN_SMK_FILEorserver.master_keyZANN_CONFIG_PATH
Environment variables
Section titled “Environment variables”Common env vars:
ZANN_CONFIG_PATH- path to the server config fileZANN_ENV- environment name (prodenables stricter output in health checks)ZANN_PASSWORD_PEPPER/ZANN_PASSWORD_PEPPER_FILEZANN_TOKEN_PEPPER/ZANN_TOKEN_PEPPER_FILEZANN_SMK/ZANN_SMK_FILE
Secret key files must be regular files without group or world permissions.
When a file is supplied directly through systemd LoadCredential=, the server
also accepts systemd’s 0440 copy, but only when it is an immediate child of
the current $CREDENTIALS_DIRECTORY; the same mode is rejected elsewhere.
Migrations
Section titled “Migrations”Run database migrations via the server CLI:
zann-server migrateTokens (service accounts)
Section titled “Tokens (service accounts)”Create and manage tokens for CLI automation:
zann-server token create ci-prod infra:/zann-server token listzann-server token revoke <token_id>token create takes <name> <vault:prefixes> [ops]. The prefixes are / for a
whole vault or a comma-separated list of subtrees, and ops defaults to read:
zann-server token create deployer infra:services/web read,writezann-server token create audit infra:services,platform read --ttl 30dValid ops are read, write, read_history, read_previous and rotate.
The rotate op grants coordinated rotation only and never force-abort. A prefix
matches a path exactly or anything beneath it, and a token holding only
prefixed rules cannot list the vault as a whole.
For server-side bootstrap flows, use the privileged provisioning helpers:
zann-server provision ensure-system-userzann-server provision ensure-vault --name Infrastructure --slug infrazann-server provision set-field --vault infra --path rlyeh/yogg/grafana --key value --kind password --value-file /run/secrets/grafana-client-secretzann-server provision retype-item --vault infra --path rlyeh/yogg/mcp --from-type-id secret --source-format typed-v1 --history-source-format typed-v1 --to-type-id kv --if-existszann-server provision ensure-token yogg-grafana infra:rlyeh/yogg/grafana read --write-token-file /run/secrets/yogg-zann-tokenprovision set-field accepts plaintext only through --value-file. The input
must be a regular UTF-8 file no larger than 256 KiB; its bytes, including
leading/trailing whitespace and a final newline, are preserved exactly.
New items use type secret by default. For that type, only the canonical
password field value is accepted and the configured default secret policy is
added automatically. Pass an explicit non-secret --type-id for generic typed
items.
provision retype-item is an explicit repair helper for legacy items whose
stored type no longer matches the server contract. It decrypts and validates
the current payload and every retained history payload in memory, rewrites only
their type metadata, and commits the item, history, and change record in one
transaction. No plaintext is printed or written to disk. Both source and target
types and the versioned current and retained-history encodings are required; a
mismatch fails closed. Use --source-format typed-v1 and
--history-source-format typed-v1 when both generations use the canonical
typed encoding. The explicit legacy-secret-v0 format is restricted to source
type secret and migrates the historical strict {value, policy, meta} shape.
It may be selected independently for retained history after a current payload
has already been rewritten. The current payload snapshot created by the command
always uses --source-format; only history that predates the command uses
--history-source-format. Neither historical encoding is recognized by normal
secret API reads. Use --if-exists only for idempotent bootstrap migrations
where an absent legacy item is expected.
Secret policies
Section titled “Secret policies”Values generated by the machine secrets API (ensure and rotation) follow a
named password policy:
GET /v1/vaults/{vault}/secrets lists secret metadata with bounded cursor
pagination and never decrypts or returns values. Use prefix, limit (1-100),
and the opaque cursor query parameters; prefix-scoped service accounts must
request a covered subtree.
secrets: policies_file: /etc/zann/secret-policies.yaml default_policy: "default"default_policy: defaultpolicies: default: length: 32 min_lowercase: 1 min_uppercase: 1 min_digits: 1Coordinated rotation windows are configured under rotation:
(lock_ttl_seconds, stale_retention_seconds, cleanup_interval_seconds,
max_versions). The API these settings govern is documented in the Machine
Secrets guide (docs/Machine-Secrets.md).
Health endpoint
Section titled “Health endpoint”The server exposes a health check at:
GET /healthIt includes component status (db, db_pool, kdf, oidc) and version info.
Security notes
Section titled “Security notes”- Prefer HTTPS and pin the server fingerprint in clients.
- Keep token scopes narrow and rotate regularly.