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+ (
!overrideneeds 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.shon a client box. It defaults to the demo env
file, which ships an emptyLICENSE_PUBLIC_KEY(every module goes dark) and a
localhostbase URL (breaks signing links + passkeys).update-prod.shpins the prod
env + overlay and refuses to run without a license key and anhttps://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=developmenton a public box — it enablesdev-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.