5.2 KiB
Cloud hosting requirements — occupymedia.cc stack
Date: 2026-10-12 Basis: measured on the production home deployment (CT 150 app, CT 152 chat, CT 320 files) — see the table for real numbers, not estimates.
What runs where
Everything except object storage and the CF edge is self-hostable on ONE VPS:
- Hub app: api, scheduler, web (Next.js), intake site, Element Web client
- Data: Postgres, Redis, Temporal, chat homeserver (tuwunel/RocksDB), files server (oCIS S3NG + optional Collabora)
- Edge: cloudflared tunnel, nginx edge, certbot, failover watchdogs
- Media worker (transcoding): can stay OFF the box (distributed worker model — e.g. the planned Windows/NVENC node joins over tailscale)
Externalized by design (never self-host): R2 object storage (all media payloads — files, chat media, video), Cloudflare (DNS, ingress, failover), Telegram/Matrix federation peers.
Measured footprint (production, today)
| Component | RAM used | Disk used | Notes |
|---|---|---|---|
| App CT (everything above) | 1.0 GB / 16 GB | 147 GB* | *images + build artifacts + snapshots — real data is small |
| Chat CT (tuwunel + RocksDB) | 145 MB / 4 GB | 7.8 GB | grows slowly: new media → R2 |
| Files CT (oCIS + Collabora) | 1.4 GB / 8 GB | 13 GB | metadata only; payloads in R2 |
| R2 (object storage) | — | 385 GB on account** | **occupymedia usage ≈ 0 today; the 385 GB is another project sharing the account |
Real concurrent RAM: ~2.6 GB total. Media payloads are externalized to R2, so disk does NOT grow with video/uploads.
Sizing
| Tier | Specs | What it covers | Ref. price (Hetzner-class) |
|---|---|---|---|
| Minimum | 4 vCPU / 8 GB RAM / 160 GB SSD | full stack at current usage | ~€15/mo |
| Comfortable | 8 vCPU / 16 GB RAM / 240 GB SSD | + live-event spikes, on-box transcoding, Collabora sessions | ~€30/mo |
- CPU: 4 vCPU is enough if video transcoding stays distributed (render workers join over tailscale — the design). On-box transcoding wants 8.
- RAM: 8 GB floor (Temporal + oCIS + Postgres headroom); 16 GB makes live events boring.
- Disk: does not grow with media (R2 externalized). 80–160 GB lasts years.
- Bandwidth: near-zero egress (R2/Cloudflare deliver media; R2 has zero egress fees).
- Object storage (R2): pay-per-GB (~$0.015/GB/mo) + small ops fees. Current occupymedia usage ≈ 0; expect low single-digit $/mo at collective scale.
Single-box placement
One VPS runs the consolidated stack (all three home CTs on one host):
- Docker compose projects: occ-app, occ-chat, occ-files, occ-edge, occ-element,
occ-intake — the same compose files in
infra/occupymedia/. - Ingress: Cloudflare tunnel (remotely managed — config lives in the CF dashboard, re-point at the new box) + the edge nginx + watchdogs (the ipfs3 relay failover works from any location; from a cloud box it is redundant but harmless).
- Tailscale optional on a cloud box (its address is already public).
Migration runbook (home → cloud)
Ordered; each step reversible:
- Prereq: fresh VPS (Ubuntu 24.04), Docker + compose plugin, tailscale (optional), DNS ready (CF API token).
- Data export (from home, per store):
- Postgres:
pg_dump(owner format) → transfer. - Chat: stop tuwunel → tar
occ-chat_conduwuit_datavolume (final snapshot exists; make a fresh one) → transfer. Keeptuwunel.toml(has R2 creds). - Files: stop oCIS → tar
ocis-config+ocis-metadatavolumes → transfer. (Blobs are in R2 — they do not move.) - Hub files folders: they are oCIS resources (in R2) — nothing extra.
- Postgres:
- R2: unchanged — same account, same buckets, same keys. If the VPS region differs, no action (R2 is anycast).
- Restore on the VPS: start postgres → restore dump → restore chat/files volumes from tars → start stacks in order (datastores → api/scheduler/web → chat → files → edge) → apply any pending migrations with the api CLI.
- Ingress cutover: install cloudflared with the same tunnel token (the
tunnel id moves with the token; ingress config is remote) → connections
register from the new box. Re-point tunnel ingress service URLs from
192.168.13.x/100.xaddresses to the VPS's local container names/ports. - Edge + watchdogs: copy the edge dir; the ipfs3 relay and ingress watchdog keep working (the watchdog flips DNS to the relay if the new box's CF path is ever sick).
- Verify (the standard checklist): api/web/chat/files/element health, login, collective creation mints rooms, archive E2E (upload → R2 → bot → files), restore tooling round-trip.
- Rollback: home stack stays intact until step 7 passes; DNS flips back in one API call.
Cost picture
| Item | Monthly |
|---|---|
| VPS (comfortable tier) | ~€30 |
| R2 storage (grows with media) | ~$1–5 at collective scale, zero egress |
| Cloudflare free tier | $0 |
| Total | ~€30–35/mo all-in |
What was measured vs assumed
Measured: RAM/disk per CT (table above), R2 bucket inventory + usage, docker image sizes, component list. Assumed: audience scale stays collective-sized (tens–hundreds of users); video delivery rides R2/CF (no self-hosted CDN egress); transcoding off-box. Re-measure after the first large live event.