Introduction

Scafo is a self-hosted serverless deployment platform for JavaScript projects: one binary that is both the node daemon and the operator CLI, with an S3-compatible bucket as its registry.

#What Scafo is

One executable provides two things:

InvocationWhat it is
scafo sailThe node daemon. Joins the machine to a fleet, serves the node API, supervises runtime processes, and renders the fleet's routing.
every other subcommandThe operator CLI: app, deploy, deployment, trust, operator, remote, fleet, wg, metrics, traces, health.

Scafo stores its registry as JSON objects in an S3-compatible bucket and mutates them with conditional writes. There is no database and no consensus protocol. Nodes that point at the same bucket and key prefix are one installation.

#Vocabulary

TermMeaning
FleetOne installation: one registry (bucket + prefix) and every Scafo node that joined it. A single node is a fleet of one.
NodeA machine running scafo sail. It has a persistent id and Ed25519 keypair.
ApplicationThe unit Scafo deploys, places, serves, blocks, retires and deletes, identified by its name. It holds the current deployment, its hosts, its placement constraints and its trust policy, and it is served at <name>.<platform domain>.
DeploymentThe current artifact an application serves. Scafo records a monotonic deployment revision, never a selectable version.
PlacementThe registry record naming which nodes serve an application, written by the coordinator.
IngressCaddy or Traefik, running beside a node. It pulls the fleet's routing from the node API; Scafo never writes ingress configuration.
OperatorA person or automation holding an Ed25519 key the fleet trusts, at admin or operator tier.
RegistryThe _scafo/ object tree in the bucket: meta, nodes, operators, applications, trust policies, deployments, deploys, placements, domains, TLS material, observations.
Celld fleetCelld's own concept, one per Scafo application. Unqualified fleet and node always mean Scafo's machine-level concepts.

#How the parts connect

  • Operator CLI → node API. Deploys and most control operations are signed requests to a node. Some commands (fleet nodes, trust, metrics, traces, wg, deployment prune, app retire/unretire/selector/replicas/delete when no node is named, operator keygen --register, remote add --register) read or write the bucket directly with bucket credentials.
  • Nodes ↔ registry. Every node reads and writes the same bucket. Membership, placement and coordination are registry state, not a cluster protocol.
  • Ingress → node. An ingress holds one bearer token and reaches its colocated node on /v1/ingress/routes for routing and /v1/storage for certificate material. It never holds bucket credentials.
  • Node → Celld. A node starts one Celld process per application assigned to it, on a public/internal port pair.
  • Node ↔ node. Runtime peer traffic and operator traffic cross either a WireGuard tunnel or a network the operator has declared private.

#What each part owns

Scafo ownsCelld owns
Registry and its conditional writesDeployment adoption
Authorization: operator keys, application scopes, OIDC deploy policyApplication health
Placement: selectors, rendezvous hashing, replica countsCells and durable cell ownership
Process supervision and port allocationRuntime resource policy
Deploy intake, staging and bundlingServing application requests
The routing document every ingress reads—

Vocabulary follows Celld: a deployment is what Celld serves, identified by its version; a deploy is one run of scafo deploy; a build is compiling only. Celld exposes one current deployment per application fleet, and Scafo records a monotonic deployment revision rather than a selected version: there is no per-deployment host and no historical deployment selector.

Note

/.well-known/scafo/health is the Scafo node/API health endpoint. /.well-known/celld/health is the deployed application's health endpoint, served on application hosts.

#Requirements

RequirementDetail
Celld 0.5.0 or newerThe runtime. The container image bundles 0.6.2; the Linux installer downloads and verifies it. scafo sail checks the version at start and refuses anything older than 0.5.0.
S3-compatible storeMust honour conditional writes — If-None-Match: * on create, If-Match: <etag> on update — and Range reads, which Celld needs for cell data. Tested against SeaweedFS and RustFS.
Node.js ≥ 24.17.0For the CLI installed from npm and for local development. The container image and compiled binaries carry their own runtime.
esbuildOnly to bundle Worker entries on the node. Bundled in the image; installed by the Linux installer; scafo deploy --no-bundle skips it.
wireguard-toolsAn operating-system prerequisite when SCAFO_TRANSPORT=wireguard. Scafo never brings the interface up itself.
An ingressCaddy with the scafo-ingress modules, or Traefik v3 with its http provider.
LinuxFor a node. scripts/install.sh refuses non-Linux hosts and musl-based distributions.
Read more in Docs > Quick Start.

#License and hosting

Scafo and scafo-ingress are released under the Apache-2.0 and MIT licenses respectively. This site is hosted on Netlify, which sponsors the project's open-source plan.