Ronni Baslund e0808bf13e fix(ocis): wire OCIS web SSO + Collabora document editing end to end
OCIS SSO was loading the SPA but never redirecting to Authentik: the default
OCIS CSP only allows connect-src to itself + the awesome-ocis GitHub repo, so
the metadata fetch to auth.dezky.local was blocked. Mount a custom csp.yaml
and point PROXY_CSP_CONFIG_FILE_LOCATION at it (env var lives on the proxy
service, not web — easy mistake). Also added the .html OIDC callback URIs to
the ocis-provider in Authentik (run-time state, not in this commit).

Collabora document editing required adding the OCIS collaboration service —
the WOPI bridge between OCIS storage and Collabora. Key wiring:

- ocis: expose embedded NATS (NATS_NATS_HOST=0.0.0.0) and gateway
  (GATEWAY_GRPC_ADDR=0.0.0.0:9142) so the new container can register and
  reach the rest of OCIS over the Docker network
- collaboration: COLLABORATION_GRPC_ADDR=0.0.0.0:9301 so it registers itself
  in the service registry with a reachable address (default 127.0.0.1 was
  unreachable from cross-container callers)
- collaboration: APP_ADDR uses the public host (office.dezky.local), not
  the internal Docker hostname — this value is sent to the browser as the
  iframe src
- collabora: regenerate proof key on every start (coolconfig generate-proof-key)
  so its public key matches what coolwsd signs with; otherwise collaboration
  rejects WOPI calls with "ProofKeys verification failed"
- collabora: ssl_verification=false (mkcert root not in Collabora's trust
  store), frame_ancestors=files.dezky.local (otherwise the iframe is blocked
  with a Danish "Indhold blokeret"), home_mode.enable=true to drop the
  "Explore The New" welcome popup and feedback prompt
- ocis CSP: extend connect-src + frame-src to include the new hostnames

Result: opening a .docx from OCIS now embeds Collabora in an iframe and the
document opens for editing.

Dev-mode caveats (not for prod): TLS verification disabled on Collabora's
outbound WOPI calls; home_mode caps at 20 concurrent connections / 10 docs.
2026-05-23 22:36:42 +02:00

Dezky

Sovereign workspace platform for European businesses. Mail, files, calendar, video meetings — all EU-hosted, all open source.

Quick start (local development)

# 1. Clone and enter
git clone <repo-url> dezky
cd dezky

# 2. Run bootstrap (handles everything)
./scripts/bootstrap.sh

# 3. Open the portal
open https://app.dezky.local

The bootstrap script:

  • Checks prerequisites (Docker, mkcert, openssl)
  • Generates wildcard TLS certificate via mkcert
  • Adds /etc/hosts entries (with your permission)
  • Generates secure random secrets in .env
  • Pulls Docker images
  • Starts all services in correct order
  • Prints next-step instructions

Service URLs (local development)

Service URL Purpose
Portal https://app.dezky.local Customer-facing landing & launcher
Authentik https://auth.dezky.local Identity provider (OIDC/SAML)
Files (OCIS) https://files.dezky.local File storage & sharing
Mail (Stalwart) https://mail.dezky.local Mail server admin UI
Office https://office.dezky.local Collabora Online editor
Traefik https://traefik.dezky.local Reverse proxy dashboard

What's in this repo

dezky/
├── apps/portal/                Nuxt 3 customer portal
├── services/provisioning/      NestJS provisioning worker
├── packages/                   Shared TypeScript libraries
├── infrastructure/
│   └── docker-compose/         Local development stack
├── scripts/                    Setup, reset, helpers
└── docs/                       Service references & guides

Prerequisites

  • macOS or Linux (Windows users: use WSL2)
  • Docker Desktop 24+ or OrbStack
  • mkcert (brew install mkcert)
  • pnpm 9+ (brew install pnpm)
  • Node.js 20+
  • 16 GB RAM recommended

Common commands

# Start everything
docker compose -f infrastructure/docker-compose/docker-compose.yml up -d

# View logs
docker compose -f infrastructure/docker-compose/docker-compose.yml logs -f [service]

# Stop everything (keeps data)
docker compose -f infrastructure/docker-compose/docker-compose.yml down

# Nuke and restart (DESTROYS DATA)
./scripts/reset.sh

Architecture

This is a multi-tenant SaaS platform. Each tenant gets:

  • Isolated Authentik OIDC tenant
  • Custom subdomain (e.g. customer-name.dezky.local)
  • Mail domain in Stalwart with auto-generated DKIM
  • Dedicated OCIS space hierarchy
  • Branded launcher in the portal

All components are Apache 2.0 / MIT licensed — no per-seat fees, full whitelabel rights.

Production

The production target is a single Hetzner AX41-NVMe server (€39/mo) with:

  • Stalwart on bare-metal
  • k3s for all other services
  • Hetzner Object Storage (€5/mo) as OCIS S3 backend
  • Storage Box BX11 (€3.20/mo) for Restic backups
  • Storage Box BX11 in Helsinki (€3.20/mo) for DR

See docs/PRODUCTION-DEPLOYMENT.md (TBD) for migration plan.

Stack rationale

These choices are deliberate after extensive license/architecture research. See CLAUDE.md for the full reasoning.

Component License Why this one
Stalwart Mail Apache 2.0 Modern Rust, ActiveSync built-in, JMAP support
OCIS Apache 2.0 Cleaner license than Nextcloud (AGPL+trademark)
Zulip Apache 2.0 Only truly open-core-free chat option
Authentik MIT Better multi-tenancy than Keycloak
Hetzner N/A 100% EU sovereignty — core to business

License

Application code: MIT (own code) Third-party services: see individual service licenses in stack.

S
Description
No description provided
Readme 1.1 MiB
Languages
Vue 60.5%
TypeScript 37.7%
Shell 0.9%
CSS 0.5%
JavaScript 0.4%