Tabs & Spaces Developers

Self-hosting

Self-hosting Tabs & Spaces

Tabs & Spaces is free to run yourself. A deployment is one installation: your server (or the cloud services you choose), your domain, your data. People sign up on it and work in workspaces, each with its own spaces, agents and data.

This section covers:

  1. Install (this page): one server with Docker Compose.
  2. First-run setup: naming the deployment and creating the first admin account and workspace.
  3. Managed services: using a hosted database, Redis, storage and email instead, and running on Fly.io.
  4. Running your deployment: agents, billing, support, upgrades, backups and health.

What it's made of

A deployment runs two containers:

  • The API, which keeps the data and does the work.
  • The web server (Caddy), which serves the app, forwards /api to the API (including its real-time connection), and gets HTTPS certificates for you.

They need a few services:

ServiceWhat it's forBundled, or your own
MongoDB 8All data: the deployment's and each workspace's (a database per workspace)Bundled, or any MongoDB, such as Atlas
Redis or ValkeyThe job queue: schedules, tasks and background workBundled Valkey, or any Redis 6.2+
S3-compatible storageFilesBundled SeaweedFS, or AWS S3, Cloudflare R2, Backblaze B2, MinIO…
SMTPEmail: sign-up confirmation, invitations, password resetsBundled Mailpit (for trying it out only), or any email service
OpenClaw GatewayAgents (optional)Bundled, or each workspace connects its own

Requirements

  • Docker with Compose v2.20 or later.
  • Memory: about 2 GB for the app, MongoDB and storage. Add about 1.5 GB to run the agents' Gateway.
  • For a public server: a domain pointing at the machine, with ports 80 and 443 open.
  • The repository, which has everything under deploy/:
FileWhat it is
docker-compose.ymlThe stack
setup.shWrites .env with fresh secrets, and prints the first-run link
DockerfileBuilds the images (--target api, --target web)
web/CaddyfileThe web server's config
openclaw/The agents' Gateway image and its first-start config
smoke-test.mjsChecks a running deployment end to end
fly/Configs for running on Fly.io (see Managed services)

Install

sh
cd deploy
./setup.sh --domain chat.example.com   # or just ./setup.sh to try it on this machine
docker compose up -d

setup.sh writes .env, readable only by you. It holds generated secrets, the bundled services to run, and your address. At the end, it prints the first-run setup link: open it to set up the deployment.

Its options:

OptionWhat it does
--domain NAMEServe https://NAME. Caddy gets and renews the certificate
--agentsAlso run an OpenClaw Gateway (see Agents)
--version X.Y.ZThe release to run. The default is latest: pin a version in production
--http-port NUse a port other than 80 when trying it locally

Without --domain, the app is at http://localhost, and email goes to the bundled Mailpit, which only catches it: read it at http://localhost:8025. With --domain, set the SMTP_* settings in .env to a real email service before people sign up.

Choosing what runs here

COMPOSE_PROFILES in .env lists the bundled services to run. To use your own service instead, remove its profile, set its settings, and run docker compose up -d.

ProfileServiceTo use your own instead
mongoMongoDB 8Set MONGODB_URI, e.g. mongodb+srv://user:pass@cluster.example.net/tabs-and-spaces
redisValkey 8Set REDIS_URL, e.g. rediss://user:pass@redis.example.net:6379
s3SeaweedFSSet S3_ENDPOINT (blank for AWS), S3_REGION, S3_BUCKET and the keys. The bucket is created if it's missing
agentsOpenClaw GatewayLeave OPENCLAW_GATEWAY_* empty. Workspaces can still connect their own Gateway
mailMailpit (trying it out)Set SMTP_HOST, SMTP_PORT, SMTP_SECURE, SMTP_USER, SMTP_PASSWORD and MAIL_FROM

Hosted services need a few things set up right, such as a database user that may delete databases, and Redis that never evicts: Managed services goes through each one.

Workspaces can also keep their data in their own MongoDB and bucket, chosen when they're created. A deployment admin can turn that off in Deployment settings. If those databases or buckets are on your private network, set WORKSPACE_INFRASTRUCTURE_PRIVATE_NETWORKS=true.

Behind your own proxy

Set SITE_ADDRESS=:80, choose a port with HTTP_PORT, and set PUBLIC_URL to the address people use, e.g. https://chat.example.com. Your proxy must:

  • forward everything to that port, including WebSocket upgrades on /api/ws;
  • allow large request bodies: attachments up to ATTACHMENT_MAX_MB, Docs files up to DOCS_MAX_MB, imports up to IMPORT_MAX_MB;
  • send X-Forwarded-For, so sign-ins are recorded with the visitor's address. The web server trusts it from private networks.