dweb · application-level networking
Application-level logical networks — game rooms, not system VPNs.
Multi-device applications form logical networks — like game rooms, not a system-level VPN — with controlled, invite-based membership. Peers connect directly over QUIC when possible and fall back to a self-hostable relay.
$npx opendweb server
* opendweb server v0.2.1
> Local: http://localhost:8787
> Network: http://192.168.1.100:8787
gateway 8787 · rendezvous 8787 · relay 3340
What’s inside
Identity
Ed25519 EndpointId
Stable identity decoupled from network addresses; z-base-32 display form.
identity
Roster
Signed facts, converged by union-merge
Genesis/Grant/Join/Revoke facts are content-addressed (BLAKE3) and converge by union-merge.
roster
Membership
Controlled, invite-based joins
Issuer-online single redemption: challenge-response PoP plus invite_id CAS consumption.
invites
Session
iroh 1.1: QUIC direct + relay fallback
Direct connections with NAT traversal; falls back to a self-hostable relay. Gating on both sides — gate before data.
session
Sync
Opaque envelopes, bidirectional
Send/receive opaque envelopes both ways; an Automerge adapter is planned as a separate change.
sync
Self-hosting
One-liner server
npx opendweb server or docker ghcr.io/gaubee/dweb — gateway 8787 + relay 3340.
server
Plugins
Marketplace, vendor-neutral core
Any non-builtin first token dispatches adaptively; missing plugins fetch on first use. Cloudflare Tunnel ships as a plugin.
plugins
SDK
Node SDK (napi-rs)
@jixo/opendweb-client-sdk embeds fabrics in your own app (darwin-arm64 / win32-x64).
sdk
Quick start
Start the server, invite a peer, chat
The gateway (8787) serves /healthz, /services.json and rendezvous; the relay (3340) is a separate listener. Invites must be redeemed while the inviter is online — the inviter's process stays running during redemption.
# 1. Start the self-hosted server (gateway + relay) — top-level CLI
npx opendweb server
# or: docker run -p 8787:8787 -p 3340:3340 ghcr.io/gaubee/dweb
# The banner lists every Network address. Any of them is the single
# config entry for clients — the gateway discovers the relay URL
# automatically via /services.json.
# 2. On each client machine: one-time config (persisted to ~/.opendweb/config.json)
npx @jixo/opendweb-example config set relay http://192.168.2.13:8787
# 3. Terminal A: initialize and keep a chat session running
npx @jixo/opendweb-example init --data ~/.dweb-a
npx @jixo/opendweb-example invite --data ~/.dweb-a --ttl 30m # copy the token
npx @jixo/opendweb-example chat --data ~/.dweb-a
# 4. Terminal B (another directory/device): redeem the invite and chat
npx @jixo/opendweb-example join --data ~/.dweb-b <token>
npx @jixo/opendweb-example chat --data ~/.dweb-b* opendweb server v0.2.1
> Local: http://localhost:8787
> Network: http://192.168.1.100:8787
NAME PORT STATE
gateway 8787 entry point
rendezvous 8787 merged into gateway
relay 3340 enabledSelf-host without npx: docker ghcr.io/gaubee/dweb. Behind a reverse proxy or tunnel, set DWEB_PUBLIC_GATEWAY_URL / DWEB_PUBLIC_RELAY_URL — see the README for
the vendor-neutral recipe.
Packages
One CLI, one server binary, one SDK — all published
All packages are published at v0.2.1. The server CLI is the marketplace host; plugins and the Node SDK extend the same fabric.
| npm package | Role |
|---|---|
opendweb | Server CLI — `npx opendweb server` starts the self-hosted gateway + relay; plugin marketplace host |
@jixo/opendweb-server-binary | Server binary wrapper used by the CLI; also exposes a programmatic `startServer()` |
@jixo/opendweb-example | Reference two-process client CLI (`init` / `invite` / `join` / `chat`) |
@jixo/opendweb-client-sdk | Node SDK for embedding fabrics in your own app (napi-rs; darwin-arm64 / win32-x64) |
@jixo/opendweb-config | `definePlugin` helper for local plugin files (runtime-agnostic: deno / bun / node) |
@jixo/opendweb-ext-cf | Cloudflare Tunnel plugin: ingress push via API, DNS routing, end-to-end verification, optional cloudflared co-spawn |
Ecosystem
Vendor integrations are plugins; your app embeds the SDK
The CLI core stays vendor-neutral by construction — any non-builtin first token dispatches to a marketplace plugin. The Cloudflare Tunnel plugin covers no-public-IP deployments; the Node SDK embeds fabrics directly.
Plugin — Cloudflare Tunnel
opendweb plugin add cf # install (detected pm), lock name@version
opendweb cf setup --hostname dweb.example.com
# push ingress via CF API, route DNS,
# write opendweb.config.toml, verify end-to-end
opendweb cf plan --hostname dweb.example.com # zero-side-effect previewNode SDK — fabric in your app
const { Fabric } = require("@jixo/opendweb-client-sdk");
const relay = { mode: "custom", urls: ["http://192.168.2.13:3340"] };
// Machine A: create the fabric (this node becomes root) and sign an invite
const a = await Fabric.createRoot({ dataDir: "/path/a", relay });
const token = await a.invite(60 * 60_000, null); // dweb1.-prefixed token
// Machine B: redeem the token (issuer must be online) and exchange messages
const b = await Fabric.joinWithToken({ dataDir: "/path/b", relay }, token);
await b.connect(a.endpointId);
await a.send(b.endpointId, Buffer.from("ping"));
await a.revoke(b.endpointId); // root-onlyEvent stream: peer-connected / peer-disconnected, roster-updated, message, path-changed (direct / relay), relay-online / relay-offline. Full contract on GitHub.