Core components
m87 CLI (client)
The command-line interface you run on your workstation to interact with remote devices. Primary functions:- Device management (list, approve, reject)
- Remote access (shell, exec, port forwarding)
- File operations (copy, sync)
- Container management (docker commands)
- Authentication (OAuth2 device flow)
- Written in Rust for performance and reliability
- Runs on Linux and macOS
- Located in
m87-clientpackage - Licensed under Apache-2.0
The CLI stores credentials in
~/.config/m87/credentials.json with 0o600 permissions for security.m87 runtime (device agent)
A long-running process that runs on edge devices to enable remote management. Primary functions:- Maintains outbound connection to m87 server
- Executes commands received from authorized users
- Streams logs and metrics
- Handles file transfer operations
- Manages container deployments
- Written in Rust (shares codebase with CLI)
- Linux-only (supports amd64 and arm64)
- Can run as systemd service for production use
- Located in
m87-clientpackage (runtime feature)
m87 server (relay)
The backend service that connects CLI users to device runtimes. Primary functions:- Device registration and approval workflow
- Authentication and authorization
- QUIC tunnel relay between users and devices
- WebTransport support for browser-based access
- REST API for device management
- Written in Rust
- Uses MongoDB for persistence
- QUIC-based tunneling (via Quinn library)
- Located in
m87-serverpackage - Licensed under AGPL-3.0-or-later
443(or 8084): Runtime connections and tunnel traffic (TLS/QUIC)8085: REST API
The server can be self-hosted for on-premise deployments or used via the hosted make87 platform.
Communication flow
Initial device registration
View detailed registration flow
View detailed registration flow
- Device initiates registration: Runtime calls
m87 runtime run --email user@example.com - Server creates request: Stores device info, generates unique
request_id - User reviews request: Runs
m87 devices listto see pending devices - User approves device: Runs
m87 devices approve <request-id> - Server issues credentials: Generates API key for device
- Device polls for approval: Receives API key within timeout
- Runtime saves credentials: Stores in
~/.config/m87/credentials.json - Persistent connection: Device establishes QUIC tunnel to server
Runtime tunnel connection
Once registered, devices maintain a persistent outbound connection:Command execution flow
When you run commands likem87 <device> shell:
- CLI authenticates: Gets OAuth2 token (refreshes if expired)
- CLI requests action: Sends authenticated request to server API
- Server authorizes: Verifies user has access to device (scope-based)
- Server relays: Forwards request through device’s QUIC tunnel
- Runtime executes: Spawns process and captures I/O
- Bidirectional stream: I/O flows through server back to CLI
Shared components
m87-shared
A Rust crate containing types and utilities used by both client and server:- Device system information structures
- Protocol message definitions
- Common serialization formats
- Shared utility functions
This is an internal crate, not published separately. It ensures consistency between client and server implementations.
Technology stack
Core technologies
- Rust 1.85+: All components written in Rust for safety and performance
- QUIC (Quinn): Low-latency, multiplexed tunneling protocol
- Tokio: Async runtime for handling concurrent connections
- TLS/Rustls: Secure communication without OpenSSL dependencies
- MongoDB: Server-side persistence for devices, users, and deployments
Key libraries
| Library | Purpose |
|---|---|
quinn | QUIC protocol implementation |
tokio-rustls | Async TLS connections |
openidconnect | OAuth2 device flow authentication |
jsonwebtoken | JWT validation for API requests |
reqwest | HTTP client for API calls |
serde | Serialization/deserialization |
Deployment patterns
Hosted platform
Use the managed make87 platform (default):Self-hosted
Deploy your own m87 server:Self-hosting requirements
Self-hosting requirements
- MongoDB: For storing devices, users, and state
- TLS certificate: For port 443 (runtime/tunnel traffic)
- OAuth provider: Auth0 or compatible OAuth2/OIDC provider
- Environment variables: See
m87-server/docker-compose.yml
- 1 CPU core
- 512MB RAM
- 10GB storage
Performance characteristics
Connection overhead
- Initial tunnel setup: ~100-200ms (QUIC handshake)
- Command latency: ~5-20ms after tunnel established
- Reconnection: Automatic with exponential backoff
Scalability
- Single server: 1000+ concurrent device connections
- Horizontal scaling: Multiple servers with load balancing
- Connection multiplexing: Multiple streams per QUIC connection
Resource usage
Runtime (per device):- Idle: ~5-10MB RAM
- Active command: +10-50MB depending on operation
- CPU: Minimal when idle, scales with workload
- RAM: ~500MB-1GB
- CPU: 1-2 cores
- Network: ~100KB/s idle, scales with active traffic
The QUIC protocol provides efficient multiplexing, allowing multiple operations simultaneously without additional overhead.