vitrinka.docs

Configuration

Deployment settings, defaults and where administrators can override them.

How configuration works

The server reads deployment defaults from environment variables at startup; a change needs a restart. Some settings can be overridden after startup: saved SMTP configuration applies to the next email, and workspace AI settings take precedence over the deployment backend. Validation varies by setting; use the values in the reference and check startup logs after changes.

The configuration reference lists registered variables, defaults and meanings. This page covers the main deployment choices.

Core

VariableDefaultNotes
VITRINKA_ADDR:8080Listen address.
BASE_URLhttp://127.0.0.1:8080The public URL; must be https for cookies to carry Secure and for HSTS to ship.
DATA_DIR./dataThe control database, every workspace database, filesystem blobs and the blob cache.
VITRINKA_MASTER_KEY—Required with VITRINKA_KEYS_PROVIDER=env. 64 hex chars; seals application secrets and doubles as the deployment key when VITRINKA_KEK is unset. Under openbao, set it for one boot so it is adopted into the key store, then remove it.
VITRINKA_KEKfalls back to the master key64 hex chars; the key every workspace data key is wrapped under — Encryption.
VITRINKA_SEAL_STRICToffon refuses legacy plaintext rows and objects instead of reading them through — flip after seal-existing -verify passes.
MAX_SET_MB200Request body limit and unpacked-size limit per set.
VITRINKA_SESSION_TTL720hAbsolute session lifetime, enforced server-side. The enterprise bundle's compose sets 12h.
VITRINKA_SESSION_IDLE0Idle timeout; 0 disables it, anything set must be at least 5m and shorter than the lifetime. The enterprise bundle's compose sets 30m.
VITRINKA_WAITLISTunset1 holds every new account until it is approved in /admin; a pending invitation counts as approval, and existing accounts always sign in — the first admin.
VITRINKA_OPS_ORGunsetSlug of the organization that runs the install. Its admins — and platform admins, always — manage the deployment-wide settings: the mailer, SSO email-domain claims, turning forced SSO on while claims are on, deployment-managed SSO connections, and the trackers, AI backends and AI endpoints that may reach your internal network (Outbound targets). Unset means platform admins alone. It grants no data access — the first admin.
VITRINKA_SSO_DOMAINSoffon lets organizations claim email domains for home-realm routing and per-domain forced SSO — SSO.
VITRINKA_SSO_PRIVATE_NETWORKSunsetComma-separated CIDRs an SSO connection may reach besides public addresses, for an identity provider on your own network; only a deployment-managed connection reaches them — SSO.
VITRINKA_SSO_CAunsetA private CA for your identity provider's certificate, as a PEM file path or the PEM text, trusted beside the system roots by the SSO client alone — SSO.
VITRINKA_BREAK_GLASSownersWho may take the forced-SSO emergency door ?local=1: off, owners (of the forcing organization) or all — SSO.
VITRINKA_TRUSTED_PROXIESunsetComma-separated CIDRs of your reverse proxy, whose X-Real-Ip the rate limiter and every audit row trust for the client address (a bare address needs its /32); loopback is always trusted, and from any other peer the header is ignored and the connection's own address is used — Installing.
AIR_GAPunset1 blanks every integration that reaches the public internet, turns link-card previews off and confines the admin-configured targets that are left — issue trackers, a workspace AI backend, an organization's AI endpoint — to internal addresses, and only those deployment authority saved; SSO reaches only the internal ranges VITRINKA_SSO_PRIVATE_NETWORKS lists, and MCP clients register without a client-ID metadata document; S3, SMTP, the capture and transcription sidecars and the metrics listener stay reachable — Air-gapped deployment.
LICENSE_FILEDATA_DIR/license.jsonWhere the server looks for the vendor-signed licence. The enterprise bundle's compose sets /run/license/license.json. No file means the unrestricted evaluation posture; a file that is present but unusable refuses the boot — Licensing.

Blob storage

VariableDefaultNotes
BLOB_BACKENDfsfs or s3.
S3_ENDPOINT S3_REGION S3_BUCKET—Required if BLOB_BACKEND=s3. The bucket is created if missing and validated at startup.
S3_ACCESS_KEY_ID S3_SECRET_ACCESS_KEY—Credentials for that bucket.
VITRINKA_S3_SSEaes256Server-side encryption requested from the bucket: aes256, kms:<key id> or off. Objects are client-side ciphertext either way.
BLOB_CACHE_MAX_GB20S3 only: a read-through cache under DATA_DIR/blobcache, pre-warmed at boot, oldest-first eviction. 0 disables it.
CLAMD_ADDRunsetA clamd address turns on fail-closed malware scanning of every blob write — Storage.

Key store and audit export

Both are off by default and make no outbound call until you turn them on — the full contract, the boot check, the migration and the failure behaviour are in Encryption and keys.

VariableDefaultNotes
VITRINKA_KEYS_PROVIDERenvenv keeps the KEK in the environment; openbao holds it in an OpenBao transit key the server only ever talks to.
VITRINKA_OPENBAO_ADDR VITRINKA_OPENBAO_MOUNT VITRINKA_OPENBAO_KEY VITRINKA_OPENBAO_ROLE_ID VITRINKA_OPENBAO_SECRET_ID VITRINKA_OPENBAO_CAtransit · vitrinka-kekThe transit engine: address, mount, key name, AppRole credential and a private CA (a PEM file path or the PEM text itself, starting with -----BEGIN). VITRINKA_OPENBAO_TOKEN is the development-only alternative to AppRole.
VITRINKA_DEK_REVERIFY15mHow often every open workspace's data key is re-verified against the key store; a revoked key stops serving within this window.
VITRINKA_AUDIT_EXPORToffdir or s3 exports the audit trail every VITRINKA_AUDIT_EXPORT_EVERY (5m) as a hash-chained, signed JSONL stream — Audit export.
VITRINKA_AUDIT_EXPORT_DIRDATA_DIR/audit-wormThe write-once directory for dir — the air-gapped choice.
VITRINKA_AUDIT_EXPORT_S3_ENDPOINT VITRINKA_AUDIT_EXPORT_S3_REGION VITRINKA_AUDIT_EXPORT_S3_BUCKET VITRINKA_AUDIT_EXPORT_S3_PREFIX VITRINKA_AUDIT_EXPORT_S3_ACCESS_KEY_ID VITRINKA_AUDIT_EXPORT_S3_SECRET_ACCESS_KEY—The object-lock bucket for s3 and a put-only credential.
VITRINKA_AUDIT_EXPORT_RETAIN_DAYSunsets3 only: Object Lock retention stamped on each batch; unset keeps every batch. Ignored by dir.

Retention, headers and the share host

VariableDefaultNotes
VITRINKA_RETENTION_GRACE720hHow long a deleted session stays recoverable before the sweeper purges it.
VITRINKA_RETENTION_SWEEP1hHow often the sweeper runs; never under 1m.
VITRINKA_CSPreport-onlyenforce promotes the full content security policy from reporting to enforcement — Headers and CSP.
VITRINKA_FRAME_ANCESTORSunsetOrigins allowed to embed workspace pages; empty means 'self'.
VITRINKA_SHARE_ORIGINunsetA dedicated host for share links that never accepts sessions or tokens.
VITRINKA_RECORDER_FULL_FIDELITYdenyallow lets a workspace's recorder policy switch redaction off entirely — a self-host escape hatch — Full fidelity.
VITRINKA_REFERENCE_ORIGINSunsetSpace-separated exact HTTPS origins that may read private reference collections with the browser session; applies only to /api/v1/reference-library.

Plans and metering

VariableDefaultNotes
VITRINKA_METEREDunset1 enforces each organization's plan — storage, seats, boards per workspace — as set in /admin; a new organization starts on Free. Unset, and without Stripe billing, every organization runs on Enterprise limits: 500 GiB of pooled storage, unlimited seats and 250,000 active boards per workspace. The stored plan is kept and applies again once metering is on. Any other value refuses the boot.
STRIPE_API_KEY STRIPE_WEBHOOK_SECRET STRIPE_PRICE_STARTER STRIPE_PRICE_PRO STRIPE_PRICE_TEAM—All five set ⇒ billing active, and plans are metered too. A partial set, or a placeholder value, refuses the boot. All unset ⇒ billing routes are unmounted. STRIPE_PACKS optionally lists prepaid AI packs.

AIR_GAP=1 blanks Stripe, so an air-gapped install meters plans only with VITRINKA_METERED=1. The boot log says which applies: metering on: VITRINKA_METERED, metering on: Stripe configured or metering off: self-hosted.

Observability

Every signal but the process log is off until you point it somewhere, and nothing leaves the host on its own.

VariableDefaultNotes
VITRINKA_LOG_FORMATtextThe process log on stderr; the enterprise bundle's compose sets json for a log shipper. Either way only opaque ids reach it — never an email, name, IP, user agent, query string, header or payload.
VITRINKA_LOG_LEVELinfodebug, info, warn or error.
VITRINKA_METRICS_ADDRunset (off)A second, metrics-only listener serving Prometheus /metrics (e.g. :9464). It sits outside the licence gate and the session layer, so keep it on your private network and never publish it through the proxy — the bundle's compose maps no port for it.
OTEL_EXPORTER_OTLP_ENDPOINTunset (off)OTLP/HTTP endpoint that receives traces (e.g. http://otel-collector:4318).
VITRINKA_TRACE_SAMPLE0.1Head sampling ratio from 0 to 1, decided per request before anything is known about it. A collector's tail policy chooses only among the exported share, so keeping every slow or failed trace needs 1.
SENTRY_DSNunset (off)Error reports from the server and, through the same-origin /api/v1/telemetry tunnel, from the browser — browsers never talk to Sentry themselves. Headers, cookies, bodies and IPs are scrubbed before anything is sent, and the user is an opaque id. Point it at your own Sentry.

AIR_GAP=1 blanks SENTRY_DSN and OTEL_EXPORTER_OTLP_ENDPOINT at boot. The metrics listener stays, because it only answers scrapes on your own network.

Integrations

Configure only the integrations you need. Some also require workspace or project settings — see Connectors.

VariableNotes
AI_BACKEND_URL AI_BACKEND_TOKENThe AI backend behind the run view and chat; the token is sent upstream as a bearer. Legacy spellings EVE_API_URL / EVE_API_TOKEN still work.
EVE_URL EVE_SECRETThe AI channel for board mentions and review passes, over HMAC-signed pushes.
GITHUB_APP_ID GITHUB_APP_PRIVATE_KEY GITHUB_APP_SLUG GITHUB_APP_CLIENT_ID GITHUB_APP_CLIENT_SECRET GITHUB_WEBHOOK_SECRETThe GitHub App: commit pills, per-workspace repository connect, pull-request webhooks, sign in with GitHub (GITHUB_LOGIN=1).
PLANE_API_URL PLANE_API_TOKEN PLANE_WORKSPACEAll three set ⇒ Plane integration active: one upserted comment per set on the referenced issue.
VITRINKA_CAPTURE_URL VITRINKA_CAPTURE_TOKENA browserless/chrome screenshot sidecar you run (e.g. http://capture:3000) for link-card previews, press renders, document PDF export, diagram PNG export and the stills of web-recorder sessions (replayed from the recorded DOM stream, with no network access). Unset, link cards fall back to og:image metadata, and a web-recorder session's board fails to build until it is set. A link preview hands it only a page on a host vetted as public, and discards a shot whose page loaded a response from a non-public address — what leaves the host.
VITRINKA_STT_URLThe whisper.cpp sidecar the bundle's stt profile runs (http://vitrinka-stt:8080) for server-side meeting transcription — Connectors.
VITRINKA_LISTENER_TTLDefault 90. Seconds a listener lease survives between heartbeats before its in-flight work reverts.

Mail

One mailer per install, set in Settings → Organization → Email, from the CLI (vitrinka admin smtp) or from the environment: as SMTP (SMTP_HOST, SMTP_PORT, SMTP_TLS, SMTP_USER, SMTP_PASSWORD, SMTP_CA_FILE, EMAIL_FROM — authentication over cleartext is refused at boot) or as RESEND_API_KEY. A saved configuration wins over the environment, and only deployment authority saves one — Mail and notifications. Web push needs VAPID_PUBLIC_KEY and VAPID_PRIVATE_KEY; set VAPID_SUBSCRIBER to your own mailto:, because the default is a placeholder.

vitrinka admin smtp --help

On this page