An example Ruby-based embedded Linux system with a cloud dashboard. Uses JSON-RPC over websocket for cloud-to-device communication. Support for authenticated cloud to device, and device to cloud RPC calls.
Device health monitoring and acceptance/rejection of new devices:

An example RPC call to get containers, and logs from those containers, with a UI:

The device stack contains three containers:
jsonrpc-client: Bridge between dashboard traffic and device RPC traffic.worker: Example worker container that handles and can make RPC calls.nats: Device-local NATS broker used for internal messaging.
The worker client can be extended with more functionality, or additional containers can be added to the stack.
jsonrpc-client manages websocket connectivity between dashboard and device to enable two-way communication.
This client acts as a bridge between the websocket, and NATS. It also handles all auth.
The cloud side is a Rails dashboard in cloud/cloud-dashboard.
Authentication follows a similar (but more secure) model used by mender-connect:
- Each device has a public/private key pair.
- Device identity is established via key-based trust.
- UI provides accept/reject controls for presented public keys.
./run-dev.sh runs scripts/ensure-cloud-keys.sh before starting containers.
The script creates cloud/cloud-dashboard/config/crypto/cloud_private.pem when missing, derives cloud/cloud-dashboard/config/crypto/cloud_public.pem from it, and syncs that public key to device/keys/cloud_public.pem for the device-side read-only mount.
- On websocket connect, the device sends a JSON-RPC authentication request using
AUTH_RPC_METHOD. - The authentication request includes the configured
DEVICE_IDand the device public key. - Before any outbound websocket message is sent, the bridge signs the RPC payload with the device private key.
- Signing adds a
metaobject containing the signer ID, audience ID, direction, nonce, timestamp, algorithm, and signature. - The audience ID says who the signed message is intended for. This prevents a message with a valid signature from being replayed or forwarded to a different recipient that should not accept it.
- The cloud validates device-originated messages with the device public key.
- Inbound cloud messages follow the same pattern in reverse. The cloud signs websocket messages with its private key, and this bridge verifies them with
CLOUD_PUBLIC_KEY_PATHbefore handling or forwarding the JSON-RPC content. - The bridge expects cloud messages to be signed by
cloud-dashboard, addressed to thisDEVICE_ID, and marked with directioncloud_to_device. Device messages sent by the bridge are addressed tocloud-dashboardand marked with directiondevice_to_cloud.
From repo root:
./run-dev.shTo stop both stacks:
./run-dev.sh down