Deployment Modes¶
Strata's deployment_mode is binary — personal or service — but
personal supports two flavors depending on whether
STRATA_PERSONAL_MODE_USER_HEADER is set. In practice you're choosing
between three shapes.
Decision matrix¶
| Personal | Personal + auth proxy | Service | |
|---|---|---|---|
| Best for | One developer, laptop, single notebook open | 5–20 trusted users behind Cloudflare Access / Pomerium / etc. | Multi-tenant team or customer-facing |
| Writes | Enabled | Enabled (per-user filter on discover/delete) | Off by default (server-side transforms); opt-in client write-back via service_writes_enabled |
| Auth | None | Identity from STRATA_PERSONAL_MODE_USER_HEADER (proxy injects) |
X-Strata-Principal + X-Strata-Proxy-Token from a trusted proxy |
| Identity scoping | No scoping (single user) | Per-user filter on discover / delete; shared artifact store |
Per-tenant cache keys, storage dirs, QoS pools |
| Multi-tenancy | n/a | n/a | Optional (multi_tenant_enabled=true) |
| ACLs | Not evaluated | Not evaluated | Deny-first (acl_config) |
| Default artifact dir | ~/.strata/artifacts |
~/.strata/artifacts |
Must be set explicitly (or blob backend) |
| Network binding | Loopback only | Non-loopback with allow_remote_clients_in_personal=true |
Unrestricted |
| Used by Strata's hosted preview | – | ✓ (Fly.io + Cloudflare Access) | – |
| Use in production for sharing? | ❌ Anyone on the network can write | ⚠️ Only behind a real auth proxy, small trusted group | ✓ |
The rows that drive the choice are typically Writes (does anyone who reaches the URL get to mutate?), Auth (who decides who's allowed?), and Identity scoping (what's isolated and what's shared?). The flags that follow are the consequences.
Choosing a shape¶
- Personal: running the notebook on your own machine. Fast to start, nothing to configure, writes land in your home directory. This is the default for Docker Compose and the "from source" instructions.
- Personal + auth proxy: small team sharing one Strata instance with the proxy handling auth. Cheap to operate, no per-user isolation (artifact store is shared), but each user gets their own list in "Open existing." See Sharing personal mode with a small group below. This is what Strata's own hosted preview at strata-notebook.fly.dev runs. See Fly.io deployment for the deployment recipe.
- Service: hosting Strata for users you can't fully trust, or
with sensitive data, or with multi-tenant isolation requirements.
Reads are tenant-scoped and ACL-gated; writes are off by default
(routed through server-side transforms), or authenticated clients
can publish directly to a shared store with
service_writes_enabled. See Service Mode.
Setting the mode¶
Or in pyproject.toml:
Default is personal: the common case. A first-time
uv run strata-notebook boots into a single-user, loopback-only
deployment that just works.
Service mode is explicit opt-in. The coherence checker fires clear
errors at startup if you set deployment_mode=service without
matching auth / artifact configuration, so misconfigured production
deploys fail fast rather than silently exposing write endpoints.
Personal mode¶
The server binds to 127.0.0.1 by default and refuses non-loopback
addresses unless you opt in:
STRATA_DEPLOYMENT_MODE=personal \
STRATA_HOST=0.0.0.0 \
STRATA_ALLOW_REMOTE_CLIENTS_IN_PERSONAL=true \
uv run strata-notebook
Opt in only if you have separate protection (firewall, VPN, private network) personal mode exposes write endpoints with no authentication.
Artifacts persist to ~/.strata/artifacts unless STRATA_ARTIFACT_DIR
is set. Notebook deletion and session discovery/reconnect APIs are
personal-mode-only.
Service mode¶
STRATA_DEPLOYMENT_MODE=service \
STRATA_AUTH_MODE=trusted_proxy \
STRATA_PROXY_TOKEN=<shared-secret> \
uv run strata-notebook
Short version: an upstream proxy authenticates the caller, injects
identity headers (X-Strata-Principal, tenant header,
X-Strata-Scopes, X-Strata-Proxy-Token), and is the only ingress
path. Strata trusts the proxy and refuses to do its own auth.
See Service Mode for the full story:
- The trusted-proxy header contract.
- The shipped demo stack (
docker-compose.service.yml+ nginx proxy injecting two demo identities on ports 8865/8866). - Production reference architecture.
- Multi-tenancy, ACLs, server-side transforms.
- Migration path from personal mode.
Sharing personal mode with a small group¶
A common deployment shape is "personal mode behind an authenticating proxy", for example, Cloudflare Access in front of a Fly.io app, sharing the notebook UI with a handful of trusted users. This isn't full multi-tenancy (no per-user storage, no per-user QoS, no artifact isolation), but Strata provides a thin per-user filter so each invitee sees their own work in the "Open existing" list.
Set:
STRATA_DEPLOYMENT_MODE=personal
STRATA_ALLOW_REMOTE_CLIENTS_IN_PERSONAL=true
STRATA_PERSONAL_MODE_USER_HEADER=Cf-Access-Authenticated-User-Email
The header value is whatever your proxy injects after authenticating the caller. Strata treats the value as opaque, email, GitHub login, internal ID, anything stable.
What changes when the header is set:
POST /v1/notebooks/createstamps the caller's identity intonotebook.tomlasowner.GET /v1/notebooks/discoverreturns only notebooks whereowner == callerorowner is None.DELETE /v1/notebooks/{id}andPOST /v1/notebooks/delete-by-pathreturn 404 if a non-owner tries to delete an owned notebook.- Direct-URL access stays open: anyone with a notebook ID can
POST /openand view it. This is intentional, it preserves "share a link with a collaborator" while preventing accidents in the discovery list.
What does not change:
- Concurrent edits to the same notebook still race (no per-user sessions).
- The artifact store is shared; provenance hashes don't include the caller.
- The AI API key pool (STRATA_AI_*) is shared across all users.
- Unowned (legacy) notebooks remain visible and deletable by everyone.
This shape is the right answer for a 5–20 person trusted group. For untrusted or paid users, migrate to service mode for proper tenant isolation.
Coherence enforcement¶
Strata rejects incoherent mode combinations at startup. These combos
raise ValueError during config load:
| Combination | Why it's rejected |
|---|---|
deployment_mode=personal + auth_mode=trusted_proxy |
Personal mode has no upstream proxy; identity headers would come from the loopback client |
deployment_mode=personal + multi_tenant_enabled=True |
Personal mode is single-user; there are no tenants to isolate |
deployment_mode=personal + require_tenant_header=True |
Same reason, no tenant dimension in personal mode |
deployment_mode=service + personal_mode_user_header |
Service mode uses X-Strata-Principal via trusted-proxy auth; the personal-mode shim is for proxy-fronted personal deployments only |
If you see one of these errors, you almost certainly pulled flags from a
service-mode config into a personal-mode deployment. Remove the
service-specific flags or switch to deployment_mode=service.
Mode-independent settings¶
These apply identically in either mode and can be tuned freely:
rate_limit_*, token-bucket rate limitingacl_config, deny/allow rules (only effective whenauth_modeis set)artifact_blob_backend, local / s3 / gcs / azure- Tracing, logging, S3 / GCS / Azure credentials
- Cache size, cache directory, metadata DB path