Self-hosting
One project, your infrastructure, your identity provider. The hub is the self-hosted product — not a cut-down copy of the cloud, and not a lesser path.
Maude Cloud and self-hosting are two different products that share one image.
The cloud is multi-tenant: it provisions a cell per project, bills you, and runs a control plane that owns accounts across all of them. Self-hosting is the hub. One project per hub, operated by you, with no account anywhere and nothing phoning home. That is a deliberate decision rather than a gap — a portable copy of the control plane would be a second thing to keep correct, and the half nobody on the cloud side ever runs is the half that rots.
So the self-hosted story is smaller on purpose, and complete on its own terms.
Which shape do you want
| Plain hub | Workspace | |
|---|---|---|
| Who owns the project | each peer, in their own clone | the hub |
| Autosave becomes | a message to other peers | an append-only git commit |
| Media | in git | an S3-compatible bucket |
| Signing in | a token pasted into a terminal | an email and a password — or your own IdP |
| In a browser | no | yes, the real studio |
If everyone on the team has a clone and is comfortable with git, a plain hub is smaller and there is less to operate — Deploy a hub. If somebody should never have to think about git, you want a workspace — Workspace mode.
Everything below assumes a workspace.
The shortest honest path
maude hub workspace-up --local --dev-minio \
--domain localhost --admin-email you@example.comThat runs the whole stack on your laptop — no domain, no certificate, no account anywhere — and then runs the same verification a public deployment gets. It is the cheapest way to find out what you are signing up for. It is testing only: local mode serves plain HTTP, so a sign-in password would travel in the clear.
When you are ready for something real, /design:hub-workspace walks you through it and collects exactly the credentials your choices need.
Exports from the browser: the render sidecar
The hub image carries no browser — that is a security invariant (no tenant-authored code is ever evaluated next to your hub's secrets), not an omission. Since v1.0.7 that matters less than it used to: PNG and SVG of the artboard you're looking at, and the PPTX deck, export straight from the member's own browser — the canvas already renders there, so those clicks are instant and need no sidecar. What still needs a real Chromium on a server is video (MP4/WebM/GIF), PDF, and multi-artboard PNG/SVG scopes.
Two honest options:
- Do nothing. PNG/SVG of the active artboard, the PPTX deck, ZIP and AI handoff all work in the hosted studio; video/PDF show up disabled in the export dialog with the reason, and the desktop app exports every format. Many teams never need more.
- Add
--rendertoworkspace-up. It deploys themaude-rendersidecar — a separate container that holds the Chromium and nothing else: no hub secret, no volume, no public port (the hub reaches it over the compose network only), and a boot-time refusal if any known secret variable is present in its environment. Renders authenticate back to the hub with the same short-lived read-only capability a member's own browser holds.
maude hub workspace-up … --renderRe-running with the flag is also how you add it to an existing workspace — like every re-run, existing secrets in .env are reused. The verification suite gains a render-health step; a sidecar that is up but misconfigured reports as failed, never as fine.
Pin the tag, and know your architecture. MAUDE_IMAGE_TAG covers both containers, and the sidecar is published for release tags only — unlike the hub it has no :latest, so --render without --image-tag vX.Y.Z names an image that does not exist. Both images are published for linux/amd64 and linux/arm64; releases up to and including v1.0.3 published the sidecar for amd64 only, so on an arm64 host pin a later tag. workspace-up checks the published architectures before it writes anything and refuses with the reason — Docker itself would pull the image happily and only fail at exec format error, ~3 GB later.
The sidecar is a ~3 GB image running Chromium, so give it room: a 2 GB instance is tight for the hub plus a render, and swap or a larger instance is the cheaper answer than a killed container mid-export.
What you are taking on
The command scaffolds and verifies once. It does not operate the deployment, and it prints that list on every successful run rather than implying otherwise. In short:
- Durability is the page to read before you rely on this. Not the backup — the restore.
- Rotate
HUB_SECRETwhen someone leaves. It is the operator credential. - Pin the image tag.
latestmeans an unplanned upgrade on the next restart. - Never expire the
assets/prefix. A canvas in git history can reference media no current canvas does, so "unreferenced" never means "unreachable". - The bill is yours. This runs on your infrastructure.
Read next
- On AWS — EC2 + EBS + S3, the IAM policy, and the two AWS defaults that quietly break this.
- Durability — what survives a restart, a lost volume, and a second hub.
- People — accounts, invite links, and what "removed" actually means.
- Identity — keep the built-in sign-in, or bring Auth0 / Google.
The hub
Self-hostable Yjs sync hub for cross-machine canvas collaboration. Deploy once, link your peers, share canvases over the internet — no SaaS, no Cloudflare account, no Yjs knowledge.
Deploy a hub
One self-hostable Yjs sync hub, deployable to Fly or any box that runs Docker. No SaaS, no Cloudflare account, no Yjs knowledge required.