Skip to content

Le nœud d'applications personnel open source pour tout le monde — auto-hébergez sans apprendre l'ops : confiez un endpoint MCP et une clé à votre agent de code IA.

Original (English)

OpenIWeb logo

OpenIWeb is an open-source personal application node for people who don't want to learn containers, databases, or network operations. An AI coding agent (Codex, Claude Code, …) deploys and operates applications on the node through MCP; the owner manages everything from a browser console with a single key.

Applications may be copied from the internet or generated by AI, so they are untrusted by default. Isolating every application from the node control plane and from each other is the product's security bottom line.

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

One OpenIWeb installation is one owner's personal node. Everything except the Kernel ingress — RustFS, the control API, every celld listener — stays on container-internal loopback and is never published.

What's inside

Layer Choice Why
Ingress & control plane Rust kernel (kernel-rs/, ~4MB static binary) One published port, host routing, recovery authority, owner-key auth, per-app proxy with WebSocket upgrade tunnels
Trusted application runtime celld v0.3 (Cloudflare Workers API) Image-seeded fleet apps, one process per app, watchdog soft limits
Untrusted application runtime iweb-wasmd (Wasmtime, wasi:http 0.2 components) The only runtime admission path: engine-enforced isolation, host services, no socket capability
Object storage RustFS (S3-compatible, MinIO lineage) Single-node friendly, low memory envelope, loopback-only
Console SvelteKit + shadcn-svelte static app served as celld native assets Replaceable like any app; never a secret configuration screen

Idle memory envelope: ≤ 240 MB RssAnon for the whole node (spec: openspec/specs/node-boundary/).

Quick start

cp .env.example .env
# Set a unique CELLD_NODE, IWEB_BASE_HOST, a long random IWEB_API_TOKEN,
# and the MinIO-compatible root + celld S3 secrets.
docker compose up -d --build
curl -H "Host: $IWEB_BASE_HOST" http://127.0.0.1:9010/_iweb/health

Prebuilt images are also published to ghcr.io/jixoai/openiweb (multi-arch, built by CI on every release) if you prefer docker run or compose pull over building locally — set IWEB_IMAGE, default in .env.example.

IWEB_BASE_HOST is a hostname suffix only (no scheme/port/path). The container publishes one port (8080 → map it however you like). TLS is terminated in front of the node (1Panel, Caddy, nginx, …); the kernel routes by HTTP Host header only.

Open the console at https://admin.<base>/ and log in with any valid owner key (the bootstrap IWEB_API_TOKEN, or a delegated key issued in the console — see below).

Demo applications

The image ships three reference applications that exercise the runtime end-to-end (see 中文说明 for screenshots-level detail):

App Host Demonstrates
hello hello.<base> Pure static site via celld's wrangler assets interface — no worker code
search search.<base> D1 (SQLite) database search with parameterized SQL
collab collab.<base>, collab-b.<base> Frontend/backend split; two celld instances share one Durable Object for cross-instance realtime collaboration over WebSocket

Owner keys & audit

One identity, many revocable tokens (GitHub PAT model). In the console's Keys & Audit view you can:

  • issue delegated keys (iwb_<id>_<secret>) with absolute expiry,
  • copy a ready-to-paste Chinese deployment prompt containing the MCP endpoint and key for an AI agent,
  • ban a key instantly (in-flight monitor sockets close; new requests get 401),
  • read an append-only, per-key-attributed audit trail of every control-plane operation (including rejected attempts).

The bootstrap IWEB_API_TOKEN always authorizes and cannot be banned — it is the credential face of the api.<base> recovery law: even if every delegated key and the Admin app are compromised, the owner can still reach the Kernel control API directly.

MCP

mcp.<base>/mcp is a protected system application. Every JSON-RPC request — including initialize and tools/list — must carry Authorization: Bearer <owner-key> (bootstrap or delegated). Tools cover workspace read/write/delete and domain listing/registration. The worker forwards the credential per request and never stores it.

Point an MCP client at it like this:

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

Development

bun install          # workspace tooling (tests are bun-native)
bun test             # full battery (489 tests; proxy-immune via bunfig preload)
cd kernel-rs && cargo test && cargo clippy --all-targets   # Rust battery
KERNEL_TEST_COMMAND=$PWD/kernel-rs/target/debug/iweb-kernel \
  bun test tests/kernel-recovery.test.ts    # black-box contract suite (also: node kernel/index.js)
openspec validate --all --strict           # spec discipline

Installs always resolve from the workspace root bun.lock (lockfileVersion 2): running bun install from inside apps/admin-console or any workspace package walks up to the root and uses the root lock, so a subdirectory install cannot bypass the root lock's --frozen-lockfile verification. Stale nested locks (e.g. the pre-monorepo apps/admin-console/bun.lock) are dead weight and were removed; the Docker build likewise installs from the root before the app sources are even copied.

Cross-implementation contract tests drive the Rust kernel and the frozen JS reference kernel (kernel/index.js) through the same black-box suites (tests/kernel-recovery.test.ts, tests/kernel-browser-contract.test.ts, tests/owner-keys.test.ts), so wire-format drift cannot ship silently. A dedicated suite validates every kernel response against the Admin console's own zod schemas.

Multi-arch images: Dockerfile (arm64) and Dockerfile.amd64 (x86_64, with builder knobs CARGO_BUILD_JOBS and CRATES_MIRROR=rsproxy for constrained hosts).

Project shape

kernel-rs/               Rust kernel (ingress, control API, proxy, keys, audit, monitor)
apps/workers/            celld applications: admin, mcp, notes, hello, search, collab
apps/admin-console/      SvelteKit console (built into the image as celld assets)
supervisor/              wasm execution supervisor (in-container, journals execution only)
kernel-rs/wasmd/         iweb-wasmd: the Wasmtime host for admitted components
packages/contracts/      shared cross-implementation contract vectors
packages/worker-shared/  worker-safe helpers (HTML escaping, JSON responses)
scripts/                 node operations (probe matrix, backup, migration, portless …)
openspec/                the product law: specs/, active changes/, archive/
tests/                   bun-native batteries incl. browser-contract suites

Security boundary

OpenIWeb runs a two-tier trust model. celld is the trusted tier: fleet applications (admin, mcp, notes, hello, search, collab) enter the node only through node images you build, run one process per app, and are bounded by a userspace resource watchdog (soft-limit SIGKILL plus per-app restart). There is no celld runtime admission and celld is never a hostile multi-tenant boundary. wasm is the untrusted tier and the only runtime admission path: arbitrary, network-sourced, or AI-generated packages execute as wasi:http 0.2 components under Wasmtime with engine-enforced limits (no socket/TLS/fs capability, host-mediated egress, fuel/epoch/store caps) and host services (KV/SQL/Logging) as the data plane — all self-contained in the node container. The residual trust in wasmd/Wasmtime is explicit; law lives in openspec/specs/application-sandbox/.

Never place secrets in the workspace: credentials live only in node environment or Kernel-issued keys.

Current limitations

  • TLS/wildcard certificates are a deployment concern (kernel is HTTP Host-routing inside the container).
  • Monitor metrics are per-Kernel-lifecycle, not durable history.
  • notes is deployed but not routed (user routes target the wasm tier only).
  • wasm publication stays fail-closed behind its acceptance record and switch; celld publication does not exist (image-only supply).

中文文档见 README-zh.md。完整行为规格见 openspec/specs/