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:
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).
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.
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 }'$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.
hive-cloud --name node-b --peer http://<node-a-ip>:8786
# region is auto-derived from the node's real locationDomains & 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.
fluidctl deploy examples/hello # deploy a local app
fluidctl ls # list deployments
hivectl submit --image node:20 -c 'npm ci' -c 'npm run build' --followAPI 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.
| Method | Endpoint | Description |
|---|---|---|
| POST | /v1/git/deploy | Build & deploy from a git repo |
| GET | /deployments | List deployments |
| POST | /deployments | Create a deployment from a manifest |
| DELETE | /v1/deployments/:id | Delete a deployment |
| POST | /v1/deployments/:id/promote | Promote (instant rollback) |
| POST | /v1/projects/:project/redeploy | Rebuild the latest commit |
| GET | /v1/projects/:project/settings | Project settings (env masked) |
| POST | /v1/projects/:project/env | Set an env var (sensitive ones encrypted) |
| PUT | /v1/projects/:project/functions | Function settings: regions, fluid, duration |
| GET | /v1/regions/catalog | Regions from the live mesh |
| GET | /v1/nodes | Mesh nodes (region, geo, capacity, health) |
| GET | /v1/overview | Overview analytics |
| POST | /v1/sandbox | Run code in an isolated cell |
| POST | /v1/apikeys | Create a platform API key (hive_…, shown once) |
| POST | /v1/token | Mint a short-lived JWT (needs HIVE_JWT_SECRET) |
Self-hosting
shadw is one node binary. Run at least two for the full mesh (anycast, failover):
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 TLSHIVE_JWT_SECRET— require Bearer auth on mutationsHIVE_SECRET_KEY— at-rest encryption key for secrets

