Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/sockudo/sockudo/llms.txt

Use this file to discover all available pages before exploring further.

Sockudo is designed as a drop-in replacement for Pusher, making migration straightforward. This guide walks you through the migration process.

Why Migrate to Sockudo?

  • Cost Savings: Self-hosted solution eliminates per-connection/per-message fees
  • Data Sovereignty: Keep all WebSocket traffic within your infrastructure
  • Performance: Optimized Rust implementation with lower latency
  • Scalability: Handle 100K+ concurrent connections per node
  • Advanced Features: Delta compression, tag filtering, Unix socket support

Migration Steps

1

Deploy Sockudo

First, deploy Sockudo alongside your existing Pusher setup. This allows gradual migration without downtime.
git clone https://github.com/sockudo/sockudo.git
cd sockudo

# Configure environment
cp .env.example .env
# Edit .env with your app credentials

# Start Sockudo
docker-compose up -d

From Source

# Install Rust
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

# Build and run
git clone https://github.com/sockudo/sockudo.git
cd sockudo
cargo run --release --features full
Verify Sockudo is running:
curl http://localhost:6001/up/app-id
# Should return: {"status":"ok"}
2

Configure Client Connections

Update your client-side code to point to Sockudo. You can do this gradually by feature flag or environment variable.

JavaScript/TypeScript

Before (Pusher):
const pusher = new Pusher('your-pusher-key', {
    cluster: 'us2'
});
After (Sockudo):
const pusher = new Pusher('your-app-key', {
    wsHost: 'sockudo.yourdomain.com',
    wsPort: 443,
    cluster: '',
    forceTLS: true
});

Environment-Based Configuration

const pusherConfig = process.env.USE_SOCKUDO === 'true' ? {
    wsHost: process.env.SOCKUDO_HOST,
    wsPort: parseInt(process.env.SOCKUDO_PORT),
    cluster: '',
    forceTLS: process.env.SOCKUDO_TLS === 'true'
} : {
    cluster: process.env.PUSHER_CLUSTER
};

const pusher = new Pusher(process.env.PUSHER_KEY, pusherConfig);

React/Vue/Angular

// config/pusher.js
export const pusherConfig = {
    key: import.meta.env.VITE_PUSHER_KEY,
    wsHost: import.meta.env.VITE_SOCKUDO_HOST || undefined,
    wsPort: import.meta.env.VITE_SOCKUDO_PORT || undefined,
    cluster: import.meta.env.VITE_PUSHER_CLUSTER || '',
    forceTLS: import.meta.env.VITE_SOCKUDO_TLS === 'true'
};
3

Update Server-Side Events

Update your backend to trigger events through Sockudo instead of Pusher.

PHP

Before:
$pusher = new Pusher\Pusher(
    'pusher-key',
    'pusher-secret',
    'pusher-app-id',
    ['cluster' => 'us2']
);
After:
$pusher = new Pusher\Pusher(
    'sockudo-key',
    'sockudo-secret',
    'sockudo-app-id',
    [
        'host' => 'sockudo.yourdomain.com',
        'port' => 443,
        'scheme' => 'https',
        'useTLS' => true
    ]
);

Python

Before:
pusher_client = pusher.Pusher(
    app_id='pusher-app-id',
    key='pusher-key',
    secret='pusher-secret',
    cluster='us2'
)
After:
pusher_client = pusher.Pusher(
    app_id='sockudo-app-id',
    key='sockudo-key',
    secret='sockudo-secret',
    host='sockudo.yourdomain.com',
    port=443,
    ssl=True
)

Node.js

Before:
const pusher = new Pusher({
    appId: process.env.PUSHER_APP_ID,
    key: process.env.PUSHER_KEY,
    secret: process.env.PUSHER_SECRET,
    cluster: 'us2'
});
After:
const pusher = new Pusher({
    appId: process.env.SOCKUDO_APP_ID,
    key: process.env.SOCKUDO_KEY,
    secret: process.env.SOCKUDO_SECRET,
    host: process.env.SOCKUDO_HOST,
    port: 443,
    useTLS: true
});
4

Test the Migration

Thoroughly test your WebSocket functionality before switching production traffic.

Connection Testing

const pusher = new Pusher('app-key', {
    wsHost: 'localhost',
    wsPort: 6001,
    cluster: '',
    forceTLS: false
});

pusher.connection.bind('connected', () => {
    console.log('✓ Connected to Sockudo');
});

pusher.connection.bind('error', (err) => {
    console.error('✗ Connection error:', err);
});

Channel Subscription

// Public channel
const publicChannel = pusher.subscribe('test-channel');
publicChannel.bind('test-event', (data) => {
    console.log('✓ Public channel working:', data);
});

// Private channel
const privateChannel = pusher.subscribe('private-test');
privateChannel.bind('pusher:subscription_succeeded', () => {
    console.log('✓ Private channel authenticated');
});

// Presence channel
const presenceChannel = pusher.subscribe('presence-test');
presenceChannel.bind('pusher:subscription_succeeded', (members) => {
    console.log('✓ Presence channel working, members:', members.count);
});

Event Triggering

Test server-side event triggering:
curl -X POST http://localhost:6001/apps/app-id/events \
  -H "Content-Type: application/json" \
  -d '{
    "name": "test-event",
    "channel": "test-channel",
    "data": "{\"message\":\"Hello from Sockudo\"}"
  }'

Feature Compatibility

Fully Compatible Features

  • ✅ Public channels
  • ✅ Private channels with HMAC authentication
  • ✅ Presence channels with member info
  • ✅ Client events on private channels
  • ✅ Channel existence queries
  • ✅ User authentication
  • ✅ Webhooks (channel occupied, vacated, member added/removed)
  • ✅ Connection state events
  • ✅ Rate limiting

Sockudo Extensions

  • 🚀 Delta compression for bandwidth optimization
  • 🚀 Tag-based publication filtering
  • 🚀 Unix socket support for reverse proxies
  • 🚀 Redis Sentinel support
  • 🚀 Prometheus metrics
  • 🚀 Advanced WebSocket buffer controls

Not Supported

  • ❌ Pusher Beams (mobile push notifications)
  • ❌ Pusher Channels encrypted private channels (use private-encrypted-* with own encryption)

Configuration Mapping

App Credentials

PusherSockudo
App IDSOCKUDO_DEFAULT_APP_ID or config file
App KeySOCKUDO_DEFAULT_APP_KEY or config file
App SecretSOCKUDO_DEFAULT_APP_SECRET or config file
ClusterNot needed (self-hosted)

Environment Variables

# Sockudo equivalent of Pusher settings
SOCKUDO_DEFAULT_APP_ID=your-app-id
SOCKUDO_DEFAULT_APP_KEY=your-app-key
SOCKUDO_DEFAULT_APP_SECRET=your-app-secret

# Server settings
PORT=6001
HOST=0.0.0.0

# For production
SSL_ENABLED=true
SSL_CERT_PATH=/path/to/cert.pem
SSL_KEY_PATH=/path/to/key.pem

Gradual Migration Strategy

1. Canary Deployment

Route a small percentage of traffic to Sockudo:
function getPusherConfig() {
    const userId = getCurrentUserId();
    const useSockudo = (userId % 100) < 10; // 10% of users
    
    if (useSockudo) {
        return {
            wsHost: 'sockudo.yourdomain.com',
            wsPort: 443,
            cluster: '',
            forceTLS: true
        };
    } else {
        return {
            cluster: 'us2'
        };
    }
}

2. Feature Flag

Use a feature flag service (LaunchDarkly, Unleash, etc.):
import { useFeatureFlag } from '@your-org/feature-flags';

function WebSocketProvider({ children }) {
    const useSockudo = useFeatureFlag('use-sockudo');
    
    const pusherConfig = useSockudo ? {
        wsHost: process.env.SOCKUDO_HOST,
        wsPort: 443,
        cluster: '',
        forceTLS: true
    } : {
        cluster: process.env.PUSHER_CLUSTER
    };
    
    const pusher = new Pusher(process.env.PUSHER_KEY, pusherConfig);
    
    return <PusherContext.Provider value={pusher}>{children}</PusherContext.Provider>;
}

3. Environment-Based

Migrate environments one at a time:
const environments = {
    development: {
        wsHost: 'localhost',
        wsPort: 6001,
        cluster: '',
        forceTLS: false
    },
    staging: {
        wsHost: 'sockudo-staging.yourdomain.com',
        wsPort: 443,
        cluster: '',
        forceTLS: true
    },
    production: {
        // Still using Pusher during gradual migration
        cluster: 'us2'
    }
};

const pusherConfig = environments[process.env.NODE_ENV];

Monitoring the Migration

Connection Metrics

Monitor Sockudo’s Prometheus metrics:
curl http://localhost:9601/metrics
Key metrics:
  • sockudo_connections_total - Total active connections
  • sockudo_messages_received_total - Messages from clients
  • sockudo_messages_sent_total - Messages to clients
  • sockudo_subscription_successes_total - Successful subscriptions
  • sockudo_subscription_errors_total - Failed subscriptions

Error Tracking

Log connection errors for analysis:
pusher.connection.bind('error', (err) => {
    // Send to your error tracking service
    trackError('sockudo_connection_error', {
        code: err.error?.data?.code,
        message: err.error?.data?.message,
        userId: getCurrentUserId()
    });
});

Troubleshooting Common Issues

Authentication Fails After Migration

Problem: Private/presence channels fail with 401 errors. Solution: Verify authentication endpoint generates signatures using Sockudo credentials:
// Update your auth endpoint
$pusher = new Pusher\Pusher(
    getenv('SOCKUDO_KEY'),      // Not PUSHER_KEY
    getenv('SOCKUDO_SECRET'),   // Not PUSHER_SECRET
    getenv('SOCKUDO_APP_ID'),   // Not PUSHER_APP_ID
    ['host' => getenv('SOCKUDO_HOST'), 'port' => 443, 'scheme' => 'https']
);

$auth = $pusher->socket_auth($_POST['channel_name'], $_POST['socket_id']);
return response()->json(json_decode($auth));

High Latency

Problem: Messages take longer to arrive than with Pusher. Solution:
  • Check network latency to Sockudo server
  • Enable delta compression for bandwidth optimization
  • Verify Redis/NATS adapter is properly configured for horizontal scaling
  • Check Nginx/proxy configuration has proper WebSocket settings

Connection Drops

Problem: WebSocket connections disconnect unexpectedly. Solution:
  • Increase WebSocket timeout in Nginx: proxy_read_timeout 300s;
  • Check Sockudo buffer settings: WEBSOCKET_MAX_MESSAGES, WEBSOCKET_MAX_BYTES
  • Verify firewall/load balancer preserves long-lived connections
  • Enable auto-ping: WEBSOCKET_AUTO_PING=true, WEBSOCKET_PING_INTERVAL=30

Rollback Plan

If issues arise, you can quickly rollback to Pusher:

Client-Side

const pusherConfig = process.env.USE_SOCKUDO === 'true' ? {
    wsHost: process.env.SOCKUDO_HOST,
    // ... Sockudo config
} : {
    cluster: process.env.PUSHER_CLUSTER  // Rollback to Pusher
};
Set USE_SOCKUDO=false to rollback.

Server-Side

const pusher = new Pusher({
    appId: process.env.USE_SOCKUDO === 'true' 
        ? process.env.SOCKUDO_APP_ID 
        : process.env.PUSHER_APP_ID,
    key: process.env.USE_SOCKUDO === 'true'
        ? process.env.SOCKUDO_KEY
        : process.env.PUSHER_KEY,
    secret: process.env.USE_SOCKUDO === 'true'
        ? process.env.SOCKUDO_SECRET
        : process.env.PUSHER_SECRET,
    ...(process.env.USE_SOCKUDO === 'true' ? {
        host: process.env.SOCKUDO_HOST,
        port: 443,
        useTLS: true
    } : {
        cluster: 'us2'
    })
});

Next Steps