Skip to main content

WebSocket Tunneling

Secure WebSocket tunnels for cloud-to-device communication. Persistent connections, heartbeat monitoring, auto-reconnect with exponential backoff, and TLS encryption.

Overview

The WebSocket Tunnel is the backbone of EdgeFlow's SaaS connectivity. It establishes a persistent, encrypted connection between each device and the cloud, enabling real-time bidirectional communication without requiring the device to have a public IP address or open inbound ports.

How It Works

Device (behind NAT/firewall)          Cloud Server
       │                                    │
       │  1. WebSocket CONNECT (wss://)     │
       │───────────────────────────────────>│
       │                                    │
       │  2. Auth: DeviceID + APIKey        │
       │───────────────────────────────────>│
       │                                    │
       │  3. "connected" confirmation       │
       │<───────────────────────────────────│
       │                                    │
       │  4. Heartbeat (ping every 30s)     │
       │<──────────────────────────────────>│
       │                                    │
       │  5. Cloud sends command            │
       │<───────────────────────────────────│
       │                                    │
       │  6. Device sends response          │
       │───────────────────────────────────>│

Tunnel Agent

The Tunnel Agent runs on each device and manages the WebSocket connection lifecycle. It handles authentication, heartbeats, reconnection, and message routing.

Key Features

  • TLS Encryption — All traffic encrypted via WSS (WebSocket Secure)
  • Auto-Reconnect — Exponential backoff with jitter (up to 60 seconds)
  • Heartbeat — 30-second ping/pong to detect stale connections
  • Authentication Timeout — 10-second window for auth handshake
  • Thread Safety — Concurrent read/write with mutex protection
  • Graceful Shutdown — Clean WebSocket close frame on disconnect

Message Protocol

All tunnel messages use a JSON envelope:

{
  "type": "command",        // connect | connected | ping | pong | command | response
  "id": "msg_abc123",       // Unique message ID for request-response correlation
  "device_id": "dev_xyz",   // Device identifier
  "api_key": "efk_...",     // Only in "connect" messages
  "version": "1.2.3",       // Agent version
  "action": "start_flow",   // For command messages
  "payload": {},            // Action-specific data
  "status": "success",      // For response messages
  "data": {},               // Response data
  "error": "",              // Error message if failed
  "timestamp": "2026-02-21T12:00:00Z"
}

Message Types

Type Direction Description
connect Device → Cloud Authentication handshake with Device ID, API Key, and agent version
connected Cloud → Device Confirmation that authentication succeeded
ping Device → Cloud Heartbeat signal sent every 30 seconds
pong Cloud → Device Heartbeat response confirming connection is alive
command Cloud → Device Remote command with action and payload
response Device → Cloud Command response with status, data, or error

Connection States

┌────────────┐     connect()     ┌──────────────┐
│Disconnected│───────────────────>│ Connecting   │
└────────────┘                   └──────┬───────┘
      ▲                                 │
      │ max retries                     │ auth success
      │ exceeded                        ▼
      │                          ┌──────────────┐
      │   connection lost        │  Connected   │
      │◄─────────────────────────│  (heartbeat) │
      │                          └──────┬───────┘
      │                                 │
      │                                 │ connection lost
      │                                 ▼
      │                          ┌──────────────┐
      └──────────────────────────│ Reconnecting │
           max retries           │ (backoff)    │
                                 └──────────────┘

Reconnection Strategy

When the connection drops, the Tunnel Agent uses exponential backoff to reconnect:

Attempt Delay Max Delay
11 second60 seconds
22 seconds
34 seconds
48 seconds
516 seconds
6+32-60 seconds

After 5 consecutive failed attempts (configurable via EDGEFLOW_SAAS_MAX_RECONNECT_ATTEMPTS), the agent stops retrying and logs an error.

Configuration

# Tunnel server address
EDGEFLOW_SAAS_URL=saas.edgx.cloud:443

# Enable TLS (wss://) — recommended for production
EDGEFLOW_SAAS_TLS=true

# Heartbeat interval (default: 30 seconds)
EDGEFLOW_SAAS_HEARTBEAT_INTERVAL=30s

# Max reconnection attempts (default: 5, 0 = unlimited)
EDGEFLOW_SAAS_MAX_RECONNECT_ATTEMPTS=5

Firewall Requirements

Since the device initiates the outbound WebSocket connection, you only need:

  • Outbound port 443 (WSS/TLS) — to the SaaS server
  • No inbound ports required on the device
  • Works behind NAT, firewalls, and corporate proxies

Monitoring

Check the tunnel status at any time via the local API:

curl http://localhost:8080/api/v1/saas/status

{
  "connected": true,
  "device_id": "dev_abc123xyz",
  "status": "online",
  "connected_at": "2026-02-21T08:00:00Z",
  "last_heartbeat": "2026-02-21T12:34:00Z",
  "agent_version": "1.2.3",
  "tunnel_url": "wss://saas.edgx.cloud:443/tunnel"
}