Self-host guide · ~5 minutes

Self-host OpenVault in 5 minutes

Clone the repo, set a handful of env vars, and bring up a TLS-terminated instance at your own domain. Your database, your encryption keys, no license key, no phone-home.

Prerequisites

Before you start, make sure you have:

  • A Linux server. Ubuntu 22.04+ or Debian 12+ recommended. 2 vCPU / 2 GB RAM minimum; 4 GB+ for production.
  • A public IP with ports 80 and 443 open.
  • A domain name with an A record pointing at the server (e.g. vault.yourcompany.com). A .local hostname is fine for offline/lab installs.
  • Docker 24+ with Compose v2.
  • A Supabase project for auth, Postgres Data API, and storage. You'll need: project URL, anon (publishable) key, service-role key, and project ref.
curl -fsSL https://get.docker.com | sudo sh
sudo usermod -aG docker $USER && newgrp docker
docker compose version   # must print v2.x

Clone the repository

Pull the source onto your server:

git clone https://github.com/abrotechit/secure-vault-enterprise.git openvault
cd openvault

Pin to a tagged release in production: git checkout v1.0.0 (see the Releases page).

Configure your environment

Copy the example file and fill in the required values. The VITE_* trio must match the server-side Supabase values — Vite inlines them into the browser bundle at build time.

cp .env.example .env
# then edit .env
# Database
POSTGRES_PASSWORD=$(openssl rand -base64 32)

# Supabase (server-side)
SUPABASE_URL=https://abcd1234.supabase.co
SUPABASE_PUBLISHABLE_KEY=eyJhbGciOi...
SUPABASE_SERVICE_ROLE_KEY=eyJhbGciOi...

# Supabase (baked into the browser bundle)
VITE_SUPABASE_URL=https://abcd1234.supabase.co
VITE_SUPABASE_PUBLISHABLE_KEY=eyJhbGciOi...
VITE_SUPABASE_PROJECT_ID=abcd1234

# Encryption — 32 random bytes
KEK_DEMO_SECRET=$(openssl rand -base64 32)

# Public URL
APP_URL=https://vault.yourcompany.com
APP_DOMAIN=vault.yourcompany.com

KEK_DEMO_SECRET is unrecoverable. If you lose it, every vault becomes permanently unreadable. Back it up offline before storing real secrets, and move custody to Azure Key Vault for production (see step 11).

Quick install (recommended)

The bundled script handles env generation, TLS, and bootstrap:

curl -Lso openvault.sh \
  https://raw.githubusercontent.com/abrotechit/secure-vault-enterprise/main/openvault.sh
chmod +x openvault.sh

sudo ./openvault.sh install
sudo ./openvault.sh start

install prompts you for:

PromptWhat to enter
Domainvault.yourcompany.com (or vault.local for offline)
Admin emailUsed for Let's Encrypt and as suggested first admin
Let's Encrypt?yes for public domains, no for .local / bare IP
Supabase URL / keysPaste the four values from step 1

Manual install

If you prefer to drive Docker Compose yourself:

# Build the web image (Vite bakes VITE_* into the bundle)
docker compose build

# Start everything
docker compose up -d

# First-time database bootstrap (migrations + seed)
./scripts/bootstrap.sh

Verify the install

docker compose ps
# all services should be "running" / "healthy"

curl -k https://localhost/api/public/health
# → {"status":"ok","t":"2026-..."}

First run — create your organization

  1. Open https://your-domain and click Create one.
  2. Provide a work email on a corporate domain (Gmail, Outlook, Yahoo, Proton are blocked by design).
  3. Pick an organization name and slug, then set a master password. This derives your account encryption key and cannot be recovered.
  4. You become the owner. Your email domain is auto-claimed for the org.
  5. Invite teammates from Admin → Users. Invites are limited to your organization's domain or its subdomains.

Day-to-day operations

CommandWhat it does
./openvault.sh startdocker compose up -d
./openvault.sh stopStop containers, keep data
./openvault.sh restartRestart all services
./openvault.sh statusShow service health
./openvault.sh logs [service]Tail logs (web, caddy, postgres, redis)
./openvault.sh updategit pull + rebuild + restart
./openvault.sh rebuildRe-render Caddyfile after .env edits
./openvault.sh uninstallStop containers; type 'wipe' to drop data

Backups

Daily Postgres dump (run via cron):

docker compose exec -T postgres \
  pg_dump -U openvault openvault \
  | gzip > /backup/openvault-$(date +%F).sql.gz

Back up all three — losing any one leaves the others useless:

  • postgres_data volume — vault ciphertext, audit log, accounts.
  • KEK_DEMO_SECRET — the key that unwraps every vault DEK. Store offline (paper safe, hardware token, separate password manager).
  • caddy_data volume — TLS certificates (optional; Caddy will re-issue if missing).

Upgrading

cd /path/to/openvault
sudo ./openvault.sh update

This runs git pull, rebuilds the web image, applies new database migrations on boot, and restarts the stack. Tag a release first and review the changelog if you pin to versions.

Production hardening

  • Move the KEK to Azure Key Vault. Replace local KEK_DEMO_SECRET custody with HSM-backed wrap/unwrap. See docs/AZURE_KEY_VAULT.md in the repo.
  • Enable SAML SSO from Admin → SAML. JIT provisioning + group-to-role mapping included.
  • Configure SCIM for automated user provisioning. See docs/SCIM.md.
  • Tighten CSP. If you add routes using Argon2 WebAssembly, edit the @crypto matcher in scripts/install-templates/Caddyfile.tmpl, then ./openvault.sh rebuild && ./openvault.sh restart.
  • Cloudflare proxy. Use "DNS only" (grey cloud) for the initial Let's Encrypt challenge, then switch to proxied.

Troubleshooting

SymptomFix
docker compose build fails with VITE_SUPABASE_URL must be setRun ./openvault.sh install (or set all four VITE_* values in .env), then rebuild.
TLS never provisions / self-signed warning on a public domainVerify ports 80/443 are open AND the A record points here. Then ./openvault.sh restart.
401 Unauthorized on server functions / SCIM / SSOSUPABASE_SERVICE_ROLE_KEY is missing or wrong in .env. Fix it, then restart.
Unlock page complains about 'wasm-unsafe-eval' in consoleCSP template drift. ./openvault.sh rebuild && ./openvault.sh restart.
Signup rejects email as 'not a corporate domain'Free providers are blocked by design. Use a domain you own.
Invited teammate gets 'domain not allowed'Invites must match the inviter's organization domain or a subdomain.
Lost the KEK_DEMO_SECRETAll vaults are unreadable. No recovery. Restore from the offline backup.
Need live logs./openvault.sh logs web (or caddy, postgres)

Where to go next

The repo ships deeper docs for each subsystem: