- api: matrix-sso module (tuwunel jwt -> login/get_token), POST /matrix/session, GET /matrix/identity, drive controller - web: /chat full-height Element view, /files Library+Drive tabs, embedded-app frame component - edge: /hub-sso.html handshake route (origin-pinned CSP), X-Frame-Options strip on files - oCIS: csp.yaml frame-ancestors app.occupymedia.cc - server config still required: tuwunel [global.jwt], MATRIX_SSO_JWT_SECRET, oCIS restart |
||
|---|---|---|
| .. | ||
| .env.example | ||
| compose.yml | ||
| csp.yaml | ||
| README.md | ||
| tuwunel-r2.toml.example | ||
OccupyMedia files/docs foundation
Status: scaffolding only; nothing deployed. This is a new occ-files
compose project. Do not merge it into occ-chat, occ-app, or the historical
one-box compose. Live chat remains conduwuit v0.5.0; this phase does not switch
its image, config, database or volumes. See storage architecture and contracts.
Payload boundary
R2 is the only durable destination for file/media payloads. oCIS S3NG requires local POSIX metadata; Matrix requires local state. These are backup-critical exceptions, not permission to store file bodies, thumbnails, pad revisions or document caches on Proxmox disks. Transient processing uses bounded RAM/tmpfs. Disable swap for those workloads (including host/CT swap) and payload-bearing core dumps. An R2 outage must fail writes, not fall back to disk.
The compose masks the expected upload staging path with tmpfs and omits the thumbnail service. This is a candidate configuration, not proof that every path in an arbitrary upstream image complies. Audit actual paths and upload behavior for the pinned releases before admitting any user data. tmpfs upload sessions disappear on restart and must be retried. Start with a 20 MiB request cap enforced by the ingress and one upload at a time; large media goes through the existing dedicated media/video plane.
Configuration
.env.example deliberately leaves images, account endpoint and secrets empty.
Select compatible release digests; do not use latest or assume the research's
version availability is sufficient validation. Use the same oCIS image for both
oCIS and collaboration. Confirm S3NG signing/path-style compatibility against
R2 with that release. The native STORAGE_USERS_S3NG_* settings explicitly select
the exclusive files bucket. files-config.ts is an opt-in validation interface,
not startup wiring; a later adapter must invoke it and enforce the same checks.
Verify the bucket inventory manually before provisioning: FILES_RESERVED_BUCKETS
must include every other product's actual bucket names, including both PeerTube
buckets. Never change live app bucket names or its KEK as part of this phase.
Source-built images (Apache-2.0): the repo Dockerfile build runs as root and
defaults its config search to $HOME/.ocis — it does NOT inherit the official
image's conventions. The compose therefore pins user: "1000",
HOME: /var/lib/ocis, and OCIS_CONFIG_DIR: /etc/ocis for the ocis service,
and publishes 9200/9980 on the LAN (no WAN forward exists; the CT150 tunnel
connector reaches occ-files over the bridge). Do not remove these when
swapping images.
Use the built-in oCIS identity provider for an isolated first deployment. Do not point its issuer at chat: current conduwuit is not the proposed OIDC provider. External OIDC and account mapping need a separate design/test pass.
For CODE 26+, generate its WOPI proof key privately with the selected image's
upstream procedure, store it outside the repository, and set
COLLABORA_PROOF_KEY_FILE to an existing regular file. Keep WOPI proof
verification enabled. The bind mount never creates a directory on a missing
file path. Review required ownership/permissions for the selected images,
including tmpfs/jail and oCIS UID/GID (scaffold assumes 1000).
Exact next deployment steps (operator work; not executed in phase one)
-
Inventory the existing buckets and CTs. Reserve a new files CT/project with 8 GiB RAM / 4 vCPU for the complete docs target; keep API and PeerTube in their current separate CTs. Provide an XFS/ZFS metadata filesystem with working xattrs, initial 10–20 GiB capacity, monitoring and off-host backups. Do not reuse existing Matrix volumes. Allocate/verify no swap and no payload dumps before user uploads.
-
Verify/create
occupymedia-files-blobsif absent. Keep it private and exclusive to oCIS. Provision a bucket-scoped read/write key just for files; Matrix and AnarchoPoster credentials remain separate. Verify lifecycle rules cannot silently expire active opaque oCIS blobs. Define a separate backup account and scheduled copy/restore job; durability alone is not a backup. -
Copy the scaffold to the new CT. Run
cp .env.example .envandchmod 600 .envin that directory. Fill real private credentials, endpoint and approved digest-pinned images, public URLs/hosts, independent random admin/JWT/WOPI secrets and proof-key path. Back up secrets in the password manager. Keep generated/etc/ocis/ocis.yamland all keys out of git. No secrets are supplied by this repository. -
Validate without launching containers:
cd infra/occupymedia/files docker compose --env-file .env -f compose.yml --profile docs config --quietThis checks syntax/required variables only. Compare the files bucket against Matrix, AnarchoPoster and PeerTube names; verify HTTPS account R2 endpoint, host/URL agreement, image digests and private key-file ownership. Do not print rendered config or
docker inspectinto shared logs (they contain secrets). -
On the new project only, initialize once:
docker compose --env-file .env -f compose.yml run --rm ocis init docker compose --env-file .env -f compose.yml up -d ocisProtect initialization output (it may contain generated credentials). Do not use an
init || truestartup loop; inspect unexpected init errors. Verify the persisted generated config contains no local user-blob driver override. -
Route
files.occupymedia.ccthrough the existing Tunnel to the new CT's127.0.0.1:9200, andoffice.occupymedia.ccto127.0.0.1:9980. These binds require a Tunnel connector on that CT, or an explicit authenticated private relay; the app CT connector cannot reach another CT's loopback. Do not expose these ports publicly. Preserve HTTPS origin/Host headers, WebSockets, encoded WOPI URLs and adequate WebDAV/TUS timeouts. Test actual Cloudflare request-size limits and chunking; Tunnel does not automatically remove those limits. -
Before opening docs, start the optional pair:
docker compose --env-file .env -f compose.yml --profile docs up -d collaboration collaboraoCIS Web permits only the configured office frame origin via
csp.yaml. Collaboration registers with oCIS over private NATS/CS3 and exposes WOPI only on the compose network. Collabora useshttp://collaboration:9300as its allowlisted WOPI source; the browser uses HTTPS office URLs. Verify discovery, proof keys, locks, read/write grants and CSP. Do not bypass proof checks or disable TLS verification to make a failed launch appear successful. -
Admission rehearsal: upload a disposable ODT/image, interrupt a TUS upload, restart services, retrieve and checksum the saved object, then co-edit an ODT with two authorized users and reload it after closing both clients. Observe uploads, jail/temp paths, writable container layers, system storage (including avatars), and metadata volumes: no payload may persist outside R2. Inspect all release-specific spill/cache paths; mask/disable them or block deployment if unresolved. Disable avatar/system-file features if they store payloads locally. Check R2 failure returns an error, revoked users cannot fetch files, tmpfs exhaustion fails safely, and a backup restores an independent project. Production is blocked until these checks pass.
-
Create restricted oCIS Spaces and explicit group/room mappings. Implement the
HubArchivePortsync-loop adapter + metadata index described in the contract before enabling mirroring. No bot image, API route or schema migration exists in this phase. Reserve an unencrypted archive room per group; require explicit membership/grant reconciliation. Keep encrypted rooms excluded. -
Rehearse Tuwunel separately with fresh state and disposable media using
tuwunel-r2.toml.examplemerged into the selected release's full config. Privately supplyendpoint,key,secret; the example deliberately lacks usable credentials. Retain the deployed server name for any eventual live upgrade, but do not connect the rehearsal to live federation/volumes. A future authorized migration needs snapshots, compatibility checks, rollback and a media-copy plan. This phase authorizes none of those live changes. -
Add a compliant pad adapter only after it can durably save text, revisions, attachments and exports to R2. Leave
PADS_ENABLED=falseuntil then. An ordinary local Postgres pad deployment plus periodic R2 exports does not satisfy this requirement. Add optional Tika only after extraction spill paths and the policy for storing derived document text have been resolved.
Resources and recovery
| New files/docs component | Planning RAM / CPU |
|---|---|
| oCIS incl. bounded upload scratch | 0.5–1.5 GiB / 1 vCPU cap |
| WOPI collaboration | 0.1–0.25 GiB / 0.25 vCPU cap |
| Collabora incl. tmpfs jail/temp | 1–2.5 GiB / 1.5 vCPU cap |
| Future hub-archive | 0.1–0.25 GiB / 0.25 vCPU allowance |
| Optional future Tika | 0.5–0.75 GiB / 0.5 vCPU allowance |
| Future pad adapter | 0.2–0.5 GiB / 0.25 vCPU allowance |
Current compose caps total 4.25 GiB / 2.75 vCPU. Reserve 8 GiB / 4 vCPU for the complete docs target and OS/headroom; actual Collabora concurrency must be measured. A 4 GiB CT is only a reduced files pilot, not this complete stack. RAM/tmpfs counts toward limits. The 20 MiB/one-transfer initial limit is deliberate; large originals and multiple active ODT sessions require measurements before raising it. No pad, bot or Tika RAM is being consumed by this scaffold.
Daily RPO target: consistent oCIS metadata/config snapshots preserving xattrs, symlinks and ownership plus independent R2 object backups; store a manifest linking the snapshot and object-copy checkpoints. Back up generated identity and signing configuration and the Collabora proof key on change. Later add Hub DB index/mapping/outbox/sync-cursor dumps, and Matrix state snapshots via its supported backup method. Protect the AnarchoPoster KEK separately. Restore-test monthly in isolated projects; ensure metadata references resolve before reopening access. R2 alone cannot reconstruct the oCIS directory/ACL tree. Do not back up tmpfs scratch or document jails to local storage. Retention/deletion actions must be coordinated across copies, trash/versions and backup expiry, with legal holds.
Upstream verification
The research is design input, not executable deployment instructions. Settings were checked against oCIS storage-users, storage drivers, collaboration, the office compose example, and Tuwunel's config reference. Recheck the exact pinned release before running it; current upstream examples may differ (notably CODE 26 proof-key initialization). The research's mixed local/R2 Matrix provider sketch is an eventual transition design, not an R2-only end state.