celld is in alpha and is not safe for hostile multi-tenant use. Security fixes apply to the latest release only — older alpha builds do not receive backported patches. Review this page in full before exposing a celld fleet to untrusted traffic.Documentation Index
Fetch the complete documentation index at: https://mintlify.com/denoland/celld/llms.txt
Use this file to discover all available pages before exploring further.
Separate the public and internal listeners
celld opens two independent HTTP listeners. Understanding what each one does — and does not — serve is the foundation of the security model.| Listener | Flag | Default | Purpose |
|---|---|---|---|
| Public | --listen | 127.0.0.1:8080 | Serves the deployed Worker to end users |
| Internal | --internal-listen | 127.0.0.1:0 | Serves the peer replication protocol and the operator API |
127.0.0.1:0 — a random loopback port chosen at each start. The startup output reports the selected address. For a multi-node fleet, bind the internal listener to a private interface and use --advertise to tell peers the address they can reach:
--advertise value requires an explicit --internal-listen address. celld also rejects an explicit non-loopback public listener that does not have an explicit internal listener, to catch obsolete single-listener configurations.
Public listener
The public listener reserves only one path:| Path | Healthy | Draining |
|---|---|---|
/__celld/health | 200 {"ok":true} | 503 |
/health — belongs to the deployed Worker. The internal listener returns 404 for any path it does not recognise, so a misrouted operator request cannot accidentally become an application request.
Protect the internal listener
celld does not terminate TLS on the internal listener. If the private network does not provide the required confidentiality, use an encrypted overlay such as WireGuard or Tailscale.Internal operator API paths
The following paths are available on the internal listener:| Path | Description |
|---|---|
/state | Reports current occupancy, eviction, and restoration values. Remains available during graceful shutdown drain. |
/cell/NAME | Resolves or activates a cell for an operator check. |
/evict/NAME | Evicts a resident cell. |
/do/NAME | Sends a direct Durable Object request. |
POST /shutdown | Starts a graceful ownership handoff. |
POST /shutdown?handoff=preserve | Prepares a clean same-node reload and keeps the ownership records. |
GET /__celld/probe | Serves the signed diagnostic probe used by celld diagnose. Also available during graceful shutdown drain. |
The operator API is an alpha interface. A release can change its paths or response formats without notice. Keep your operator tooling and the celld release at the same version.
Peer authentication
Peer requests on the internal listener use a separate authentication layer from the operator API. Each peer request carries:- An HMAC over the request metadata
- A body signature that covers the request payload
- A clock bound that rejects requests with a timestamp too far from the current time
- Replay protection that prevents a captured request from being replayed
Protect the fleet bucket
The bucket stores:- Deployed Worker bundles and static assets
- SQLite cell state (replicated data for every cell)
- Ownership leases (which node owns each cell)
- Node leases (used for fleet discovery)
- The shared peer-authentication secret
- Give each credential access to one fleet bucket only.
- Use a key prefix (
s3://BUCKET/PREFIX) to isolate multiple fleets in one bucket, but give each fleet its own credential scoped to its prefix. - Replace a credential immediately after a suspected disclosure.
Cell isolation
Each cell is a SQLite database with one writer at a time. A cell can access only its own database — there is no shared storage between cells at the application level. A defective or compromised cell can consume CPU, memory, and file descriptors on its fleet nodes, but it cannot read or modify another cell’s data. The fleet has no shared multi-tenant scheduler or account service. One application deployment runs per fleet.Application authentication
celld does not authenticate the users of the deployed application, and it does not terminate public TLS. Both concerns belong in front of the public listener:- TLS termination — use an ingress proxy (nginx, Caddy, a cloud load balancer) to terminate HTTPS before traffic reaches
--listen. - User authentication — enforce authentication in the ingress proxy or in the deployed Worker itself before requests reach cell handlers.