ORCHD

the open-source, self-hosted Fly.io alternative

Run a thousand small apps
on one box.

Hostname routing, per-tenant isolation and scale-to-zero, without the platform bill. ORCHD is a single Go daemon that provisions per-tenant workloads, gives each one a hostname, caps and isolates it, puts it to sleep when nobody is using it, and wakes it on the next request in about a second. No cluster, no control-plane sprawl, no YAML.

~0.9 s
wake from zero
~2.8 s
cold provision
0 MB
RAM while idle
1 binary
control plane + gateway

measured on a Hetzner Cloud VM under gVisor, tinbase workload incl. initdb

the problem

Idle tenants are the expensive ones

Preview environments, per-customer backends, per-project dev servers, agent sandboxes — they all have the same shape: many small workloads, each needing its own URL and its own data, almost all of them idle almost all of the time.

A process manager is too little

systemd or pm2 will keep N processes alive, but nothing hands out hostnames, mints credentials, isolates a tenant from its neighbour, or reclaims the memory of the 900 tenants nobody is using.

Kubernetes is too much

A cluster to run 40 MB dev servers means an API server, etcd, a CNI, an ingress controller and a knative-shaped add-on before the first request is served — and someone to keep all of it alive.

A PaaS is someone else's box

Per-app pricing on a platform you do not operate stops being an option the moment your unit is a free-tier tenant, or the code you run is untrusted, or the margin is the product.

the shape

One daemon, three records

Everything ORCHD does is expressed with a project, a workload and a route. The control plane provisions and mints; the gateway resolves hostnames, wakes what is asleep, and proxies. Both live in the same binary.

                     *.example.com          (wildcard DNS -> the box)
                            |
                     +--------------+   gateway: Host -> route table -> workload,
                     |  gateway     |   wake if suspended, reverse-proxy
                     |  :8081       |   (HTTP, WebSockets, streaming)
                     +--------------+
                            |
        +-------------------+-------------------+
   +----------+        +----------+        +----------+     one instance per
   | workload |        | workload |        | workload |     workload, its own
   | + volume |        | + volume |        | + volume |     volume, suspended
   +----------+        +----------+        +----------+     when idle
                            ^
                     +--------------+   control plane: create projects and
                     |  API :8080   |   workloads, mint keys, attach domains,
                     +--------------+   back up, place in a region
The runtime under the workloads is a swappable driver: host processes locally, Docker + gVisor on a Linux box, microVMs later. Nothing above the driver changes.

Project

grouping

A tenant, an environment, a customer. Owns workloads and cascades on delete.

Workload

the unit

One routable, independently scheduled, scale-to-zero instance with a volume, resource caps and env.

Route

addressing

A hostname pointing at a workload. Default subdomain, custom domains, or a local port.

in practice

A project is one call away

The control plane is an ordinary JSON API behind a bearer key. Everything the admin panel does, you can do with curl — or with a template, which describes a whole multi-workload project in one file that lives in the repo.

provision, then use the endpoint
curl -X POST https://api.example.com/v1/projects \
  -H "Authorization: Bearer $ORCHD_KEY" \
  -d '{"name":"acme","workloads":[{"preset":"vite"},{"preset":"api"}]}'

# -> workloads, each with routes, endpoints and keys.
#    First request through the gateway wakes them.
orchd.json — a template in the repo
{
  "name": "acme",
  "workloads": [
    { "name": "db",  "kind": "tinbase" },
    { "name": "api", "kind": "node", "dir": "api",
      "install": ["npm","install"],
      "run": ["node","index.js"], "port_env": "PORT" },
    { "name": "web", "kind": "static", "dir": "web" }
  ]
}

The same file runs without a control plane at all: npx orchd up boots every workload on your machine, each on its own port. See the CLI.

what you get

Built in, not bolted on

Scale-to-zero + wake→

An idle reaper suspends what has not been asked for; the gateway wakes it on the next request. keep_warm pins the ones that must stay hot.

Isolation without KVM→

The Docker driver runs tenants under gVisor, a userspace kernel — VM-grade syscall isolation on a plain cloud VM, plus memory, CPU and pid caps per container.

Hostnames and TLS→

Default subdomains, bring-your-own domains, path subroutes, and on-demand certificates gated so a cert is only ever issued for a host that resolves to a real workload.

Templates→

One orchd.json describes a multi-workload project. Provisioning is async, so a heavy first install never blocks the call.

Versioned images→

Freeze a template into an immutable v1, v2… — a tarball plus a container image per workspace — push it to a registry, import it on another instance.

Backups that stay small→

Byte-exact volume snapshots to a local dir or S3/R2 over hand-rolled SigV4, excluding everything derived. The control-plane index is backed up too.

Keys, roles, rate limits→

A bootstrap key from a file on the box, minted keys stored hashed, readonly vs admin roles, and a per-key token bucket so one client cannot starve another.

Replaceable parts→

Runtime driver, state store, backup target, event sink and metrics sink are all interfaces. Most switch from the settings page; the rest are one env var.

Runs on your laptop→

The same control loop runs with no Docker at all — workloads as host processes on stable ports, or on a real wildcard *.test domain with trusted TLS.

who uses it

ORCHD is the substrate, not the product

It is a standalone orchestrator with no opinion about what it runs. Two products are being built on it — and they are users of ORCHD, not part of it.

tinbase cloud

hosted backends

One dedicated Supabase-compatible backend per project, coupled the way Supabase Cloud couples them, but a single small process per tenant instead of a container stack.

RapidNative dev environments

per-project runners

A web runner, a mobile runner, an API server and a dev database per generated project — mostly idle, running untrusted user code, which is exactly why the isolation matters.

Start with why it exists

The docs open with the reasoning — the problem, the goals, and the things ORCHD deliberately refuses to do — before any endpoint.

from the same team

Related projects

ORCHD is built by the makers of these open-source tools and products.