This repository has been archived on 2026-03-27. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
drive/docs/deployment.md
Sienna Meridian Satterwhite 58237d9e44 Initial commit — Drive, an S3 file browser with WOPI editing
Lightweight replacement for the upstream La Suite Numérique drive
(Django/Celery/Next.js) built as a single Deno binary.

Server (Deno + Hono):
- S3 file operations via AWS SigV4 (no SDK) with pre-signed URLs
- WOPI host for Collabora Online (CheckFileInfo, GetFile, PutFile, locks)
- Ory Kratos session auth + CSRF protection
- Ory Keto permission model (OPL namespaces, not yet wired to routes)
- PostgreSQL metadata with recursive folder sizes
- S3 backfill API for registering files uploaded outside the UI
- OpenTelemetry tracing + metrics (opt-in via OTEL_ENABLED)

Frontend (React 19 + Cunningham v4 + react-aria):
- File browser with GridList, keyboard nav, multi-select
- Collabora editor iframe (full-screen, form POST, postMessage)
- Profile menu, waffle menu, drag-drop upload, asset type badges
- La Suite integration service theming (runtime CSS)

Testing (549 tests):
- 235 server unit tests (Deno) — 90%+ coverage
- 278 UI unit tests (Vitest) — 90%+ coverage
- 11 E2E tests (Playwright)
- 12 integration service tests (Playwright)
- 13 WOPI integration tests (Playwright + Docker Compose + Collabora)

MIT licensed.
2026-03-25 18:28:37 +00:00

6.9 KiB

Deployment

How Drive runs in production as part of the SBBB Kubernetes stack.


Where This Fits

Drive replaces the upstream suitenumerique/drive Helm chart in the SBBB stack. Same role, one binary instead of Django + Celery + Redis queues + Next.js.

Sits alongside the other La Suite apps and shares the Ory identity stack (Kratos + Hydra) for auth.


The Binary

deno task build

Produces a single driver binary via deno compile:

deno compile --allow-net --allow-read --allow-env --include ui/dist -o driver main.ts

Bundles:

  • Deno runtime
  • All server TypeScript (compiled to JS)
  • The entire ui/dist directory (React SPA)

No Node.js, no npm, no node_modules at runtime. Copy the binary into a container and run it. That's the deployment.


Environment Variables

Everything is configured via environment variables. No config files.

Variable Default Required Description
PORT 3000 No Server listen port
PUBLIC_URL http://localhost:3000 Yes Public-facing URL. Used in WOPI callback URLs, redirects, and CSRF. Must be the URL users see in their browser.
DATABASE_URL postgres://driver:driver@localhost:5432/driver_db Yes PostgreSQL connection string
SEAWEEDFS_S3_URL http://seaweedfs-filer.storage.svc.cluster.local:8333 No S3 endpoint
SEAWEEDFS_ACCESS_KEY (empty) No S3 access key (empty = unauthenticated)
SEAWEEDFS_SECRET_KEY (empty) No S3 secret key
S3_BUCKET sunbeam-driver No S3 bucket name
S3_REGION us-east-1 No S3 region for signing
VALKEY_URL redis://localhost:6379/2 No Valkey/Redis URL for WOPI locks. Falls back to in-memory if unavailable. Set to your Valkey cluster URL in production.
KRATOS_PUBLIC_URL http://kratos-public.ory.svc.cluster.local:80 No Kratos public API for session validation
KETO_READ_URL http://keto-read.ory.svc.cluster.local:4466 No Keto read API for permission checks
KETO_WRITE_URL http://keto-write.ory.svc.cluster.local:4467 No Keto write API for tuple management
COLLABORA_URL http://collabora.lasuite.svc.cluster.local:9980 No Collabora Online for WOPI discovery
WOPI_JWT_SECRET dev-wopi-secret-change-in-production Yes HMAC secret for WOPI access tokens. Change this in production.
CSRF_COOKIE_SECRET dev-secret-change-in-production Yes HMAC secret for CSRF double-submit cookies. Change this in production.
DRIVER_TEST_MODE (unset) No Set to 1 to bypass auth. Never set this in production.

Health Check

GET /health

Returns:

{ "ok": true, "time": "2026-03-25T10:30:00.000Z" }

No auth required. Use this for Kubernetes liveness and readiness probes:

livenessProbe:
  httpGet:
    path: /health
    port: 3000
  initialDelaySeconds: 5
  periodSeconds: 10
readinessProbe:
  httpGet:
    path: /health
    port: 3000
  initialDelaySeconds: 3
  periodSeconds: 5

Collabora Configuration

Collabora needs to know which hosts can make WOPI callbacks. This is the aliasgroup1 env var on the Collabora deployment. Get this wrong and Collabora will reject every callback with a "Not allowed" error.

# Collabora environment
aliasgroup1: "https://drive\\.example\\.com"

The value is a regex — dots must be escaped. Multiple hosts:

aliasgroup1: "https://drive\\.example\\.com|https://drive\\.staging\\.example\\.com"

In the Docker Compose test stack, this is:

aliasgroup1: "http://host\\.docker\\.internal:3200"

OIDC Client Setup

Drive authenticates users via Ory Kratos sessions. For OIDC flows, you need a client registered in Ory Hydra.

Client credentials go in a Kubernetes secret:

apiVersion: v1
kind: Secret
metadata:
  name: oidc-drive
type: Opaque
stringData:
  client-id: "drive"
  client-secret: "your-secret-here"

The Kratos identity schema needs standard OIDC claims (email, name). Drive reads from session traits:

const givenName = traits.given_name ?? traits.name?.first ?? "";
const familyName = traits.family_name ?? traits.name?.last ?? "";

Supports both OIDC-standard (given_name/family_name) and legacy (name.first/name.last) formats. You probably won't need to think about this.


SeaweedFS Bucket

Create the bucket before first deploy (or don't — SeaweedFS creates buckets on first write with default config):

# Using AWS CLI pointed at SeaweedFS
aws --endpoint-url http://seaweedfs:8333 s3 mb s3://sunbeam-driver

Bucket name defaults to sunbeam-driver, configurable via S3_BUCKET.


Keto Deployment

Keto is new to the SBBB stack — Drive introduced it. You need to deploy:

  1. Keto server with read (4466) and write (4467) APIs
  2. OPL namespaces from keto/namespaces.ts loaded at deploy time

The namespace file defines the permission model (User, Group, Bucket, Folder, File). See permissions.md for the details.

Typical Keto config:

# Keto config
dsn: postgres://keto:keto@postgres:5432/keto_db
namespaces:
  location: file:///etc/keto/namespaces.ts
serve:
  read:
    host: 0.0.0.0
    port: 4466
  write:
    host: 0.0.0.0
    port: 4467

Read API: accessible from Drive pods. Write API: accessible from Drive pods + admin tooling. Neither should be exposed to the internet.


Database Migration

Run migrations before first deploy and after updates that add new ones:

DATABASE_URL="postgres://..." ./driver migrate

Or, if running from source:

DATABASE_URL="postgres://..." deno run -A server/migrate.ts

Idempotent — running them multiple times is safe. A _migrations table tracks what's been applied.


Observability

OpenTelemetry tracing and metrics are built in (server/telemetry.ts) — every request is instrumented automatically.

Full picture:

  • OpenTelemetry — tracing and metrics via OTLP. Especially useful for debugging WOPI callback chains.
  • /health endpoint for uptime monitoring
  • PostgreSQL query logs for database performance
  • S3 access logs from SeaweedFS
  • Container stdout/stderr

Deployment Checklist

  1. Build the binary: deno task build
  2. Set WOPI_JWT_SECRET to a random secret (32+ characters)
  3. Set CSRF_COOKIE_SECRET to a different random secret
  4. Set PUBLIC_URL to the actual user-facing URL
  5. Set DATABASE_URL and run migrations
  6. Ensure SeaweedFS bucket exists
  7. Configure Collabora aliasgroup1 to allow WOPI callbacks from PUBLIC_URL
  8. Register the OIDC client in Hydra (or use the oidc-drive secret)
  9. Deploy Keto with the namespace file from keto/namespaces.ts
  10. Verify: curl https://drive.example.com/health
  11. Do not set DRIVER_TEST_MODE=1 in production. It disables all auth. You will have a bad time.