Complete interactive map of every layer, protocol, container, and data path · Click anything to expand
1 MB — BIOS boot (for older machines without UEFI)512 MB — EFI System Partition (UEFI boot files)30 GB — Root filesystem (Debian OS, binaries, Podman storage)Remaining — LUKS2 encrypted → /var/lib/archipelago (all user data)archipelago user (UID 1000) with Podman subuid/subgid mappingpodman — Rootless container runtime (replaces Docker)nginx — Reverse proxy (front door for all web traffic)tor — Privacy network daemontailscale — Mesh VPN for remote accesschromium — Kiosk browser for local displaycryptsetup — LUKS disk encryptionxorg — Display server for kiosk modenet.ipv4.ip_unprivileged_port_start=80 — lets rootless Podman bind ports 80+vm.overcommit_memory=1 — for Redis/Valkey container requirementsarchipelago (UID 1000) — main user, owns all containers and dataroot — only for Tor management, LUKS, and boot servicesaes-xts-plain64 (AES-256-XTS) — hardware-accelerated, fastest optionxchacha20,aes-adiantum-plain64 (ChaCha20-Adiantum) — fast on any CPU/root/.luks-archipelago.key (4KB random, auto-generated):80 (HTTP) and :443 (HTTPS with self-signed cert)//rpc/v1, /ws, /health/app/{name}/nostr-provider.js into all app iframes127.0.0.1:9050host.containers.internal:9050100.x.x.x) regardless of networkDEFAULT_FORWARD_POLICY=ACCEPT (required for rootless Podman)127.0.0.1:5678 — localhost only, nginx handles external accessPOST /rpc/v1 — JSON-RPC 2.0 (all commands)WS /ws — WebSocket (live updates, container status, logs)GET /health — Health check (no auth)/archipelago/ — P2P node messaging/content — Content sharing (via Tor)/dwn — Decentralized Web Node protocolauth.* — login, TOTP, password change, onboardingseed.* — generate, verify, restore wallet seedspackage.* — container CRUD (create, start, stop, remove)node.* — DID identity, signing, backupsapp.* — marketplace, app confignotify (signals readiness to systemd)archipelago (UID 1000)archipelago:100000:65536/run/user/1000/podman/podman.sock--cap-drop=ALL then add only what's needed (least privilege)--security-opt=no-new-privileges--read-only)80.71.235.15:3000/archipelago/<script setup lang="ts">rpc-client.ts → POST /rpc/v1/wsX-CSRF-Token headerSameSite=Lax/ — Dashboard (system status, apps)/kiosk — Kiosk mode (public, no auth)/kiosk-recovery — Fallback with IP + QR code/marketplace — App installer/settings — System configuration/app/{name}/ proxy pathsnostr-provider.js injected for identity--kiosk --app=http://localhost/kiosk mode--disable-gpu — software rendering only--renderer-process-limit=1 — single renderer process--js-flags="--max-old-space-size=128" — 128MB JS heap max--disable-metrics-reporting — no telemetry to Google--enable-low-end-device-mode — reduce animations and compositingCtrl+Alt+F7 — switch to kioskCtrl+Alt+F1 — switch to terminalsudo archipelago-kiosk enable|disable|toggle|statusmariadb -uroot -e 'SELECT 1'pg_isready -U postgresbitcoin-cli getblockchaininfoPOST /rpc/v1{"jsonrpc":"2.0","method":"package.start","params":{"id":"bitcoin-knots"},"id":1}WS /ws (HTTP upgrade)bitcoin-knots:8332 (inside archy-net)lnd:10009electrumx:50001 (TCP)tcp://bitcoin-knots:28332 — New block hashes (hashblock)tcp://bitcoin-knots:28333 — New raw transactions (rawtx)127.0.0.1:9050host.containers.internal:9050tor-helper.sh (privileged helper)nostr-provider.js injected into all app iframes/dwn (proxied through nginx)Web5Identities.vue — Create/manage identities (Personal, Business, Anonymous purposes)Web5CredentialsSummary.vue — View issued/held credentials with status badgesWeb5DWN.vue — DWN status, protocol registration, message browserWeb5QuickActions.vue — Copy DID, publish to DHT, trigger syncManagedIdentity — id, name, purpose, did, pubkey, nostr_pubkey, profileVCData — id, issuer, subject, type, claims, status (active/revoked/expired)DwnStatusData — running, sync_status, message_count, registered_protocols@context: W3C Credentials v2 + Ed25519 signature suitetype: ["VerifiableCredential", "CustomType"]issuer: did:key or did:dhtcredentialSubject: { id: did, claims: {...} }proof: Ed25519Signature2020 with verification method referencecredentialStatus: CredentialStatusList2021 for revocationauthentication (vs. assertionMethod for VCs)identity.issue-credential — Issue from any managed identityidentity.verify-credential — Verify by credential IDidentity.list-credentials — List with optional filtering/var/lib/archipelago/credentials/store.jsonRecords.Write — Store a message (UUID-based record_id)Records.Read — Retrieve by record_idRecords.Query — Filter by protocol, schema, author, date rangeRecords.Delete — Remove recorddwn.register-protocol RPC, enforced automatically127.0.0.1:9050)/var/lib/archipelago/dwn/sync_state.jsonPOST /dwn (proxied through nginx)dwn.status — Running state, sync status, message countdwn.sync — Trigger background sync with trusted peersdwn.register-protocol / dwn.list-protocols / dwn.remove-protocoldwn.write-message / dwn.query-messages / dwn.read-message / dwn.delete-message/var/lib/archipelago/dwn/messages/{record_id}.json/var/lib/archipelago/dwn/protocols/{protocol_uri}.jsondid:key:z6Mk... (multicodec Ed25519 in base58btc)did:dht:z... (z-base-32 encoded Ed25519 pubkey)verificationMethod: Ed25519VerificationKey2020 + derived X25519KeyAgreementKey2020authentication, assertionMethod, capabilityInvocation, capabilityDelegationkeyAgreement: X25519 (derived from Ed25519 via Curve25519)EcdsaSecp256k1VerificationKey2019 for Nostr interop/var/lib/archipelago/identities/{id}.jsonidentity.create / .list / .get / .delete / .set-defaultidentity.sign / .verify — Ed25519 message signingidentity.resolve-did / .verify-did-documentidentity.create-dht-did / .resolve-dht-did / .refresh-dht-dididentity.create-nostr-key / .nostr-signidentity.nostr-encrypt-nip04 / .nostr-decrypt-nip04identity.nostr-encrypt-nip44 / .nostr-decrypt-nip44identity.update-profile / .resolve-remote-did/var/lib/archipelago/identity/node_key (32 bytes raw)ed25519-dalek 2.2.0 — Ed25519 signaturescurve25519-dalek 4.1.3 — X25519 key agreement (Ed25519 → X25519 conversion)nostr-sdk 0.44 — secp256k1 signing, NIP-04/44 encryptionmainline 2 — BitTorrent Mainline DHT client (did:dht)zbase32 0.1 — z-base-32 encoding for DID identifiersWeb5 was initiated by TBD (Block/Jack Dorsey) and shut down November 2024. Open-source components were donated to the Decentralized Identity Foundation (DIF). The W3C specs (DIDs, VCs) are independent standards with broad industry adoption. Archipelago implements these W3C standards directly with a custom DWN — not dependent on TBD's SDK.
| Component | Spec | Status | Archipelago |
|---|---|---|---|
| DID Core 1.0 | W3C Recommendation | Stable | did:key + did:dht, full DID Document generation |
| VC Data Model 2.0 | W3C Recommendation (May 2025) | Stable | Issue/verify/revoke with Ed25519Signature2020 |
| DWN | DIF Draft | Draft | Custom Records interface, protocol management, Tor sync |
| did:dht | Near v1.0 | Active | Mainline DHT publishing via mainline crate |
| did:ion (Sidetree) | DIF 1.0 | Abandoned | Not implemented — requires Bitcoin + IPFS full nodes |
| Presentation Exchange 2.0 | DIF Ratified | Stable | Verifiable Presentations with holder proof |
| ADR | Decision | Rationale |
|---|---|---|
| ADR-002 | did:key as primary DID method | Self-contained, offline-capable, zero-cost, aligns with sovereignty |
| ADR-008 | Dual key architecture (Ed25519 + secp256k1) | Ed25519 for W3C/Web5, secp256k1 for Bitcoin/Lightning/Nostr ecosystems |
| ADR-011 | Custom DWN, not full W3C spec compliance | TBD shut down, DWN spec stalled. Federation + Nostr relays prioritized for peer sync |
/root/.luks-archipelago.key and mounts it at /var/lib/archipelago.network-online.target. Tor and Tailscale start.archipelago.service launches the Rust binary. Runs crash recovery, starts container state snapshots, initializes JSON-RPC server on :5678.first-boot-containers.sh runs once (guarded by marker file). Creates all containers in tier order: databases → Bitcoin → services → apps./health passes.archipelago-kiosk.service waits for /health endpoint (up to 30s), then starts X11 + Chromium on VT7.--cap-drop=ALL then add only specific capabilities needed. --security-opt=no-new-privileges prevents privilege escalation inside containers./var/lib/archipelago/secrets/ (mode 700). Bitcoin RPC uses HMAC-SHA256 auth hashes, never plaintext.ProtectSystem=strict, MemoryDenyWriteExecute, RestrictRealtime, RestrictAddressFamilies. Backend can only write to approved paths.Architecture analysis sourced from Start9Labs/start-os on GitHub (master branch). Click any layer to expand.
projects/ui/ — Main admin interfaceprojects/setup-wizard/ — Initial setup flowprojects/start-tunnel/ — VPN management UIPatchDB.watch$()toSignal()ApiService abstract class with 100+ methodsstartd — Main daemonstart-cli — CLI interfacestart-container — Runs inside LXC containers, communicates with hostregistrybox — Package registry daemontunnelbox — WireGuard VPN tunnel daemonstartd.service: Type=simple, Restart=always, RestartSec=3/usr/lib/startos/container-runtime/rootfs.squashfs) mounted as OverlayFSlxc.idmap = u 0 100000 65536lxcbr0 (10.0.3.x subnet, host at 10.0.3.1)/media/startos/rpc/service.sock — Inbound (runtime listens)/media/startos/rpc/host.sock — Host callbacks (effects)core/src/net/vhost.rs handles all HTTP routinghickory-server (formerly trust-dns)avahi-resolve-host-name for .local domainsasync-acme) for Let's Encrypt with TLS-ALPN-01 challenge10.0.3.1:1080 for container outbound trafficwg-quick + x25519-dalekInterfacePortForwardControllerSTARTOS_<random> (encrypted) or STARTOS_<random>_UNENCcryptsetup luksFormat/luksOpen with password-based key"password" (changed during setup)cp --reflink=always for instant volume snapshots before upgradesmain (8 GB) — System data, Patch-DBpackage-data (100% remaining) — All service/app data/media/startos/rpc/service.sock (inbound) and host.sock (host callbacks). Services export init(), uninit(), main() via JavaScript ABI.lxcbr0 (10.0.3.x subnet). GPU passthrough support via manifest flag.LxcManager handles creation (30s timeout), garbage collection, and cleanup. Service actors manage per-service state machines. btrfs reflink snapshots before install/upgrade for atomic rollback.0x3b 0x3b 0x02. Enables partial downloads, integrity verification of subsets, and efficient delta updates.manifest.json (metadata) + javascript.squashfs (service logic, Node.js) + images/<arch>/*.squashfs (container filesystems per CPU architecture) + assets.squashfs (optional static assets) + icon + LICENSE.mdinit(), uninit(), and main() in JavaScript. The container runtime provides an Effects interface for host callbacks (dependency queries, config, health reporting)./media/startos/rpc/service.sock/media/startos/rpc/host.sock (Effects interface)rpc-toolkit (custom Rust crate)PatchDB.watch$() → Angular signals via toSignal()ApiService abstract class
/media/startos/data/main/async-acme) with TLS-ALPN-01 challengewg-quick + x25519-dalek (Rust)tunnelbox (symlink of startbox binary).local domainslxcbr0 bridge, host at 10.0.3.1
StartOS does not implement Web5 (DIDs, DWNs, or Verifiable Credentials).
Authentication uses password-based sessions and public/private key signatures.
/media/startos/config/preinit.sh runs before anything else. Enables local auth cookie.lshw.lxcbr0) created. Database validated. Service actors start all installed services. Postinit script runs.Architecture analysis sourced from getumbrel/umbrel on GitHub (master branch). Click any layer to expand.
motion package)getumbrel/umbrel-apps, pulls every 5 minutesumbrel.yaml — no database, just a YAML filedockerode library + execa shell callsisomorphic-git for app store managementapp-script)umbrel.service: After=network-online.target docker.service--project-name <app-id>)<app-id>_<service>_1 for DNS compatumbrel_main_network (10.21.0.0/16)exports.sh)app_proxy container (Node.js Express, getumbrel/app-proxy)/images/ (tor, auth-server baked into ISO)HOSTNAME.local accesstor_proxy container on 10.21.21.11 (SOCKS5)tor_server container creating hidden servicesexports.shumbrelos.Dockerfile)/var/log → /data/umbrel-os/var/log/var/lib/docker → /data/umbrel-os/var/lib/docker/home → /data/umbrel-os/home/data partition persists across OS updatesumbrel (UID 1000), default password umbrel--project-name <app-id>). Legacy container naming: <app-id>_<service>_1 for DNS compatibility.umbrel_main_network (10.21.0.0/16). All apps share one network — any container can communicate with any other. Static IPs assigned per service via exports.sh.app_proxy container (getumbrel/app-proxy, Node.js Express) that handles JWT authentication for iframe embedding. Proxies to the actual app on its internal port./images/ (tor, auth-server baked into ISO).umbrel_main_network. Images pinned by SHA256 digest. Apps define their own security constraints (no enforced capability dropping).exports.sh exports environment variables (IPs, ports, credentials) for dependency resolution. hooks/ directory with lifecycle scripts: pre/post-install, pre/post-start, pre/post-stop, pre/post-update, pre-uninstall.getumbrel/umbrel-apps). Cloned locally, pulled every 5 minutes. Community app stores supported. implements field enables alternative implementations (e.g., Bitcoin Knots for Bitcoin Core).app-script (bash, labeled "legacy")settings.yml can map dependency (e.g., bitcoin → bitcoin-knots)10.21.21.11 (tor_proxy container)getumbrel/umbrel-apps (GitHub)umbrelOS does not implement Web5 (DIDs, DWNs, or Verifiable Credentials).
Authentication uses a single-user JWT model. Per-app passwords are derived from a deterministic seed via HMAC-SHA256.
UMBREL_PROXY_TOKEN.--cap-drop=ALL, no no-new-privileges by default.umbrel.service starts umbreld --data-directory=/home/umbrel/umbrel./images/. Prevents stale state from previous versions.tor_proxy + auth containers first, then all installed apps in parallel. Express HTTP server starts on port 80. App store update loop begins (every 5 min).| Aspect | Archipelago | StartOS | umbrelOS | Notes / Trade-offs |
|---|---|---|---|---|
| Core Architecture | ||||
| Backend Language | Rust | Rust | TypeScript / Node.js 22 | Rust: memory safety, performance, no GC pauses. Node.js: faster prototyping, larger ecosystem, but runtime overhead. |
| Frontend | Vue 3 + Vite 7 + Tailwind | Angular 21 + Taiga UI 5 | React 19 + Vite 6 + Tailwind 4 | All modern choices. Angular is heaviest (TypeScript-only). Vue/React are lighter. Tailwind enables rapid UI iteration. |
| API Protocol | JSON-RPC 2.0 | JSON-RPC (rpc-toolkit) | tRPC v11 | JSON-RPC is standard and language-agnostic. tRPC gives end-to-end TypeScript type safety but couples frontend/backend. |
| State Sync | Pinia + JSON Patch over WebSocket | Patch-DB (CBOR diffs over WebSocket) | Zustand + TanStack React Query | Patch-DB is most efficient (binary diffs). Archipelago and StartOS push updates; Umbrel polls via React Query. |
| Reverse Proxy | Nginx (external, battle-tested) | Built into Rust backend (Axum/Hyper) | None (Express on :80 + per-app proxy containers) | Nginx: proven, configurable, rate limiting. Built-in: fewer moving parts. Umbrel: no central proxy means no rate limiting or security headers. |
| Container Isolation | ||||
| Container Runtime | Podman (rootless, OCI) | LXC (system containers, AppArmor) | Docker 28.5 (rootful) | Podman: no daemon, rootless by design. LXC: heavier isolation (full system containers). Docker: rootful daemon is a larger attack surface. |
| Rootless Containers | Yes (all containers as UID 1000) | User namespaces (UID 0 → host 100000) | No (Docker daemon runs as root) | Rootless Podman: container escape = unprivileged user. LXC: namespace mapping mitigates. Docker rootful: escape = root on host. |
| Capability Dropping | --cap-drop=ALL + whitelist |
AppArmor profiles (generated) | Not enforced by default | Archipelago: explicit least-privilege. StartOS: AppArmor provides MAC. Umbrel: apps define their own security (inconsistent). |
| Network Isolation | Per-tier networks (archy-net + bridge) | Per-service veth on lxcbr0 | Flat bridge (10.21.0.0/16, all apps share) | Archipelago/StartOS: apps can't see each other unless connected. Umbrel: any container can reach any other. |
| Memory Limits | Per-container (128MB–4GB) | Configurable via manifest | Not enforced by default | Memory limits prevent a single app from consuming all RAM and crashing the system. |
| Security | ||||
| Disk Encryption | Mandatory LUKS2 (AES-XTS or ChaCha20-Adiantum) | Optional LUKS on LVM/btrfs | None | Physical theft risk: Archipelago data is unreadable. StartOS depends on user choice. Umbrel data is fully exposed. |
| Security Headers | CSP, HSTS, X-Frame-Options, Permissions-Policy | Partial (built-in proxy) | None (no central proxy) | Headers prevent XSS, clickjacking, and protocol downgrade attacks. Critical for browser-based management. |
| Rate Limiting | Auth 3/s, RPC 20/s, P2P 10/s | RBAC via method metadata | None | Rate limiting prevents brute-force password attacks and API abuse. |
| TLS | Self-signed cert on :443 + HSTS | Self-signed CA + ACME (Let's Encrypt) | None (HTTP only on LAN) | Without TLS, any device on the LAN can intercept credentials. Tor provides encryption for remote but not LAN access. |
| Auth Model | RBAC (Admin/Viewer/AppUser) + CSRF + session cookies | Password + session cookies + key signatures | Single-user JWT + optional TOTP | Archipelago supports multiple roles. Others are single-user only. |
| App Ecosystem | ||||
| App Format | Container images from private registry | S9PK v2 (signed merkle archive) | docker-compose.yml + umbrel-app.yml | S9PK: most sophisticated (signed, partial downloads, delta updates). Compose: simplest for developers. Registry: fast deployment. |
| Package Signing | Registry-based trust | Ed25519 over blake3 merkle roots | Docker image digests only | StartOS has the strongest supply chain security. Archipelago trusts its private registry. Umbrel relies on Docker content trust. |
| App Store | Built-in marketplace (curated) | Registry-based (marketplace) | Git repository (pulled every 5 min) | Git-based: easy for devs to contribute. Registry: more control. Curated: quality gate but slower additions. |
| Update Mechanism | ISO reflash / manual upgrade | Registry-based OTA | Rugix A/B partitions (atomic, rollback) | Umbrel has the smoothest update path with automatic rollback. Archipelago's ISO approach is most disruptive. |
| Networking & Privacy | ||||
| Tor | System daemon + hidden services (always available) | Removed in v0.4 (planned re-integration) | Optional (containerized) | Archipelago: Tor is first-class. StartOS temporarily lost Tor in 0.4 rewrite. Umbrel: toggle on/off. |
| VPN | Tailscale (WireGuard mesh) | WireGuard (first-class, tunnelbox) | None built-in | Both Archipelago and StartOS offer remote access without port forwarding. Umbrel relies on Tor or manual setup. |
| DNS | System DNS + container NetAvark DNS | Built-in (hickory-server) | Docker DNS + static IPs in exports.sh | StartOS has the most integrated DNS. Archipelago uses standard tools. Umbrel hardcodes IPs. |
| Identity & Web5 | ||||
| DID Support | did:key + did:dht + W3C DID Documents | None | None | Archipelago is the only node OS with decentralized identity support. Enables credential issuance and cross-node trust. |
| Verifiable Credentials | W3C VC 2.0 (Ed25519Signature2020) | None | None | Archipelago can issue and verify digital certificates without any central authority. |
| DWN (Data Store) | Custom implementation + peer sync via Tor | None | None | Personal data store that syncs across nodes. Unique to Archipelago. |
| Nostr Integration | NIP-01/04/44, nostr-provider.js in iframes | None | None | Archipelago injects Nostr identity into every app iframe for seamless decentralized social integration. |
| Infrastructure | ||||
| Base OS | Debian 12 Bookworm (stable) | Debian Bookworm | Debian Trixie (testing) | Stable: proven, security patches. Testing: newer packages but less battle-tested, potential for regressions. |
| Filesystem | ext4 | btrfs (COW snapshots) | ext4 (A/B partitions) | btrfs snapshots enable instant rollback on failed installs. ext4 is simpler and more mature. A/B adds OS-level rollback. |
| Kiosk Display | X11 + Chromium on VT7 | None | None | Plug in a monitor and the dashboard appears fullscreen. Unique physical UX for dedicated hardware. |
| Boot Recovery | Crash recovery + container state snapshots | btrfs snapshots + preinit/postinit hooks | Destroys all containers on every boot | Archipelago/StartOS: resume from last known state. Umbrel: clean slate every boot (slower but deterministic). |