Getting started

Everything you need to deploy and run apps on shadw — the self-hosted, peer-to-peer cloud.

Introduction

shadw turns any machine you run into a region. Nodes find each other over a real peer-to-peer mesh (Iroh QUIC, with NAT traversal + relay fallback) and serve your deployments by anycast — no data center, no public IPs. The platform is two layers over one isolation backend:

  • Builds — turn a git repo into build output (framework detection or a Dockerfile).
  • Fluid compute — serve functions on long-lived instances that handle many concurrent requests, autoscale, and scale to zero.

Everything below talks to a node's admin API (default 127.0.0.1:8786); the public gateway serves traffic on :8787.

Quickstart

From the dashboard, click New Project, pick a template or paste a Git URL, and deploy. Or via the API:

bashdeploy.sh
curl -X POST http://127.0.0.1:8786/v1/git/deploy \
  -H 'content-type: application/json' -H 'x-hive-team: personal' \
  -d '{ "repo_url": "https://github.com/acme/app", "project": "my-app", "production": true }'
# -> { "build_id": "dpl-…", "project": "my-app" }

Your deployment is reachable instantly at my-app.localhost:8787 (a self-refreshing Building… page shows until the build finishes).

Deploying apps

shadw detects how to build your repo and produces a deployment routed by its subdomain.

From a Git repository

Framework-Defined Infrastructure detects Next.js, Vite, React, SvelteKit, Nuxt, Vue, Astro, Remix, Express and more — runs install/build and normalizes the output into static assets and/or a serverless server.

Containers (Dockerfile)

If a Dockerfile is present, shadw builds the image and runs it as a container (Railway-style). Stateful container singletons use consensus-free leases + fencing, so a node failure triggers automatic failover.

Build configuration

Override detection per project under Settings → Build: install/build commands, output directory, and root directory (monorepos).

The latest production deploy owns the project's domain; each deploy also gets a per-deployment URL. Roll back instantly by promoting a prior deployment.

Environment & secrets

Set variables when creating a project or under Settings → Environment Variables. They're injected into both build and runtime — so NEXT_PUBLIC_*, VITE_* and server config all work.

Secrets are encrypted at rest

Variables marked Sensitive are sealed with ChaCha20-Poly1305 before they touch disk — stored as enc:v1:…, masked in API responses, and decrypted only when injected.

bashenv.sh
curl -X POST http://127.0.0.1:8786/v1/projects/my-app/env \
  -H 'content-type: application/json' -H 'x-hive-team: personal' \
  -d '{ "key": "API_KEY", "value": "sk-live-…", "target": "all", "sensitive": true }'
Back up $HIVE_DATA/secret.key (or set HIVE_SECRET_KEY) — without it, sealed secrets can't be decrypted.

GitOps

Connect GitHub once and shadw manages your org as code: it commits project config to a repo as openedge.yaml and keeps it in sync.

  • Push to deploy — a push triggers a build & deploy via an installed GitHub Action + webhook.
  • Config-as-code — declarative config, versioned in git.
  • Two-way sync — dashboard changes commit back; commits redeploy.

The workflow calls your node's public webhook (OPENEDGE_WEBHOOK_URL) at /v1/git/webhook.

Regions & the peer-to-peer mesh

Your regions are wherever your nodes actually are — each node geolocates and is auto-placed on its continent.

  • Iroh QUIC — direct, encrypted connections with NAT traversal and relay fallback.
  • Anycast — requests route to the lowest-latency healthy node, failing over automatically.
  • Mesh routing — any node can serve any deployment by proxying to a peer.
bashadd-node.sh
hive-cloud --name node-b --peer http://<node-a-ip>:8786
# region is auto-derived from the node's real location

Domains & TLS

Every project gets <project>.localhost:8787. Deployments route purely by subdomain, so the same project is reachable at <project>.<your-domain> once the gateway is exposed there.

The gateway terminates TLS (self-signed locally, or your cert via HIVE_TLS_CERT/HIVE_TLS_KEY) and runs an authoritative DNS server. Add custom domains under Domains.

CLI

The repo ships CLIs that talk to a node's admin API.

bashcli.sh
fluidctl deploy examples/hello     # deploy a local app
fluidctl ls                        # list deployments
hivectl submit --image node:20 -c 'npm ci' -c 'npm run build' --follow

API reference

All endpoints live on a node's admin API (default :8786). Authenticate with a platform API key (hive_…, created under Settings → API Keys or POST /v1/apikeys) via Authorization: Bearer — the key is bound to its team, so no team header is needed. Without a key, the x-hive-team header scopes requests in dev mode; when HIVE_JWT_SECRET is set, mutations require a JWT minted with POST /v1/token.

MethodEndpoint
POST/v1/git/deploy
GET/deployments
POST/deployments
DELETE/v1/deployments/:id
POST/v1/deployments/:id/promote
POST/v1/projects/:project/redeploy
GET/v1/projects/:project/settings
POST/v1/projects/:project/env
PUT/v1/projects/:project/functions
GET/v1/regions/catalog
GET/v1/nodes
GET/v1/overview
POST/v1/sandbox
POST/v1/apikeys
POST/v1/token

Self-hosting

shadw is one node binary. Run at least two for the full mesh (anycast, failover):

bashcluster.sh
hive-cloud --name node-a --listen 127.0.0.1:8787 --admin 127.0.0.1:8786

HIVE_DATA=~/.hive-cloud-b HIVE_DNS_ADDR=127.0.0.1:5355 HIVE_TLS_ADDR=127.0.0.1:8444 \
  hive-cloud --name node-b --listen 127.0.0.1:8789 --admin 127.0.0.1:8788 \
  --peer http://127.0.0.1:8786
  • $HIVE_DATA — durable state dir (snapshot, blobs, GuardianDB, secret key)
  • HIVE_TLS_CERT / HIVE_TLS_KEY — production TLS
  • HIVE_JWT_SECRET — require Bearer auth on mutations
  • HIVE_SECRET_KEY — at-rest encryption key for secrets

Open the dashboard