Multi-tenant Hosting: Isolated Gateway Cells for Each Tenant
Learn how to host multiple tenant trust domains as isolated OpenClaw Gateway cells. This page explains why each tenant requires a separate cell for security and how the experimental fleet command deploys them.
Read this when
- You are hosting OpenClaw for multiple users or organizations
- You need to choose an isolation boundary for tenant workloads
Multi-tenant hosting
OpenClaw's built-in security model assumes a single trusted operator per Gateway. It does not provide hardened isolation between untrusted tenants sharing one Gateway. To host users or organizations that do not trust each other, you must deploy a separate, complete OpenClaw instance for each tenant.
openclaw fleet refers to each isolated instance as a cell. Every cell is a full Gateway running inside a hardened container, with its own state, credentials, workspace, channel accounts, token, and a loopback-only host port.
Fleet is experimental. Its commands, flags, and container profile may change between releases without any deprecation notice.
Fleet has been tested on Linux and macOS hosts. Windows hosts have not been tested yet.
Why each tenant needs a cell
An authenticated operator inside a Gateway holds a trusted control-plane role. Session IDs determine routing but do not authorize one tenant against another. Agent sandboxing can limit the impact of untrusted content or tool execution, but it does not convert a shared Gateway into a tenant authorization boundary.
Assign one cell per tenant so each trust domain gets its own Gateway process, container, persistent state tree, and Gateway credential. This aligns with the Gateway security model: never place mutually untrusted users inside the same OpenClaw process or OS user.
Architecture
The Fleet CLI acts as a lifecycle supervisor on the host. It stores cells in the OpenClaw state database and instructs a local Docker or Podman runtime to create, inspect, start, stop, replace, and remove their containers. Remote runtime endpoints are unsupported because Fleet's bind paths and loopback URLs are tied to the local host. Fleet does not proxy tenant messages and does not introduce a shared application-level data path between cells.
Every cell runs the official ghcr.io/openclaw/openclaw image on its own user-defined bridge network. Separate bridges prevent direct container-IP communication between cells while still allowing outbound NAT access for providers and channels. Outbound egress is unrestricted by default. Podman cells can use --network internal to block egress while keeping the published loopback Gateway port accessible. Docker internal networks break that published port, so Fleet rejects that combination; instead, enforce Docker egress policy using host firewall rules such as the DOCKER-USER chain. The cell Gateway listens on port 18789 inside the container, and the runtime publishes it only to 127.0.0.1:<allocated-port> on the host. An operator can place an approved reverse proxy, SSH tunnel, or tailnet in front of that loopback endpoint when remote access is required.
Persistent Gateway state originates from <state-dir>/fleet/cells/<tenant>/ and is mounted at /home/node/.openclaw. Auth-profile encryption keys come from the separate <state-dir>/fleet/auth-profile-secrets/<tenant>/ host path and are mounted at /home/node/.config/openclaw, matching the official Docker persistence layout. The key is not stored inside the ordinary state mount. Per-tenant channel accounts terminate inside the cell that owns them; Fleet does not provide a shared channel account or inbound message router.
The official image defaults to the non-root node user with UID 1000. Fleet applies host-compatible user mappings so private bind mounts remain writable: Podman uses keep-id, rootful Docker uses the invoking non-root identity, and rootless Docker maps container root to the unprivileged daemon user. Docker and Podman apply a private :Z relabel when host SELinux is active. The container profile avoids privileged host features and is rootless-friendly, but rootless operation is a host runtime choice and prerequisite, not something Fleet enables automatically.
Trust boundary
Multi-tenancy protects tenants from one another. The Fleet operator and the host are trusted by every tenant. Resistance to a compromised host is not a goal.
This means a host administrator can inspect container configuration and environment, read mounted cell data, replace images, or enter containers. Gateway tokens and values passed with --env are visible to an administrator through Docker or Podman inspection. Use host controls, administrative access policy, monitoring, backups, and an approved secret manager accordingly.
The baseline prevents accidental wildcard network exposure and removes common container escalation primitives, but it does not make an untrusted host safe.
Isolation ladder
Choose the boundary that matches the tenants you host:
- Hardened container baseline. Fleet drops all Linux capabilities, enables
no-new-privileges, applies PID, memory, CPU, and optional writable-layer disk limits, uses separate persistent mounts and per-cell networks, and publishes only to host loopback. Bridge networking leaves egress unrestricted; use Podman--network internalor Docker host firewall policy when a cell must not initiate outbound connections. This is the default profile for tenants that trust the operator and host. - Stronger container or VM isolation. For higher-risk workloads, configure Docker or Podman to use a stronger OCI isolation runtime such as gVisor or Kata Containers, or place cells in microVMs. This is runtime or infrastructure configuration; Fleet's
--runtime docker|podmanoption chooses the container CLI, not the OCI isolation backend. See Docker's alternative container runtimes and the Docker VM runtime guide. - Separate machines for hostile tenants. Do not co-locate hostile tenants in one OpenClaw process or OS user. When tenants do not trust the same host operator or need a stronger administrative boundary, use separate VMs or physical hosts with separate runtime administration.
No rung in this ladder changes the OpenClaw application trust model: one Gateway remains one trusted operator domain.
Quick start
Create a cell. The command prints a generated Gateway token once, so store it immediately:
openclaw fleet create acme
Open the reported http://127.0.0.1:<port> URL on the Fleet host, authenticate with that tenant's token, and configure provider credentials and channel accounts inside the cell.
Check the container state and Gateway liveness:
openclaw fleet status acme
Upgrade while preserving the host port, mounted data, resource profile, user-supplied environment, and Gateway token:
openclaw fleet upgrade acme
Remove the container and registry row while retaining tenant data:
openclaw fleet rm acme --force
To delete persistent tenant data too, add --purge-data. Purge requires --force, is irreversible, and performs a resolved-path containment check before deleting anything:
openclaw fleet rm acme --purge-data --force
See the openclaw fleet CLI reference for every command and option.
Current scope
Fleet does not provide these surfaces:
- Shared channel accounts or a shared ingress router
- Slimmed-down per-tenant host processes instead of complete OpenClaw instances
- Remote cell hosts managed by one supervisor
- A tenant self-service portal, billing plane, or delegated administration UI
These capabilities need explicit identity, routing, authorization, and failure-domain contracts. Do not approximate them by sharing one Gateway or its credentials across tenants. Fleet is a single-host lifecycle supervisor; multi-machine, identity-governed fleets require a separate control-plane layer.