think
16px
820px

Obscura — Client Deployment Quickstart

The short, repeatable path to stand up Obscura for a new client. It automates the
error-prone setup with one script and keeps every later update on a single safe command.
For the fully-worked two-VM reference (backups, DR, firewall hardening) see
DEPLOYMENT.md; this page is the simple happy path.

What you deploy

One Docker Compose stack (obscura + postgres + minio + sidecars). Two shapes:

  • Single box — the box terminates HTTPS itself (nginx + certbot on the host).
  • Box behind an edge — an external reverse proxy (another host's nginx) terminates TLS
    and forwards to the box on :8091. Then add a tiny client-local overlay (see step 5).

Sizing for ~35 users, full features, AI outsourced to OpenAI: 8 vCPU / 32 GB / 300 GB
SSD
. Drop the local embedding sidecar (EMBED_PROVIDER=openai) to save ~5 GB RAM.

Prerequisites

  • Ubuntu host with Docker Engine + Compose v2.24+ (!override needs 2.24+), openssl, git.
  • A public DNS name → the box (or → the edge that fronts it), and an IdP (Casdoor or any
    OIDC) with a client registered. You'll set its redirect URI = <APP_BASE_URL>/auth/callback.
  • An OpenAI API key (for AI chat) — optional; the app runs without it, AI just stays off.

Steps

# 1. Get the code
git clone git@github.com:Virtue-Digital-Indonesia/obscura.git ~/obscura && cd ~/obscura

# 2. Bootstrap: generates secrets (blob key, stego key) correctly, scaffolds deploy/prod.env,
#    and sets the permissions the distroless container needs. Prompts for anything you omit.
./deploy/bootstrap-client.sh \
  --app-base-url https://dms.client.example \
  --admin-email  admin@client.example \
  --oidc-issuer  https://sso.client.example \
  --oidc-client-id  <client-id> \
  --oidc-client-secret <client-secret>      # or omit → prompted (hidden)
  # optional: --openai-key sk-...  --license-file <path>  --license-public-key <b64>

3. License (premium modules). Without a signed license the box boots core-only
(documents, workflow, RBAC, retention, in-house e-signing) — fine to go live, premium
modules (AI, semantic, watermarking, correspondence) light up later. To enable them:

cd go && go run ./cmd/licensegen -gen-key           # keep the PRIVATE key safe
go run ./cmd/licensegen -private-key '<PRIV>' -customer '<Org>' \
  -modules correspondence,watermarking,ai,esign,semantic -seats 40 -expiry 2027-12-31 \
  -out ~/obscura/deploy/secrets/obscura.license.json
# then add LICENSE_PUBLIC_KEY=<PUB> to deploy/prod.env  (it is BAKED IN at build time)

4. First bring-up.

docker compose -f deploy/docker-compose.yml -f deploy/docker-compose.prod.yml \
  --env-file deploy/prod.env up -d --build          # (or pass --up to bootstrap-client.sh)

5. Expose it.
- Single box: sudo certbot --nginx -d dms.client.example after copying
deploy/nginx/obscura.conf.example. The prod overlay binds every port to 127.0.0.1;
point nginx at http://127.0.0.1:8091.
- Behind an external edge: the web port must reach the edge, so add
deploy/docker-compose.<host>.yml with web: ports: !override ["8091:80"] and restrict
:8091 to the edge's IP with ufw. update-prod.sh picks up that overlay automatically.

6. Deploy / update — always the wrapper.

./deploy/update-prod.sh --yes        # snapshot → build → migrate → health-gate → auto-rollback

Never run bare ./deploy/update.sh on a client box. It defaults to the demo env
file, which ships an empty LICENSE_PUBLIC_KEY (every module goes dark) and a
localhost base URL (breaks signing links + passkeys). update-prod.sh pins the prod
env + overlay and refuses to run without a license key and an https:// base URL.

7. First admin + verify. Open <APP_BASE_URL>, sign in via SSO as the admin email —
it receives admin on first login. Then:

curl -s <APP_BASE_URL>/api/v1/version        # {"version":"…","commit":"…"}
curl -s <APP_BASE_URL>/api/v1/auth/methods   # modes:["oidc"], oidc block present

Updating later

git pull && ./deploy/update-prod.sh --yes. Migrations are forward-only and run on boot;
if the new build isn't healthy, images roll back automatically and the DB snapshot to
restore from is printed. Env-only changes (e.g. rotating the OpenAI key) don't need a
rebuild — edit deploy/prod.env then ./deploy/update-prod.sh --yes --app-only.

Non-negotiables (why the box stays safe on a public IP)

  • Never OBSCURA_ENV=development on a public box — it enables dev-login, which mints
    an admin session for anyone (full auth bypass). Production mode is the default.
  • Never docker compose down -v — it wipes the postgres + minio volumes.
  • Keep the OIDC secret, blob key, stego key, and license out of git (they live in
    deploy/secrets/, gitignored). Generate a fresh stego + blob key per client — never
    reuse the demo defaults.