OpenIWeb v0.1.0: a lower self-hosting barrier, simpler node management
The first public release. Self-hosting without learning containers or operations: hand an MCP endpoint and one key to an AI coding agent, and applications deploy on your own node; one port open to the internet, untrusted code confined to a sandbox, every delegated key instantly revocable. Whole-node idle memory ≤ 240 MB.
이 글은 영어로 작성되었습니다. 중국어 버전 읽기 →
$ curl -H "Host: $IWEB_BASE_HOST" http://127.0.0.1:9010/_iweb/health
OpenIWeb 0.1.0 is out (2026-09-06, the first public release). It is an open-source personal application node: self-hosting without containers, databases, or network-operations knowledge; hand the MCP endpoint and one 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.
Until now, running personal apps on your own server meant one of two roads: learn the whole operations stack, from containers and databases to reverse proxies, or hand your data to someone's PaaS. AI coding agents can already do most of that work; what they lack is a controlled entry: one endpoint, one key, and one clear boundary. OpenIWeb is a node built around that entry; the repo's first commit landed on 2026-08-11, and the tag came less than a month later.
One port open to the public internet
On a self-managed server, the database, the admin panels, and object storage each listen on their own socket, and every one of them is exposure you have to guard. OpenIWeb pulls the whole node behind a single port. kernel-rs (~4MB Rust static binary) listens on :8080, handling host routing, owner-key auth, and node recovery, and proxying traffic per application with WebSocket upgrade tunnels. It is the node's only published port; every other listener (RustFS, the control API, and each celld) 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 terminates 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/).
How the 240 MB is measured
The node is idle (no in-flight requests) and has completed at least one fresh storage-lease renewal cycle; per-process RssAnon is sampled and summed, and reclaimable file-backed page cache (RssFile) is excluded. Measurements recorded in the spec: lima 159 MB, a cloud host at 162.3 MB, and an iMac at 231.3 MB.
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.
Ops gathered into one MCP endpoint
The operations entry for an AI agent is this one endpoint. mcp.<base>/mcp is a protected system application: every JSON-RPC request (including initialize and tools/list) must carry an owner key as a Bearer token, and the worker forwards the credential per request and never stores it. Wiring an agent in is one standard MCP config:
{ "mcpServers": { "OpenIWeb": { "url": "https://mcp.<base>/mcp",
"headers": { "Authorization": "Bearer <owner-key>" } } } }
The tool surface at 0.1.0 carries 19 tools in three groups: application lifecycle (admit, prepare, readiness, activate, start, stop, rollback, versions, …), workspace read/write/delete, and domain listing/registration. Deploying, verifying, rolling back, and cleaning up all happen under the same key's authorization.
Inventory: all 19 MCP tools
application iweb_application_list iweb_application_start
lifecycle iweb_application_admit iweb_application_stop
iweb_application_prepare iweb_application_rollback
iweb_application_readiness iweb_application_delete_version
iweb_application_activate iweb_application_inspect
iweb_application_versions
iweb_application_delete_data
iweb_application_metrics
workspace iweb_workspace_list iweb_workspace_read_text
iweb_workspace_write_text iweb_workspace_delete
domains iweb_domain_list iweb_domain_register
Untrusted code only enters a sandbox
Application code may be copied from the internet or generated by AI, so it is untrusted by default; every application is isolated from the node control plane and from every other application, with no switch to turn that off. The runtime splits along that trust line.
The trusted tier: celld v0.3 (Cloudflare Workers API). Applications 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), the only path new code takes into the node. Isolation is enforced inside the engine, with host services only and 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.
Layout: the four storage buckets
RustFS keeps four buckets with distinct roles: iweb-workspace, iweb-cells-<app>, iweb-apps, iweb-system.
Every key you hand out can be taken back
Keys follow the GitHub PAT model: one identity, many revocable tokens. The console issues delegated keys in the iwb_<id>_<secret> format with absolute expiry (1/7/30 days or permanent), and its copy button produces a ready-to-paste Chinese deployment prompt with the MCP endpoint and key already templated; paste it straight into any AI agent.
Revocation takes effect immediately: tickets invalidate, monitored WebSockets close, and later requests get 401. The audit trail is append-only and per-key-attributed; every control-plane operation is recorded, rejected 401 attempts included, with rotation capped at 4 MiB.
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(a pure static site using only celld's assets file interface),search(D1/SQLite search with parameterized SQL), andcollab(two celld instances sharing one Durable Object for cross-instance realtime collaboration over WebSocket).Testing: 489 bun tests; the Rust side runs cargo test and clippy; plus the kernel-recovery black-box contract suite.
Example: demo app domains and how to verify them
hello.<base> (pure static), search.<base> (D1/SQLite search), collab.<base> and collab-b.<base> (cross-instance realtime collaboration). Open collab and collab-b in two browser windows and watch messages jump across instances in real time.
Known limitations: TLS and 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 and the console, 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
Changelog: GitHub Release v0.1.0
Docs: openiweb.jixoai.com · README · Chinese README · node-boundary spec
Install: see the Install section above (docker compose build from the tag)
Discussion: GitHub Issues
On this blog: OpenDWeb v0.4.2 · OpenTray v0.21.1
Chinese version: /zh/blog/2026-09-06-openiweb-v0-1-0/
