Self-hosting
Run korva-vault as a shared service for your team. Docker Compose ships in-tree with optional Traefik for HTTPS. systemd unit for Linux servers, launchd plist for macOS dev machines.
Updated: 2026-04-30
The Vault is designed to run on your laptop by default, but nothing prevents you from running it as a shared service on a VPS, in Kubernetes, or behind your reverse proxy. This page documents the three official deployment shapes.
Docker (recommended for shared deployments)
docker pull ghcr.io/alcandev/korva-vault:latestdocker compose up -d vaultThe Dockerfile is multi-stage:
- Stage Beacon (Node 22-alpine): builds the React 19 SPA →
beacon/dist. - Stage Vault (Go 1.26-alpine): copies
distintovault/internal/ui/dist/and compiles with-tags embedui. - Stage Runtime (alpine 3.21): runs as
korva(uid 1001), volume mount at/data, exposes 7437.
A health check is wired in:
wget -qO- http://localhost:7437/healthz | grep -q '"status":"ok"' || exit 1(interval 30 s, timeout 5 s, retries 3, start period 10 s).
Docker Compose
The repo ships docker-compose.yml with two services:
services: vault: image: ghcr.io/alcandev/korva-vault:latest ports: ["7437:7437"] volumes: - korva-data:/data - ${KORVA_ADMIN_KEY_PATH}:/data/admin.key:ro # Optional Traefik for auto-HTTPS via Let's Encrypt # traefik: # ...volumes: korva-data:To run vault only:
docker compose up -d vaultTo run vault + the licensing server (operators only, profile teams):
KORVA_LICENSING_SECRET=change-me \KORVA_LICENSING_KEY_PEM="$(cat priv.pem)" \ docker compose --profile teams up -dTraefik for automatic HTTPS
The docker-compose.yml ships with Traefik labels commented out. Uncomment to expose the Vault at vault.yourcompany.com with auto-renewing Let’s Encrypt certificates:
labels: - "traefik.enable=true" - "traefik.http.routers.vault.rule=Host(`vault.yourcompany.com`)" - "traefik.http.routers.vault.entrypoints=websecure" - "traefik.http.routers.vault.tls.certresolver=letsencrypt" - "traefik.http.services.vault.loadbalancer.server.port=7437"Clients then point at the public host:
KORVA_VAULT_HOST=vault.yourcompany.com korva ...macOS LaunchAgent (developer machines)
cp scripts/korva-vault.plist ~/Library/LaunchAgents/dev.korva.vault.plistlaunchctl load ~/Library/LaunchAgents/dev.korva.vault.plist- Label:
dev.korva.vault RunAtLoad,KeepAliveon crash- Logs at
~/.korva/logs/vault.{log,error.log} - Restart throttle: 10 s
systemd user service (Linux servers)
mkdir -p ~/.config/systemd/usercp scripts/korva-vault.service ~/.config/systemd/user/systemctl --user daemon-reloadsystemctl --user enable --now korva-vault- Restart
on-failure(5 s delay), max 5 restarts in 60 s - Logs via journald:
journalctl --user -u korva-vault -f - Hardening:
NoNewPrivileges,PrivateTmp,ProtectSystem=strict,ProtectHome=read-only,ReadWritePaths=~/.korva
Required environment variables
| Variable | Default | Purpose |
|---|---|---|
KORVA_VAULT_HOST | 127.0.0.1 for local, 0.0.0.0 for shared | Bind address |
KORVA_VAULT_PORT | 7437 | Listen port |
KORVA_VAULT_DB | /data/vault.db (Docker) | SQLite path |
KORVA_CORS_ORIGIN | http://localhost:5173 | CORS origin allowed (Beacon dev) |
KORVA_EMAIL_API_KEY / KORVA_EMAIL_FROM | unset | Resend API for Teams invites |
KORVA_LICENSING_ENDPOINT | https://licensing.korva.dev | Licensing server URL |
KORVA_HIVE_ENDPOINT | https://hive.korva.dev | Hive cloud brain |
KORVA_HIVE_DISABLE | unset | Set to 1 to kill Hive worker |
Reverse proxy considerations
The Vault expects to terminate TLS at the proxy and receive cleartext HTTP/1.1 internally. CORS is configurable via KORVA_CORS_ORIGIN. Rate limit (120 req/min/IP) is enforced inside the Vault, so you don’t need a separate WAF rule for protection.
Observability
- Health probe:
GET /healthzreturns{"status":"ok"}. - Status snapshot:
GET /api/v1/status— version, uptime, license tier, total observations. - Metrics:
GET /api/v1/metrics— Prometheus format.
Wire any of those into your monitoring stack.
Where the data lives in Docker
The named volume korva-data maps to /data inside the container:
| Path | What |
|---|---|
/data/vault.db | SQLite database |
/data/admin.key | Admin credential (mode 0600, mounted read-only) |
/data/license.key | Active JWS license token |
Snapshot the volume daily for backup; SQLite supports hot backups if you use VACUUM INTO.