$git clone https://github.com/bex-co/bexThe open-source Render alternative — AI-native.
| 1 | # bex |
| 2 | |
| 3 | **The open-source Render alternative — AI-native.** |
| 4 | |
| 5 | Push a Git repo (or a prebuilt image), get a running HTTPS service at `<name>.onbex.co` — on machines you own. bex runs identically as a local Docker mock and on Hetzner; only the infrastructure provider overlay changes. Built so AI agents can deploy and operate apps as first-class users, not an afterthought. |
| 6 | |
| 7 | [](LICENSE) [](https://github.com/bex-co/bex/actions/workflows/deploy.yml) [](https://github.com/bex-co/bex/actions/workflows/docs.yml) |
| 8 | |
| 9 | > [!WARNING] > **bex is under active development and is not yet ready for production use. APIs, configuration, and behavior may change without notice.** |
| 10 | |
| 11 | ## Why bex |
| 12 | |
| 13 | - **Own your PaaS.** Render's developer experience — deploy-from-git, custom domains + TLS, suspend/resume — on your own hardware, Apache-2.0. |
| 14 | - **Drop-in familiar.** `bex.yml` is `render.yaml`-shaped, and `bex-api` speaks Render's REST and GraphQL, verified against Render's OpenAPI spec ([docs/ADR006-bex-api.md](docs/ADR006-bex-api.md)). How far the compatibility actually goes — every Render capability × REST/GraphQL/MCP/UI, with evidence — is the parity ledger ([docs/ADR018-render-parity.md](docs/ADR018-render-parity.md)). |
| 15 | - **Built for agents.** Every action is an API call or a Kubernetes CR; state is machine-readable (`phase` / `revision` / `url`). No dashboard-only actions. See the mission and roadmap in [docs/ADR008-vision.md](docs/ADR008-vision.md). |
| 16 | |
| 17 | ## Quickstart: local mock (machines = Docker containers) |
| 18 | |
| 19 | Prereqs: Docker (OrbStack works), Go 1.25+, `kubectl`, `kind`, `clusterctl`. |
| 20 | |
| 21 | ```bash |
| 22 | # 1. stand up the mock substrate: kind infra cluster + Cluster API + CAPD |
| 23 | # + an app cluster whose nodes are Docker containers |
| 24 | bash scripts/mock-cluster.sh # writes infra/local/bex.kubeconfig |
| 25 | export KUBECONFIG=$PWD/infra/local/bex.kubeconfig |
| 26 | |
| 27 | # 2. build the operator image, load it into every node, deploy it as a pod |
| 28 | ( cd lego/operator && make docker-build IMG=bex-operator:dev ) |
| 29 | docker save bex-operator:dev -o /tmp/bex-op.tar |
| 30 | for n in $(kubectl get nodes -o name | sed 's|node/||'); do |
| 31 | docker cp /tmp/bex-op.tar "$n":/op.tar && docker exec "$n" ctr -n k8s.io images import /op.tar |
| 32 | done |
| 33 | ( cd lego/operator && make deploy IMG=bex-operator:dev ) # ns bex-system, BEX_RUNTIME=kubernetes |
| 34 | # local CAPD only: pin the operator to the control-plane node (see docs/ADR004-deployment.md) |
| 35 | kubectl -n bex-system patch deploy bex-controller-manager --type merge -p \ |
| 36 | '{"spec":{"template":{"spec":{"nodeSelector":{"node-role.kubernetes.io/control-plane":""}, |
| 37 | "tolerations":[{"key":"node-role.kubernetes.io/control-plane","effect":"NoSchedule"}]}}}}' |
| 38 | kubectl -n bex-system rollout status deploy/bex-controller-manager |
| 39 | |
| 40 | # 3. deploy an App — the operator reconciles it onto the worker machines |
| 41 | kubectl apply -f examples/whoami-app.yaml |
| 42 | kubectl get pods -l app.bex.co/app=whoami -o wide |
| 43 | |
| 44 | # 4. ★ add a machine, then scale the App onto it |
| 45 | bash scripts/mock-cluster.sh scale 2 |
| 46 | kubectl patch apps.app.bex.co whoami --type merge -p '{"spec":{"replicas":6}}' |
| 47 | |
| 48 | # fast dev loop (optional): run the operator from source instead of as a pod — |
| 49 | # ( cd lego/operator && make install && BEX_RUNTIME=kubernetes make run ) |
| 50 | ``` |
| 51 | |
| 52 | **Deploy to Hetzner:** same bex, different provider — swap `infra/clusterapi/overlays/local-capd` → `…/hetzner-caph`. See [infra/README.md](infra/README.md). |
| 53 | |
| 54 | ## The `App` resource |
| 55 | |
| 56 | ```yaml |
| 57 | apiVersion: app.bex.co/v1alpha1 |
| 58 | kind: App |
| 59 | metadata: { name: whoami } |
| 60 | spec: |
| 61 | image: traefik/whoami # prebuilt image; OR build from git with `repo:` + `branch:` |
| 62 | port: 80 |
| 63 | replicas: 2 # pods bin-pack across machines |
| 64 | ``` |
| 65 | |
| 66 | `kubectl get apps.app.bex.co` shows phase / revision / url. Prefer Render-style config? `scripts/app-apply.sh <bex.yml>` applies a `render.yaml`-shaped `bex.yml` |