Sockudo ๐
High-performance, scalable WebSocket server built in Rust ๐ฆ
Sockudo is a production-ready WebSocket server that provides real-time communication capabilities with built-in support for channels, presence, authentication, rate limiting, and horizontal scaling. Designed for modern applications that need reliable, fast, and scalable real-time features. It aims for Pusher protocol compatibility, making it a potential backend for clients like Laravel Echo.
โจ Features
๐ Core Capabilities
- High Performance: Built in Rust for maximum speed and efficiency.
- WebSocket Protocol: Full RFC 6455 compliance.
- Channel System: Organize connections with public, private, and presence channels. Support for private-encrypted channels is also included.
- Real-time Messaging: Instant bidirectional communication.
- Horizontal Scaling: Multi-node clustering with adapters for Redis, Redis Cluster, and NATS.
๐ Security & Authentication
- Channel Authentication: Secure private and presence channels using token-based authentication.
- User Authentication: User sign-in support with custom data, typically validated with signatures.
- Rate Limiting: Configurable limits for API and WebSocket connections, with backends like Memory or Redis.
- SSL/TLS Support: Production-ready HTTPS and WSS.
- CORS Configuration: Flexible cross-origin request handling.
๐ Monitoring & Observability
- Prometheus Metrics: Comprehensive performance monitoring for connections, messages, API calls, and adapter performance.
- Health Checks: Built-in health endpoints (
/up/{appId}) for load balancers. - Structured Logging: Configurable logging with multiple levels (DEBUG/INFO).
- Debug Mode: Enhanced debugging for development.
๐๏ธ Flexible Architecture
- Multiple Adapters: Choose between Local (single-node), Redis, Redis Cluster, or NATS for message broadcasting and horizontal scaling.
- Database Support for App Management: Options include Memory, MySQL, PostgreSQL, and DynamoDB for storing application configurations.
- Queue Systems: Supports Memory, Redis, Redis Cluster, and SQS for background job processing (e.g., webhooks).
- Cache Backends: Options for Memory, Redis, or Redis Cluster for caching channel data and other information.
๐ Integration Features
- Webhooks: Real-time event notifications (e.g.,
channel_occupied,channel_vacated,member_added,member_removed,client_event) to your services. - AWS Lambda: Direct Lambda function invocation for webhooks.
- REST API: Full HTTP API for triggering events, batch events, and managing channels/users.
- Client Libraries: Compatible with Pusher client libraries due to protocol adherence.
๐ Quick Start
Using Docker (Recommended)
# Clone the repository
# Ensure you have an .env file (e.g., from .env.example)
# cp .env.example .env
# nano .env # Customize if needed
# Quick setup and start (assumes make command is configured)
# Or, using docker-compose directly:
# docker-compose up -d
# you can also use
Sockudo should now be running. Default endpoints (configurable):
- WebSocket Server:
ws://localhost:6001/app/your-app-key(e.g.,demo-keyif using default app) - REST API:
http://localhost:6001(e.g.,http://localhost:6001/apps/demo-app/events) - Metrics:
http://localhost:9601/metrics - Health Check:
http://localhost:6001/up/your-app-id
Manual Installation
Prerequisites
- Rust 1.85+ (
rustup install stable) - Redis (optional, for scaling and certain drivers)
- MySQL/PostgreSQL (optional, for persistent app storage if using those drivers)
Install from Crates.io
# Install using cargo
# Or install using cargo-binstall (faster)
# Run Sockudo (ensure config/config.json exists or use ENV variables)
Build from Source
# Clone the repository
)
# Build the project
# Run with a configuration file (recommended)
# Or rely on environment variables and default app settings
# ./target/release/sockudo
๐ Usage Examples
WebSocket Client Connection (JavaScript)
// Connect to a public channel
const ws = ; // Replace your-app-key
ws ;
ws ;
ws ;
ws ;
Private Channel with Authentication (Conceptual Client-Side)
Actual signature generation must happen on your backend.
const ws = ;
ws ;
Presence Channel (Conceptual Client-Side)
Actual signature generation must happen on your backend.
const ws = ;
ws ;
// Listen for presence events
ws ;
REST API - Trigger Events (from your Backend)
Requires authentication (see Security section).
# Send event to a channel
# Replace your-app-id, your-app-key, and generate a valid auth_signature
Client Events (from an Authenticated WebSocket Client)
Client events can only be sent on private or presence channels by authenticated clients for whom the app has enable_client_messages set to true.
// Ensure the WebSocket 'ws' is connected and subscribed to 'presence-chat' (a private or presence channel)
ws.;
๐ง Configuration
Sockudo can be configured via a JSON file (default: config/config.json) or environment variables. Environment variables generally override file settings for basic options, but the file provides more detailed structure.
Environment Variables (Key Examples)
Create a .env file (or set them in your environment):
# Basic Settings
HOST=0.0.0.0
PORT=6001
DEBUG=false # Enables more verbose logging
# Database (Example for Redis, adapt for MySQL/Postgres/DynamoDB if used as primary for AppManager)
REDIS_URL=redis://redis:6379/0 # Used by multiple components if not overridden
# For MySQL AppManager:
# DATABASE_MYSQL_HOST=mysql
# DATABASE_MYSQL_USER=sockudo
# DATABASE_MYSQL_PASSWORD=your_mysql_password
# DATABASE_MYSQL_DATABASE=sockudo
# Drivers (Lowercase: "local", "redis", "redis-cluster", "nats", "memory", "mysql", "pgsql", "dynamodb", "sqs")
ADAPTER_DRIVER=redis # For horizontal scaling
APP_MANAGER_DRIVER=memory # For app definitions
CACHE_DRIVER=redis # For caching
QUEUE_DRIVER=redis # For webhooks & background tasks
# Security
SSL_ENABLED=false # Set to true for production and provide paths
# SSL_CERT_PATH=/path/to/cert.pem
# SSL_KEY_PATH=/path/to/key.pem
# REDIS_PASSWORD=your-redis-password # If Redis requires auth
# Application Defaults (if not using a persistent AppManager or for fallback)
SOCKUDO_DEFAULT_APP_ID=demo-app
SOCKUDO_DEFAULT_APP_KEY=demo-key
SOCKUDO_DEFAULT_APP_SECRET=demo-secret
SOCKUDO_ENABLE_CLIENT_MESSAGES=true # For the default app
Refer to src/options.rs and src/main.rs for a comprehensive list of all ENV var overrides and their default behaviors.
Configuration File (config/config.json)
Provides detailed control over all aspects. Below is a snippet; refer to your uploaded config/config.json for the full structure.
๐๏ธ Architecture
System Overview
โโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโ
โ Client Apps โ โ Load Balancer โ โ Sockudo Node โ
โ (Web/Mobile/IoT)โโโโโบโ (e.g., Nginx, โโโโโบโ (Rust) โ
โ using PusherJS โ โ AWS ALB) โ โ โ
โโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโ
โ โฒ
โ โ Pub/Sub
โโโโโโโโโโโโโโโโโโโ โ โผ
โ Pub/Sub Backend โโโโโโโโโโโโโโโ
โ (Redis/NATS for โ
โ HORIZONTAL_ADAPTER)โ
โโโโโโโโโโโโโโโโโโโ
โ
โโโโโโโโโโโโโโโโโโโโโโโ โ โโโโโโโโโโโโโโโโโโโโโโ
โ App Config Storage โโโโโโโโบโ Cache Storage โ
โ (MySQL/PG/DynamoDB/ โ โ (Redis/Memory) โ
โ Memory) โ โโโโโโโโโโโโโโโโโโโโโโ
โโโโโโโโโโโโโโโโโโโโโโโ
Core Components
- Connection Handler (
adapter::handler): Manages individual WebSocket connections, message parsing, authentication, and routing to appropriate handlers. - Channel Manager (
channel::manager): Handles channel subscriptions, presence state, and signature validation for channel access. - Adapter (
adapter): Abstract interface for connection management and message broadcasting.- Local Adapter (
adapter::local_adapter): Single-node operation. - Horizontal Adapters (
adapter::redis_adapter,adapter::redis_cluster_adapter,adapter::nats_adapter): Enable multi-node setups by using Redis, Redis Cluster, or NATS for pub/sub to synchronize state and broadcast messages across instances.
- Local Adapter (
- App Manager (
app::manager): Manages application configurations (keys, secrets, limits, features), with backends like Memory, MySQL, PostgreSQL, or DynamoDB. - Cache Manager (
cache::manager): Provides caching for frequently accessed data (e.g., channel information, app settings) with Memory or Redis backends. - Queue Manager (
queue::manager): Handles background tasks, primarily for delivering webhooks, using Memory, Redis, Redis Cluster, or SQS. - Rate Limiter (
rate_limiter): Protects against abuse with configurable limits, using Memory or Redis. - Webhook System (
webhook): Delivers real-time server events (e.g., channel occupied/vacated, member added/removed) to configured HTTP endpoints or AWS Lambda functions. - Metrics Collector (
metrics): Exposes Prometheus metrics for monitoring performance and health. - HTTP Handler (
http_handler): Provides the Pusher-compatible REST API for triggering events and querying server state. - WebSocket Handler (
ws_handler): Manages the WebSocket upgrade process and initial connection setup.
Supported Architectures
- Single Node: Ideal for development, testing, and smaller applications. Uses
localadapter andmemoryfor other components if not otherwise configured. - Multi-Node (Clustered): Achieves horizontal scalability using Redis, Redis Cluster, or NATS as the
adapter.driverfor message broadcasting and state synchronization between Sockudo instances. - Microservices Integration: Sockudo can act as the real-time layer in a microservices architecture, receiving events to broadcast via its HTTP API.
- Serverless Integration: Webhooks can trigger AWS Lambda functions, allowing for serverless processing of Sockudo events.
๐ Client Integration
Sockudo implements the Pusher WebSocket protocol. This means you can use any Pusher-compatible client-side library to connect to Sockudo for real-time messaging.
For triggering events from your application backend (server-to-server), you would use Sockudo's HTTP API (see API Reference section), potentially with an HTTP client or a Pusher server-side library configured to point to Sockudo's HTTP API endpoints.
Recommended Client-Side Libraries (for WebSocket Connection)
JavaScript/TypeScript (PusherJS)
This is the most common library for frontend integration.
import Pusher from 'pusher-js';
const pusher = ;
const channel = pusher.;
channel.;
Other Pusher-Compatible Client Libraries
Most Pusher client libraries for other languages (Python, Ruby, Java, .NET/C#, Swift, Android, etc.) can be configured to connect to a custom host and port, allowing them to work with Sockudo. You'll typically need to set:
- App Key
- Host (your Sockudo server address)
- Port (your Sockudo WebSocket port)
forceTLS(or equivalent for secure connections)- An
authEndpointif using private or presence channels.
Native WebSocket
You can also connect directly using any standard WebSocket client, but you'll need to implement the Pusher message format manually (e.g., for pusher:subscribe, pusher:ping).
const ws = ;
ws ;
// ... handle other WebSocket events
Triggering Events from Your Backend (Server-Side)
Use Sockudo's HTTP API. Examples using curl are in the "Usage Examples" and "API Reference" sections.
Libraries like Pusher's official PHP or Go server libraries can also be used if you configure their host/port to point to your Sockudo HTTP API endpoint (http://localhost:6001 by default).
PHP (Pusher Server SDK - configured for Sockudo)
Go (Pusher HTTP Go - configured for Sockudo)
package main
import (
"fmt"
"[github.com/pusher/pusher-http-go/v5](https://github.com/pusher/pusher-http-go/v5)"
)
func main()
๐ข Deployment
Refer to README-Docker.md for comprehensive Docker deployment instructions.
Docker Deployment (Recommended)
Development
# Start development environment (uses docker-compose.yml and docker-compose.dev.yml)
# OR
# View logs
# Run tests (if configured in a Makefile or script)
# make test
Production
# Production deployment (uses docker-compose.yml and docker-compose.prod.yml)
# OR
# Scale to multiple instances (example)
# Monitor performance (example for Docker stats)
Kubernetes
A basic Kubernetes deployment might look like this (adapt as needed):
apiVersion: apps/v1
kind: Deployment
metadata:
name: sockudo
spec:
replicas: 3
selector:
matchLabels:
app: sockudo
template:
metadata:
labels:
app: sockudo
spec:
containers:
- name: sockudo
image: sockudo/sockudo:latest
ports:
- name: websocket
containerPort: 6001 # Sockudo's application port
- name: metrics
containerPort: 9601 # Sockudo's metrics port
env:
- name: ADAPTER_DRIVER
value: "redis" # or "nats", "redis-cluster"
- name: REDIS_URL
value: "redis://your-redis-service:6379"
# Add other necessary environment variables or configmap mounts
# - name: CONFIG_FILE_PATH
# value: "/app/config/config.json"
# volumeMounts:
# - name: sockudo-config
# mountPath: /app/config
# volumes:
# - name: sockudo-config
# configMap:
# name: sockudo-configmap
Ensure your Kubernetes setup includes appropriate services, ingress, and configuration for Redis/NATS if using horizontal scaling.
Cloud Platforms
Sockudo can be deployed to various cloud platforms:
AWS ECS / EKS
- Use the production Docker image.
- Configure Application Load Balancer (ALB) or Network Load Balancer (NLB) with WebSocket support (sticky sessions might be needed depending on adapter and client behavior, though ideally not with a proper horizontal adapter).
- Use ElastiCache for Redis (standalone or cluster) if using Redis adapter/cache/queue.
- Use RDS for MySQL/PostgreSQL if using those for AppManager.
- Use Amazon SQS if using the SQS queue driver.
Google Cloud Run / GKE
- Enable WebSocket support in Cloud Run or use GKE.
- Use Cloud Memorystore for Redis.
- Configure Cloud SQL for persistent app storage.
Azure Container Instances / AKS
- Use Azure Cache for Redis.
- Configure Azure Database for MySQL/PostgreSQL.
๐ Monitoring
Metrics
Sockudo exposes Prometheus metrics at the /metrics endpoint (default port 9601).
Key metrics include:
- Connection Metrics:
sockudo_connected: Current number of active WebSocket connections.sockudo_new_connections_total: Total number of new connections established.sockudo_new_disconnections_total: Total number of disconnections.
- Message Metrics:
sockudo_ws_messages_sent_total: Total WebSocket messages sent from server to clients.sockudo_ws_messages_received_total: Total WebSocket messages received by server from clients.sockudo_socket_transmitted_bytes: Total bytes transmitted over WebSockets.sockudo_socket_received_bytes: Total bytes received over WebSockets.
- HTTP API Metrics:
sockudo_http_calls_received_total: Total HTTP API calls received.sockudo_http_transmitted_bytes: Total bytes sent in HTTP API responses.sockudo_http_received_bytes: Total bytes received in HTTP API requests.
- Horizontal Adapter Metrics (if using Redis/NATS adapter):
sockudo_horizontal_adapter_resolve_time: Histogram of request resolution time between nodes.sockudo_horizontal_adapter_resolved_promises: Total promises fulfilled by other nodes.sockudo_horizontal_adapter_sent_requests: Total requests sent to other nodes.sockudo_horizontal_adapter_received_requests: Total requests received from other nodes.sockudo_horizontal_adapter_received_responses: Total responses received from other nodes.
- Channel Statistics (can be inferred or might require specific metrics not listed but common):
sockudo_channel_count(conceptual, often derived fromget_channels_with_socket_count)sockudo_active_subscriptions(conceptual)
Grafana Dashboard
If using the Docker setup with Grafana (docker-compose.prod.yml), a pre-configured dashboard might be available. Otherwise, you can import/create dashboards in Grafana using Prometheus as a data source.
Access Grafana at http://localhost:3000 (default credentials may vary, check docker-compose.prod.yml or README-Docker.md).
Health Checks
- Application Health:
GET /up/{app_id}- Checks if a specific application is responsive. - Metrics Endpoint:
GET /metrics(default on port 9601) - Exposes Prometheus metrics. - General Usage/Memory:
GET /usage- Provides memory usage statistics of the Sockudo server.
๐ Security
Authentication
Channel Authentication (Private & Presence Channels)
Sockudo validates auth tokens for private and presence channel subscriptions. The signature is typically generated on your backend.
The string to sign depends on the channel type:
- Private channels:
socket_id:channel_name - Presence channels:
socket_id:channel_name:channel_data_json_string(wherechannel_data_json_stringis the JSON string provided in thechannel_datafield of the subscription request).
Example Server-Side Signature Generation (Node.js conceptual):
const crypto = require;
// For a private channel:
// const appKey = "your-app-key";
// const signature = generateChannelAuth(clientSocketId, "private-mychannel", "your-app-secret");
// const authString = `${appKey}:${signature}`;
// For a presence channel:
// const channelData = JSON.stringify({ user_id: "123", user_info: { name: "Alice" } });
// const presenceSignature = generateChannelAuth(clientSocketId, "presence-mychannel", "your-app-secret", channelData);
// const presenceAuthString = `${appKey}:${presenceSignature}`;
Refer to src/channel/manager.rs (method get_data_to_sign_for_signature) for the exact server-side string construction.
User Authentication (pusher:signin)
If enable_user_authentication is true for an app, clients can send a pusher:signin event.
The string to sign for user authentication is socket_id::user::user_data_json_string.
Example Server-Side User Auth Token Generation (Node.js conceptual):
const crypto = require;
// const appKey = "your-app-key";
// const userData = JSON.stringify({ id: "user456", name: "Bob" });
// const userAuthSignature = generateUserAuth(clientSocketId, userData, "your-app-secret");
// Client sends: { event: "pusher:signin", data: { auth: `${appKey}:${userAuthSignature}`, user_data: userData }}
// Note: The `src/app/auth.rs` `validate_channel_auth` and `sing_in_token_for_user_data` suggest the client sends only the signature part in `auth`, and `user_data` separately. Your client example shows this correctly.
Refer to src/app/auth.rs (method sing_in_token_for_user_data) for server-side logic.
Rate Limiting
Configure rate limits in config/config.json or via environment variables to protect against abuse. Sockudo supports separate limits for HTTP API requests and WebSocket connections.
Backends like Memory or Redis can be used for rate limiting.
Client-specific event rate limits are configured per-application (e.g., max_client_events_per_second).
SSL/TLS
Enable HTTPS and WSS in production by setting ssl.enabled = true in config/config.json or SSL_ENABLED=true (env var) and providing paths to your SSL certificate and key.
Refer to README-Docker.md for Docker-specific SSL setup with Nginx or Let's Encrypt.
"ssl":
๐ API Reference
WebSocket Events (Pusher Protocol)
Sockudo aims for compatibility with the Pusher WebSocket protocol. Key events include:
Connection Events
pusher:connection_established: Sent to the client upon successful connection. Containssocket_idandactivity_timeout.pusher:error: Sent to the client when an error occurs (e.g., auth failure, invalid message). Containscodeandmessage.pusher:ping: Sent by the server to check if the client is alive. Client should respond withpusher:pong.pusher:pong: Sent by the client in response to apusher:ping.
Subscription Events
pusher:subscribe: Sent by the client to subscribe to a channel.dataincludeschannelname and optionallyauthstring (for private/presence) andchannel_data(for presence).pusher:unsubscribe: Sent by the client to unsubscribe from a channel.dataincludeschannelname.pusher_internal:subscription_succeeded: Sent to the client by the server confirming successful subscription to a channel. For presence channels,dataincludes current member list (presence.hash,presence.ids,presence.count).pusher:cache_miss: Sent to the client if they subscribe to a cache channel and no data is initially cached.
Presence Events (Sent by Server to Subscribed Clients)
pusher_internal:member_added: Sent to clients in a presence channel when a new member joins.dataincludesuser_idanduser_info.pusher_internal:member_removed: Sent to clients in a presence channel when a member leaves.dataincludesuser_id.
User Authentication Events
pusher:signin: Sent by the client to authenticate themselves as a user.dataincludesauth(app_key:signature) anduser_data(JSON string with user details likeid).pusher:signin_success: Sent to the client by the server upon successful user sign-in.
Client Events (Sent by Client, Broadcast by Server)
client-*(e.g.,client-message): Custom events sent by one client, broadcast by the server to other clients on the same private or presence channel (excluding the sender by default, ifsocket_idis provided when triggering via HTTP API). The app must haveenable_client_messages: true.
REST API Endpoints
All endpoints are prefixed with /apps/{app_id}/. Authentication is required for these endpoints.
Trigger Event
- Endpoint:
POST /apps/{app_id}/events - Description: Triggers an event on one or more channels.
- Body:
- Response:
200 OKwith{"ok":true}or channel info if requested.
Batch Events
- Endpoint:
POST /apps/{app_id}/batch_events - Description: Triggers multiple events in a single request.
- Body:
- Response:
200 OKwith{}or{"batch": [...]}containing info for each event if requested.
Get Channel Information
- Endpoint:
GET /apps/{app_id}/channels/{channel_name} - Description: Retrieves information about a specific channel.
- Query Parameters:
info: Comma-separated list of attributes to retrieve (e.g.,user_count,subscription_count,cache).
- Response:
200 OKwith JSON containing channel status (e.g.,{"occupied": true, "user_count": 5, "subscription_count": 10}).
List Channels
- Endpoint:
GET /apps/{app_id}/channels - Description: Retrieves a list of active channels in an application.
- Query Parameters:
filter_by_prefix: Filters channels by the given prefix.info: Comma-separated list of attributes to retrieve for each channel (e.g.,user_count).
- Response:
200 OKwith JSON{"channels": {"channel_name": {"user_count": 2}, ...}}.
Get Users in a Presence Channel
- Endpoint:
GET /apps/{app_id}/channels/{channel_name}/users - Description: Retrieves the list of users subscribed to a specific presence channel.
- Response:
200 OKwith JSON{"users": [{"id": "user_id_1"}, {"id": "user_id_2"}]}.
Terminate User Connections
- Endpoint:
POST /apps/{app_id}/users/{user_id}/terminate_connections - Description: Forcibly disconnects all WebSocket connections associated with a given
user_id. - Response:
200 OKwith{"ok":true}.
Other Endpoints
- Health Check:
GET /up/{app_id}- Returns200 OKif the app is known (even if no connections). - Server Usage:
GET /usage- Returns server memory statistics. - Prometheus Metrics:
GET /metrics(default port 9601) - Exposes metrics in Prometheus format.
๐งช Testing
Sockudo includes a suite of tests to ensure reliability.
Running Tests
# Run all unit and integration tests (ensure dependencies like Redis might be needed for some)
# For Docker-based testing environment, refer to README-Docker.md
# Example: make ci-test (if Makefile provides this)
Interactive Tester
The project includes an interactive tester in test/interactive/ which can be used to manually test WebSocket connections, subscriptions, client events, and webhooks against a running Sockudo instance.
Automated Tests
Automated tests can be found in test/automated/ which might include scripts for load testing or specific feature validation.
๐ค Contributing
We welcome contributions! Please see our CONTRIBUTING.md for guidelines on how to get started, coding standards, and the PR review process.
๐ Documentation
For more in-depth information:
- Explore the
src/directory for detailed module implementations. - Configuration options are detailed in
src/options.rs. - Docker setup is described in
README-Docker.md. - (If a dedicated documentation site exists, link it here, e.g.,
https://sockudo.appas mentioned in the original README).
๐ License
This project is licensed under the AGPL-3.0 License - see the LICENSE file for details. (Updated based on the badge at the top of your README).
๐ Acknowledgments
- Built with Tokio for async runtime.
- Uses fastwebsockets for WebSocket implementation.
- Inspired by Pusher and similar real-time messaging platforms like Laravel Reverb.
- Thanks to the Rust community for its robust ecosystem and excellent crates.
๐ Support
Community Support
- GitHub Issues: Report bugs and request features
- Crates.io: View package details
- Discord: Join the RustNSparks server
- X: Follow us on X
โญ Star us on GitHub if Sockudo helps your project! โญ