Skip to content

Deploying Centrifugo

Centrifugo is a scalable, open-source real-time messaging server that powers interactive applications requiring instant communication between clients and servers. Built in Go with high performance optimizations, Centrifugo provides a self-hosted alternative to managed services like Pusher, PubNub, and Ably.

Introduction to Centrifugo

Centrifugo enables developers to add real-time capabilities to their applications without building complex infrastructure from scratch. Whether you’re building chat applications, live dashboards, multiplayer games, or collaborative tools, Centrifugo handles the complexity of persistent connections and efficient message delivery.

The platform is language-agnostic, meaning it works seamlessly with any backend technology—Node.js, Python, Java, Go, Ruby, or anything else. Centrifugo manages WebSocket, HTTP-streaming, Server-Sent Events (SSE), WebTransport, and GRPC connections while exposing simple HTTP and GRPC APIs for your application backend to publish messages and handle events.

With battle-tested infrastructure used by companies like VK, Badoo, ManyChat, and Grafana, Centrifugo proves itself in production at scale. A single Centrifugo instance can handle millions of concurrent WebSocket connections, and it scales horizontally using Redis or NATS for message brokering across multiple instances.

Key Features

Centrifugo is packed with powerful real-time messaging capabilities:

  • Multiple Transport Protocols: Support for WebSocket, HTTP-streaming, Server-Sent Events (SSE), GRPC, and WebTransport for maximum client compatibility
  • Built-in Scalability: Horizontal scaling with Redis, Redis Cluster, NATS, or Redis-compatible storage (AWS ElastiCache, Google Memorystore, DragonflyDB, Valkey, KeyDB)
  • Channel Subscriptions: Multiplexed subscriptions over a single connection with flexible subscription types
  • Channel Namespaces: Organize channels with namespace support for better management and isolation
  • Authentication: Flexible auth mechanisms with JWT tokens and proxy-like authentication via backend requests
  • Message History: Hot message history in channels with automatic recovery upon reconnect and cache recovery modes
  • Presence Information: Online channel presence with join/leave notifications and member tracking
  • Delta Compression: Reduce bandwidth with Fossil algorithm-based delta compression for channel publications
  • Connection RPC: Send RPC calls to the backend over the real-time connection for advanced use cases
  • Efficient Protocol: JSON and binary Protobuf message transfer with optimized serialization and built-in batching
  • Admin Web UI: Beautiful embedded admin interface for server management and monitoring
  • Prometheus Metrics: Comprehensive observability with Prometheus metrics and official Grafana dashboards
  • PostgreSQL Consumer: Asynchronous PostgreSQL consumer for transactional outbox and CDC patterns
  • Kafka Consumer: Support for Kafka consumers to integrate with event streaming systems
  • Publication Filtering: Server-side publication filtering by tags for bandwidth optimization
  • SDK Support: Official client libraries for JavaScript, Python, Go, and other languages
  • Zero Downtime Deployments: Graceful shutdown and deployment support
  • Configuration Flexibility: Extensive configuration options via file, environment variables, or both
  • Production Ready: Decade-old proven infrastructure with transparent security practices

Prerequisites

Before deploying Centrifugo on Klutch.sh, ensure you have the following:

  • A Klutch.sh account and dashboard access at klutch.sh/app
  • A GitHub repository (your fork or copy of Centrifugo source code)
  • Basic knowledge of Docker and containerization
  • Understanding of real-time messaging concepts and WebSocket protocols
  • Familiarity with environment variables and configuration management
  • A custom domain for your Centrifugo instance (recommended)
  • Knowledge of Redis or NATS for scaling (optional, for single-instance deployments)

Important Considerations

Deployment Steps

Follow these steps to deploy Centrifugo on Klutch.sh:

  1. Create a Dockerfile

    Create a Dockerfile in the root of your repository. Since Centrifugo is written in Go and comes pre-compiled, we’ll use a lightweight Alpine-based image:

    FROM centrifugo/centrifugo:v6
    WORKDIR /app
    # Copy configuration file
    COPY config.json /app/config.json
    # Create directory for logs (optional)
    RUN mkdir -p /app/logs
    # Expose port for client connections
    EXPOSE 8000
    # Expose port for admin API
    EXPOSE 8001
    # Expose port for health checks
    EXPOSE 9000
    # Run Centrifugo with config file
    CMD ["centrifugo", "-c", "/app/config.json"]

    Alternatively, if you want more control over the build:

    FROM golang:1.23-alpine AS builder
    WORKDIR /build
    RUN git clone https://github.com/centrifugal/centrifugo.git .
    RUN go build -o centrifugo ./cmd/centrifugo
    FROM alpine:latest
    WORKDIR /app
    RUN apk add --no-cache ca-certificates
    COPY --from=builder /build/centrifugo /app/centrifugo
    COPY config.json /app/config.json
    RUN mkdir -p /app/logs
    EXPOSE 8000 8001 9000
    CMD ["/app/centrifugo", "-c", "/app/config.json"]
  2. Create Configuration File

    Create a config.json file in the root of your repository with Centrifugo settings:

    {
    "v3_use_offset": true,
    "api_key": "${CENTRIFUGO_API_KEY}",
    "admin": true,
    "admin_password": "${CENTRIFUGO_ADMIN_PASSWORD}",
    "admin_secret": "${CENTRIFUGO_ADMIN_SECRET}",
    "token_hmac_secret_key": "${CENTRIFUGO_TOKEN_SECRET}",
    "client_channel_limit": 128,
    "client_queue_max_size": 10485760,
    "max_request_body_size": 65536,
    "websocket_compression": false,
    "proxy_connect_timeout": 5000,
    "proxy_request_timeout": 5000,
    "namespaces": [
    {
    "name": "chat",
    "join_leave": true,
    "presence": true,
    "force_push_join_leave": true,
    "history_size": 10,
    "history_ttl": 3600
    },
    {
    "name": "notifications",
    "join_leave": false,
    "presence": false,
    "history_size": 100,
    "history_ttl": 86400
    }
    ],
    "http_api": {
    "enabled": true,
    "address": "0.0.0.0:8001"
    },
    "grpc_api": {
    "enabled": true,
    "address": "0.0.0.0:10000"
    },
    "health": {
    "enabled": true,
    "address": "0.0.0.0:9000"
    },
    "engine": "memory"
    }

    For production with Redis:

    {
    "v3_use_offset": true,
    "api_key": "${CENTRIFUGO_API_KEY}",
    "admin": true,
    "admin_password": "${CENTRIFUGO_ADMIN_PASSWORD}",
    "admin_secret": "${CENTRIFUGO_ADMIN_SECRET}",
    "token_hmac_secret_key": "${CENTRIFUGO_TOKEN_SECRET}",
    "engine": "redis",
    "redis": {
    "address": "${REDIS_HOST}:${REDIS_PORT}",
    "password": "${REDIS_PASSWORD}",
    "db": 0
    },
    "broker": "redis",
    "broker_redis": {
    "address": "${REDIS_HOST}:${REDIS_PORT}",
    "password": "${REDIS_PASSWORD}"
    },
    "presence": "redis",
    "presence_redis": {
    "address": "${REDIS_HOST}:${REDIS_PORT}",
    "password": "${REDIS_PASSWORD}"
    }
    }
  3. Create Entrypoint Script

    Create docker/entrypoint.sh to handle initialization and environment variable substitution:

    #!/bin/sh
    set -e
    echo "Starting Centrifugo initialization..."
    # Substitute environment variables in config.json
    envsubst < /app/config.json > /app/config.generated.json
    # Validate configuration
    /app/centrifugo -c /app/config.generated.json --check
    if [ $? -eq 0 ]; then
    echo "Configuration validation successful"
    # Start Centrifugo with generated config
    exec /app/centrifugo -c /app/config.generated.json
    else
    echo "Configuration validation failed"
    exit 1
    fi

    Make it executable:

    Terminal window
    chmod +x docker/entrypoint.sh
  4. Create .gitignore

    Ensure sensitive files aren’t committed to GitHub by creating .gitignore:

    .env
    .env.local
    .env.*.local
    config.generated.json
    logs/
    *.log
    .DS_Store
    vendor/
  5. Push to GitHub

    Commit and push your Centrifugo configuration to your GitHub repository:

    Terminal window
    git add Dockerfile docker/ config.json .gitignore
    git commit -m "Add Klutch.sh deployment configuration for Centrifugo"
    git push origin main
  6. Deploy on Klutch.sh

    1. Log in to your Klutch.sh dashboard at klutch.sh/app
    2. Click “Create New App” and select your GitHub repository containing Centrifugo
    3. Klutch.sh will automatically detect the Dockerfile in your repository
    4. Configure your deployment:
      • Set your custom domain (e.g., centrifugo.example.com)
      • Configure HTTP traffic on port 8000 for client WebSocket connections
    5. Click “Deploy” to start the deployment process
    6. Monitor the deployment logs to ensure successful startup
  7. Configure Traffic Settings

    After deployment, configure the traffic routing:

    1. From your app’s dashboard, navigate to the “Traffic” or “Ports” section
    2. For WebSocket client connections:
      • Set internal port to 8000 (Centrifugo’s default client port)
      • Use HTTP protocol for WebSocket support
    3. For admin API (optional, if exposing):
      • Set internal port to 8001 (Centrifugo’s admin HTTP API)
    4. For health checks:
      • Set internal port to 9000 (Centrifugo’s health check port)
    5. Apply the configuration and wait for deployment to update
  8. Configure Environment Variables

    Set up environment variables for your Centrifugo instance in the Klutch.sh dashboard:

    1. Navigate to the “Environment Variables” or “Settings” section
    2. Add all required variables from the Basic Configuration section below
    3. For production deployments, add additional optimization variables
    4. Save the configuration and trigger a redeployment if needed

Initial Setup and Configuration

After your Centrifugo deployment is live, complete the initial setup:

Accessing the Admin Dashboard

  1. Navigate to your Centrifugo instance URL (e.g., https://centrifugo.example.com:8001)
  2. You’ll see the admin login page
  3. Enter your admin credentials configured in environment variables:
    • Username: typically admin or configured via admin_user
    • Password: your CENTRIFUGO_ADMIN_PASSWORD
  4. After login, you can manage channels, view statistics, and configure settings

Creating Your First Connection

To test your Centrifugo setup, create a simple client connection:

<html>
<head>
<script src="https://cdn.jsdelivr.net/npm/centrifuge@5/dist/centrifuge.js"></script>
</head>
<body>
<div id="messages"></div>
<input type="text" id="messageInput" placeholder="Enter message">
<button onclick="sendMessage()">Send</button>
<script>
const client = new Centrifuge('wss://centrifugo.example.com', {
token: 'YOUR_JWT_TOKEN_HERE'
});
client.on('connected', (ctx) => {
console.log('Connected to Centrifugo');
});
const sub = client.subscribe('chat:general', (message) => {
console.log('Received message:', message);
document.getElementById('messages').innerHTML +=
'<div>' + message.data.text + '</div>';
});
function sendMessage() {
const text = document.getElementById('messageInput').value;
// Publish via backend API to Centrifugo
fetch('https://centrifugo.example.com:8001/api/publish', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'apikey YOUR_API_KEY'
},
body: JSON.stringify({
channel: 'chat:general',
data: { text: text }
})
});
}
client.connect();
</script>
</body>
</html>

Configuring Namespaces

Namespaces help organize channels with different settings. Create namespaces in your config.json:

{
"namespaces": [
{
"name": "chat",
"join_leave": true,
"presence": true,
"publish_options": {
"sources": ["client", "api", "subscription"],
"require_history": true
},
"subscribe_options": {
"sources": ["client", "api"]
}
},
{
"name": "private",
"join_leave": false,
"presence": false,
"force_allow_subscribe": false,
"publish_options": {
"sources": ["api"]
}
}
]
}

Environment Variables

Basic Configuration

These are the essential environment variables needed for Centrifugo to function:

# Server Configuration
CENTRIFUGO_ADMIN_PASSWORD=secure_admin_password_here
CENTRIFUGO_ADMIN_SECRET=secure_admin_secret_key_here
CENTRIFUGO_API_KEY=your_api_key_here
CENTRIFUGO_TOKEN_SECRET=your_token_secret_key_here
# Logging
CENTRIFUGO_LOG_LEVEL=info
CENTRIFUGO_LOG_FORMAT=json
# Performance
CENTRIFUGO_CLIENT_CHANNEL_LIMIT=128
CENTRIFUGO_CLIENT_QUEUE_MAX_SIZE=10485760
CENTRIFUGO_MAX_REQUEST_BODY_SIZE=65536

Production Optimization

For production deployments with Redis and advanced features:

# Redis Broker
REDIS_HOST=redis.example.com
REDIS_PORT=6379
REDIS_PASSWORD=your_redis_password
REDIS_DB=0
# Centrifugo Engine (redis for clustering)
CENTRIFUGO_ENGINE=redis
# Connection Limits
CENTRIFUGO_CLIENT_CHANNEL_LIMIT=256
CENTRIFUGO_CLIENT_QUEUE_MAX_SIZE=16777216
CENTRIFUGO_MAX_REQUEST_BODY_SIZE=131072
# Proxy Settings (if using backend proxy)
CENTRIFUGO_PROXY_CONNECT_TIMEOUT=10000
CENTRIFUGO_PROXY_REQUEST_TIMEOUT=10000
# WebSocket Settings
CENTRIFUGO_WEBSOCKET_COMPRESSION=true
CENTRIFUGO_WEBSOCKET_READ_BUFFER_SIZE=4096
CENTRIFUGO_WEBSOCKET_WRITE_BUFFER_SIZE=4096
# TLS Settings (if terminating TLS in Centrifugo)
CENTRIFUGO_TLS_ENABLED=false
CENTRIFUGO_TLS_CERT=/etc/certs/cert.pem
CENTRIFUGO_TLS_KEY=/etc/certs/key.pem
# Metrics
CENTRIFUGO_PROMETHEUS_ENABLED=true
CENTRIFUGO_PROMETHEUS_ADDRESS=:9090

Code Examples

Go - Publishing Messages to Centrifugo

Here’s a Go example for publishing messages to Centrifugo:

package main
import (
"context"
"fmt"
"log"
"github.com/centrifugal/centrifugo/v5/client"
)
func publishMessage(ctx context.Context, centrifugoURL string, apiKey string) error {
// Create a client
c := client.NewClient(centrifugoURL, client.WithAPIKey(apiKey))
// Connect to Centrifugo
if err := c.Connect(ctx); err != nil {
return fmt.Errorf("failed to connect: %w", err)
}
defer c.Close()
// Publish a message to a channel
result, err := c.Publish(ctx, "chat:general", map[string]interface{}{
"text": "Hello, real-time world!",
"timestamp": 1234567890,
})
if err != nil {
return fmt.Errorf("failed to publish: %w", err)
}
log.Printf("Message published, offset: %v", result.Offset)
return nil
}
func main() {
ctx := context.Background()
if err := publishMessage(ctx, "http://centrifugo.example.com:8001", "YOUR_API_KEY"); err != nil {
log.Fatal(err)
}
}

Python - Centrifugo Client Integration

Here’s a Python example for connecting to Centrifugo and handling messages:

import asyncio
import json
from centrifuge import Client
async def main():
# Create a Centrifugo client
client = Client(
"wss://centrifugo.example.com",
token="YOUR_JWT_TOKEN",
debug=True
)
async def on_connected(ctx):
print("Connected to Centrifugo")
async def on_disconnected(ctx):
print("Disconnected from Centrifugo")
client.on("connected", on_connected)
client.on("disconnected", on_disconnected)
# Subscribe to a channel
async def on_message(message):
print(f"Received message: {message}")
sub = await client.subscribe("chat:general")
sub.on("message", on_message)
# Connect to server
await client.connect()
# Keep the connection alive
try:
while True:
await asyncio.sleep(1)
except KeyboardInterrupt:
await client.disconnect()
if __name__ == "__main__":
asyncio.run(main())

JavaScript/Node.js - Real-time Dashboard Updates

Here’s a Node.js example for publishing real-time dashboard updates:

const http = require('http');
async function publishDashboardUpdate(data) {
const requestData = JSON.stringify({
channel: 'dashboards:updates',
data: {
timestamp: new Date().toISOString(),
metrics: data.metrics,
status: data.status
}
});
const options = {
hostname: 'centrifugo.example.com',
port: 8001,
path: '/api/publish',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': Buffer.byteLength(requestData),
'Authorization': `apikey YOUR_API_KEY`
}
};
return new Promise((resolve, reject) => {
const req = http.request(options, (res) => {
let responseData = '';
res.on('data', (chunk) => {
responseData += chunk;
});
res.on('end', () => {
if (res.statusCode === 200) {
resolve(JSON.parse(responseData));
} else {
reject(new Error(`HTTP ${res.statusCode}: ${responseData}`));
}
});
});
req.on('error', reject);
req.write(requestData);
req.end();
});
}
// Example usage
const dashboardData = {
metrics: {
cpu: 45.2,
memory: 62.8,
diskUsage: 78.5
},
status: 'healthy'
};
publishDashboardUpdate(dashboardData)
.then(result => console.log('Published:', result))
.catch(error => console.error('Error:', error));

Best Practices

When deploying and managing Centrifugo on Klutch.sh, follow these best practices:

  • Secure Authentication: Use strong, randomly generated JWT secrets and API keys. Rotate keys regularly and never hardcode them in your code
  • Use Redis for Production: Deploy with Redis or NATS for high availability and horizontal scaling, not just the in-memory engine
  • Monitor Metrics: Enable Prometheus metrics and set up Grafana dashboards to monitor connection counts, message throughput, and system health
  • Configure Timeouts: Set appropriate proxy timeouts and connection timeouts based on your application’s needs
  • Implement Rate Limiting: Apply rate limiting on the HTTP API to prevent abuse and ensure fair resource usage
  • Use Channel Namespaces: Organize channels with namespaces to manage permissions and history settings efficiently
  • Enable Compression: Configure WebSocket compression for bandwidth optimization, especially for mobile clients
  • Secure Admin Dashboard: Protect the admin dashboard with strong passwords and restrict network access
  • Regular Backups: If using persistent storage, implement regular backups of configuration and state
  • Load Testing: Test your Centrifugo deployment under expected load to identify bottlenecks before production
  • Health Checks: Implement regular health checks against the health endpoint to ensure server availability
  • Graceful Shutdown: Implement graceful shutdown procedures to ensure clients reconnect properly

Troubleshooting

Common Issues and Solutions

Issue: WebSocket connection fails

  • Verify that your client is using the correct URL (wss:// for secure WebSocket)
  • Check that port 8000 is properly exposed and routed through Klutch.sh
  • Verify JWT token is valid and not expired
  • Check browser console for specific error messages
  • Ensure CORS is properly configured if connecting from a different domain

Issue: Admin dashboard not accessible

  • Verify the admin URL uses the correct port (usually 8001 for HTTP API)
  • Check that admin credentials are correctly set in environment variables
  • Ensure the admin dashboard is enabled in config.json ("admin": true)
  • Check firewall and network rules for access to the admin port

Issue: High memory usage

  • Reduce client_queue_max_size if it’s set too high
  • Implement message history cleanup policies
  • Monitor Redis memory if using Redis engine
  • Consider enabling compression for WebSocket connections
  • Scale to multiple Centrifugo instances with Redis broker

Issue: Messages not being delivered

  • Verify channel names are correct (case-sensitive)
  • Check that clients are properly subscribed to the channel
  • Review namespace configuration for publish permissions
  • Check logs for permission errors or subscription failures
  • Ensure API key is correct when publishing via HTTP API

Issue: Authentication failures

  • Verify JWT token format and signature
  • Check that token secret key matches configuration
  • Ensure token expiration time is set appropriately
  • Review token claims and scope
  • Test token generation with JWT debugging tools

Issue: High latency or slow message delivery

  • Check network connectivity between components
  • Monitor Redis performance if using Redis broker
  • Reduce proxy timeouts if using backend proxies
  • Enable WebSocket compression
  • Check system resource utilization (CPU, memory, network)

Update Instructions

To update Centrifugo to the latest version:

  1. Check Latest Version

    Terminal window
    # Visit GitHub releases
    curl -s https://api.github.com/repos/centrifugal/centrifugo/releases/latest | grep tag_name
  2. Update Dockerfile Update the image tag in your Dockerfile:

    FROM centrifugo/centrifugo:v6.5.1 # Update version here
  3. Test Configuration

    Terminal window
    # Test with new version locally
    docker run -it centrifugo/centrifugo:v6.5.1 centrifugo --check -c config.json
  4. Push Changes

    Terminal window
    git add Dockerfile
    git commit -m "Update Centrifugo to v6.5.1"
    git push origin main
  5. Redeploy on Klutch.sh

    • Navigate to your app in the Klutch.sh dashboard
    • Trigger a redeploy to pull the latest Dockerfile
    • Monitor the deployment logs for successful startup
  6. Verify Update

    • Check admin dashboard version information
    • Monitor metrics and logs for normal operation
    • Test client connections to ensure compatibility

Use Cases

Real-time Chat Applications

Build scalable chat applications where messages are delivered instantly to online users. Support multiple channels, presence awareness, and message history for seamless communication experiences.

Live Dashboards and Analytics

Stream real-time metrics, analytics, and telemetry data to connected dashboards. Centrifugo efficiently broadcasts updates to thousands of users simultaneously with minimal latency.

Multiplayer Games

Synchronize game state and player actions in real-time gaming experiences. Centrifugo’s low-latency messaging and efficient protocol make it ideal for competitive and cooperative multiplayer games.

Collaborative Tools

Enable collaborative applications where multiple users can work together in real-time. Support co-editing, shared workspaces, and instant notifications of changes made by other users.

Live Notifications

Deliver instant alerts and notifications to users across web and mobile platforms. Centrifugo supports multiple transports to ensure reliable delivery even in constrained networks.

IoT and Real-time Tracking

Stream sensor data, device telemetry, and live location information from IoT devices to monitoring dashboards. Centrifugo efficiently handles high-volume data streams from thousands of devices.

Financial Data Streaming

Deliver real-time stock prices, trading updates, and market information to financial applications. The efficient protocol and scalability make Centrifugo perfect for high-frequency data delivery.

AI Streaming Responses

Stream AI model responses and live generation results to users in real-time. Perfect for chat interfaces and applications that need to show progressive AI output as it’s generated.

Additional Resources

Conclusion

Deploying Centrifugo on Klutch.sh gives you a powerful, self-hosted real-time messaging platform capable of powering modern interactive applications. By following this guide, you’ve set up a production-ready Centrifugo instance that can handle millions of concurrent connections while delivering messages with minimal latency.

Centrifugo’s maturity, proven track record, and extensive feature set make it an excellent choice for developers building real-time applications without relying on third-party services. Whether you’re building chat applications, live dashboards, collaborative tools, or multiplayer games, Centrifugo provides the infrastructure to deliver seamless real-time experiences.

Remember to implement proper security measures, monitor your metrics, scale with Redis when needed, and follow the best practices outlined in this guide. With Centrifugo running on Klutch.sh, you have a reliable, scalable platform ready to support real-time features at any scale.

For additional support and to connect with the Centrifugo community, visit the official documentation, join the Discord community, or explore the Centrifugo blog for advanced topics and use cases.


Author: Davaughn White