Skip to content

OpenIWeb v0.1.0: hand the ops to an AI agent, keep one revocable key

jixoai v0.1.0 openiweb

The first public cut of OpenIWeb: a single-port Rust kernel, an MCP operations surface, a two-tier trust runtime, built-in RustFS, and revocable owner keys. Hand self-hosting to an AI coding agent and gather management into one key; whole-node idle memory ≤ 240 MB.

Эта запись написана на английский. Читать на китайский →

$ curl -H "Host: $IWEB_BASE_HOST" http://127.0.0.1:9010/_iweb/health

OpenIWeb v0.1.0 is out (2026-09-06, the first public cut). It is an open-source personal application node: you never have to learn containers, databases, or network operations; hand the MCP endpoint and a single key to an AI coding agent (Codex, Claude Code, …) and applications deploy and run on your own node; you manage everything from a browser console with one key.

Background: self-hosting is too hard for most people, and the labor has changed

Running a few personal apps on your own server today means learning the whole operations stack yourself, from containers and databases to reverse proxies and network operations, or surrendering your data to someone's PaaS. AI coding agents can already do most of the deployment and operations work; what they lack is a controlled entry: an endpoint, a key, and a clear boundary.

OpenIWeb answers both with one architecture. Application code may be copied from the internet or generated by AI, so it is untrusted by default, and every application is isolated from the node control plane and from every other application. There is no switch for it.

A single-port Rust kernel: one installation, one entry

The node exposes exactly one port to the public internet: kernel-rs (~4MB static binary) listens on :8080, handling host routing, owner-key auth, and node recovery, and proxying traffic per application with WebSocket upgrade tunnels. Everything else (RustFS, the control API, every celld listener) stays on container-internal loopback, never published:

public Internet
      |
iweb-kernel :8080           the only published port (a single Rust binary)
  +-- api.<base>                  -> Kernel control API (same router/auth as loopback)
  +-- admin.<base>                -> per-app celld :8787 (Admin console)
  +-- mcp.<base>/mcp              -> per-app celld :8797 (MCP endpoint)
  +-- <app>.<base>                -> per-app celld (IWEB_CELLD_PORTS)
  +-- <base>/<app>/app            -> path alias for the same application
                                      |
              RustFS (S3-compatible, loopback-only, no console)
                                      |
          iweb-workspace / iweb-cells-<app> / iweb-apps / iweb-system

TLS is terminated in front of the node (1Panel, Caddy, or nginx); the kernel routes by HTTP Host header only. Whole-node idle memory stays under 240 MB (RssAnon), and the bound is written into the spec (openspec/specs/node-boundary/).

Example: verify the only published port
curl -H "Host: $IWEB_BASE_HOST" http://127.0.0.1:9010/_iweb/health

9010 is any host-side mapped port; inside the container only the kernel's 8080 is exposed.

The MCP operations surface: every request carries a key

The operations entry for an AI agent is one MCP endpoint: mcp.<base>/mcp is a protected system application, and every JSON-RPC request (including initialize and tools/list) must carry an owner key as a Bearer token. Tools cover workspace read/write/delete and domain listing/registration; the worker forwards the credential per request and never stores it. Wiring an AI agent in is one standard MCP config:

{ "mcpServers": { "OpenIWeb": { "url": "https://mcp.<base>/mcp",
  "headers": { "Authorization": "Bearer <owner-key>" } } } }

A two-tier trust runtime: untrusted code only enters a Wasmtime sandbox

Applications split into two tiers, matching two kinds of trust: trusted apps get their own process; untrusted code gets no socket capability.

  • The trusted tier, celld v0.3 (Cloudflare Workers API): apps enter only via the node image you build, one process per app, watchdog soft limits only. The console and the demo apps live here.

  • The untrusted tier, iweb-wasmd (Wasmtime, wasi:http 0.2 components), is the only path new code takes into the node: engine-enforced isolation, host services only, no socket capability. Apps copied from the web or generated by AI enter here.

Object storage is built-in RustFS (S3-compatible, descended from MinIO, single-node friendly, loopback-only with no console), four buckets each with its own role: iweb-workspace, iweb-cells-<app>, iweb-apps, iweb-system.

Example: demo app domains in the trusted tier

hello.<base> (pure static) · search.<base> (D1/SQLite search) · collab.<base> / collab-b.<base> (cross-instance realtime collaboration); open them in a browser to verify.

Revocable owner keys: one identity, many keys

Every key you hand to an AI agent can be taken back at any time. Delegated keys (iwb_<id>_<secret>, the GitHub PAT model) carry absolute expiry; the console copies a ready-to-paste Chinese deployment prompt (MCP endpoint and key included) straight into an AI agent's hands; revocation takes effect instantly (in-flight monitor sockets close; new requests get 401); an append-only, per-key-attributed audit trail records every control-plane operation, rejected attempts included.

The bootstrap IWEB_API_TOKEN always authorizes and cannot be revoked: it is the credential for recovering the node directly through api.<base>. Even if every delegated key and the Admin app are compromised, the owner can still reach the Kernel control API directly.

Example: the MCP endpoint accepts exactly these keys
curl -H "Authorization: Bearer <owner-key>" https://mcp.<base>/mcp

Bootstrap and delegated keys both work; a request without a key is rejected.

The rest, and known limitations

  • Static console: a SvelteKit + shadcn-svelte static app served as celld native assets; it is itself an ordinary app, replaceable as a whole, never a secret configuration screen

  • Three demo applications: hello (pure static via celld assets), search (D1/SQLite search with parameterized SQL), collab (two celld instances sharing a Durable Object for cross-instance realtime collaboration over WebSocket); domains in the example above

  • Testing: 489 bun tests, the Rust side (cargo test / clippy), and the kernel-recovery black-box contract suite

Known limitations: TLS/wildcard certificates are a deployment concern (the kernel does HTTP Host-routing inside the container); monitor metrics follow the Kernel lifecycle and keep no durable history; notes is deployed but not routed; wasm publication stays fail-closed (no celld publication exists; image-only supply).

Install

This release ships as a source-built container image (no registry image published). Build from the tag:

git clone https://github.com/jixoai/openiweb.git && cd openiweb
git checkout v0.1.0
cp .env.example .env   # set CELLD_NODE, IWEB_BASE_HOST, a long random IWEB_API_TOKEN, and the S3 secrets
docker compose up -d --build
curl -H "Host: $IWEB_BASE_HOST" http://127.0.0.1:9010/_iweb/health

Multi-arch: Dockerfile (arm64) and Dockerfile.amd64 (x86_64, with CARGO_BUILD_JOBS and CRATES_MIRROR=rsproxy builder knobs for constrained hosts). Node data lives in the iweb-data volume and RustFS buckets, and configuration lives in .env, so recreating the container keeps state; owner keys are issued by the Kernel/console and revocable from the console, and secrets are never stored in the workspace.

Acknowledgements

The trusted tier stands on celld (DenoLand); RustFS descends from MinIO; the untrusted tier's isolation comes from Wasmtime.

Links