Vnutri
An on-premise realtime communication system designed around hard privacy, hardware and infrastructure constraints.
The operational problem
Enterprise organizations handling sensitive legal, financial, or industrial data require real-time collaboration but cannot accept third-party cloud hosting, external metadata inspection, or ongoing cloud subscription vulnerabilities.
The architectural challenge: Design a turn-key, physical hardware appliance that installs directly into a client's server room, operates under strict air-gapped or LAN constraints on low-power ARM silicon (2GB RAM), guarantees end-to-end zero-knowledge encryption, and delivers a consumer-grade messaging experience across Web and iOS.
Hardware & Security Constraints
Appliance & Network Topology
┌──────────────────────────────────────┐
│ CUSTOMER OFFICE (AIR-GAPPED LAN)│
│ │
│ ┌────────────────────────────────┐ │
│ │ ARM BOX (Внутри.Лайт / 2GB) │ │
│ │ │ │
│ │ ┌────────┐ ┌──────────────┐ │ │
│ │ │ Axum │ │ SQLCipher │ │ │
│ │ │ Server │──│ (eMMC WAL) │ │ │
│ │ │ REST │ │ WriteBuffer │ │ │
│ │ │ WS Hub │ └──────────────┘ │ │
│ │ └───┬────┘ ┌──────────────┐ │ │
│ │ │ │ MicroSD │ │ │
│ │ │───────│ E2EE Media │ │ │
│ │ │ └──────────────┘ │ │
│ │ ▼ (Unix Socket) │ │
│ │ ┌────────┐ │ │
│ │ │ AI │ (On-Demand Context │ │
│ │ │Sidecar │ Zero-Knowledge) │ │
│ │ └────────┘ │ │
│ └────────────────────────────────┘ │
│ │ ▲ │
LAN Clients ◄───WSS────────┘ │ │
│ │ │
└────────────────────────┼────────────┘
│
Outbound WSS tunnel
│
▼
┌────────────────────────────────────────┐
│ CUSTOMER RELAY VPS (Internet) │
│ ┌──────────────────────────────────┐ │
│ │ Stateless Relay Forwarder │ │
│ │ VAPID Blind Push (FCM/APNs) │ │
│ └──────────────────────────────────┘ │
└─────────────────────┬──────────────────┘
│
Remote Clients ◄──WSS─┘ Architectural Trade-Off Matrix
| Decision | Why | Alternatives Rejected | Trade-Off Incurred |
|---|---|---|---|
| Cross-Platform Rust Crypto (`vnutri-crypto`) | Guarantees exact byte-level cryptographic parity across Web (WASM) and iOS (UniFFI) without rewriting algorithms in JS/Swift. | Separate crypto libs in TypeScript WebCrypto and Swift CryptoKit | Requires cross-compilation toolchains (wasm-pack, uniffi-bindgen) in build pipeline. |
| Binary 33-Byte Frame Header (MsgPack) | Enables O(1) blind message routing by server. Server reads only header bytes without deserializing message payloads. | JSON over WebSocket (v1 protocol) | Requires explicit binary serializer `@msgpack/msgpack` on clients. |
| In-Memory Write-Buffering | Collects incoming messages in a `VecDeque` RAM buffer and flushes in batches (256 items or 100ms interval), cutting disk fsyncs by ~260x. | Per-message instant SQLite commit | Small 100ms window where ungraceful power pull before UPS shutdown requires replay. |
| Dual Payload Ledger (`message_store`) | Stores `target_payload` (for recipient) and `sender_payload` (for sender self-recovery) as blind blobs, ensuring zero-knowledge synchronization. | Single ciphertext with server key escrow | Message table payload size is doubled on disk (2x ciphertext storage). |
| Client-Side Hydration for Replies | Server transmits only `reply_to` UUID. Client hydrates the quoted snippet locally from RAM/IndexedDB, saving bandwidth. | Server injecting quote text into messages | Requires clients to maintain local message store index. |
Hardware Tiers & RAM Budget (500 Concurrent Users)
| Component | RAM Allocation (MB) | Optimization Notes |
|---|---|---|
| Linux Kernel + OS Base | ~120 MB | Stripped headless Alpine/Debian ARM build |
| Rust Axum Process + Tokio Runtime | ~23 MB | Single static binary, multi-threaded worker pool |
| SQLCipher Page Cache (`vnutri.db` + `keys.db`) | ~40 MB | `PRAGMA cache_size = -32000`, `mmap_size = 64MB` |
| Write-Buffer & Log Ring Buffer | ~6 MB | In-memory `VecDeque` batching |
| WebSocket Connections (500 × 50KB) | ~25 MB | Lightweight frame buffers and connection registry |
| Frontend Static Assets (rust-embed) | ~15 MB | Pre-compressed Gzip/Brotli embedded SPA |
| Total Application Footprint | ~130 MB | Leaves ~1.8 GB free on 2GB board for OS page cache |
What was tried and rejected
- JSON WebSocket Protocol (v1): Deserializing verbose JSON strings across 500 concurrent connections generated unacceptable CPU spikes and garbage collection pressure on ARM Cortex-A53 cores. Replaced with the fixed 33-byte binary header + MsgPack protocol.
- Unbuffered Per-Message SQLite Writes: Initial tests showed that writing every incoming message directly with `fsync` exhausted eMMC write endurance limits within months under peak traffic. Implemented RAM write-buffering with a 100ms / 256-message flush trigger.
- Server-Side Message Search: Rejected because it required server-side key escrow or searchable encryption schemes with severe leakage. Shifted all message indexing and search strictly to client-side IndexedDB / SwiftData.
Active Implementation (Phase 9)
Vnutri is currently at Phase 9: Hardware-Agnostic DB & Cross-Platform Media.
- Backend: `axum 0.8`, `deadpool-sqlite`, `rusqlite 0.32` with bundled SQLCipher, MsgPack wire protocol.
- Cross-Platform Crypto: `vnutri-crypto` compiled to WASM (PWA) and UniFFI (iOS).
- Web SPA: React 19, TypeScript, `react-virtuoso` Telegram-style virtualized bubble layout, `framer-motion` swipe-to-reply, and debounced intersection observer batch read receipts.
- Native Client: Swift & SwiftUI native iOS client with SwiftData cache.
- AI Sidecar Interface: Zero-knowledge unix socket interface for on-demand summarization.
Upcoming Milestones
Phase 6 (Full Double Ratchet key rotation per peer), Phase 7 (Admin & compliance tooling), and Phase 10 (WebRTC 1-on-1 voice signaling relay).