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:
Create a Dockerfile
Create a
Dockerfilein 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:v6WORKDIR /app# Copy configuration fileCOPY config.json /app/config.json# Create directory for logs (optional)RUN mkdir -p /app/logs# Expose port for client connectionsEXPOSE 8000# Expose port for admin APIEXPOSE 8001# Expose port for health checksEXPOSE 9000# Run Centrifugo with config fileCMD ["centrifugo", "-c", "/app/config.json"]Alternatively, if you want more control over the build:
FROM golang:1.23-alpine AS builderWORKDIR /buildRUN git clone https://github.com/centrifugal/centrifugo.git .RUN go build -o centrifugo ./cmd/centrifugoFROM alpine:latestWORKDIR /appRUN apk add --no-cache ca-certificatesCOPY --from=builder /build/centrifugo /app/centrifugoCOPY config.json /app/config.jsonRUN mkdir -p /app/logsEXPOSE 8000 8001 9000CMD ["/app/centrifugo", "-c", "/app/config.json"]Create Configuration File
Create a
config.jsonfile 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}"}}Create Entrypoint Script
Create
docker/entrypoint.shto handle initialization and environment variable substitution:#!/bin/shset -eecho "Starting Centrifugo initialization..."# Substitute environment variables in config.jsonenvsubst < /app/config.json > /app/config.generated.json# Validate configuration/app/centrifugo -c /app/config.generated.json --checkif [ $? -eq 0 ]; thenecho "Configuration validation successful"# Start Centrifugo with generated configexec /app/centrifugo -c /app/config.generated.jsonelseecho "Configuration validation failed"exit 1fiMake it executable:
Terminal window chmod +x docker/entrypoint.shCreate .gitignore
Ensure sensitive files aren’t committed to GitHub by creating
.gitignore:.env.env.local.env.*.localconfig.generated.jsonlogs/*.log.DS_Storevendor/Push to GitHub
Commit and push your Centrifugo configuration to your GitHub repository:
Terminal window git add Dockerfile docker/ config.json .gitignoregit commit -m "Add Klutch.sh deployment configuration for Centrifugo"git push origin mainDeploy on Klutch.sh
- Log in to your Klutch.sh dashboard at klutch.sh/app
- Click “Create New App” and select your GitHub repository containing Centrifugo
- Klutch.sh will automatically detect the Dockerfile in your repository
- Configure your deployment:
- Set your custom domain (e.g.,
centrifugo.example.com) - Configure HTTP traffic on port 8000 for client WebSocket connections
- Set your custom domain (e.g.,
- Click “Deploy” to start the deployment process
- Monitor the deployment logs to ensure successful startup
Configure Traffic Settings
After deployment, configure the traffic routing:
- From your app’s dashboard, navigate to the “Traffic” or “Ports” section
- For WebSocket client connections:
- Set internal port to
8000(Centrifugo’s default client port) - Use HTTP protocol for WebSocket support
- Set internal port to
- For admin API (optional, if exposing):
- Set internal port to
8001(Centrifugo’s admin HTTP API)
- Set internal port to
- For health checks:
- Set internal port to
9000(Centrifugo’s health check port)
- Set internal port to
- Apply the configuration and wait for deployment to update
Configure Environment Variables
Set up environment variables for your Centrifugo instance in the Klutch.sh dashboard:
- Navigate to the “Environment Variables” or “Settings” section
- Add all required variables from the Basic Configuration section below
- For production deployments, add additional optimization variables
- 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
- Navigate to your Centrifugo instance URL (e.g.,
https://centrifugo.example.com:8001) - You’ll see the admin login page
- Enter your admin credentials configured in environment variables:
- Username: typically
adminor configured viaadmin_user - Password: your
CENTRIFUGO_ADMIN_PASSWORD
- Username: typically
- 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 ConfigurationCENTRIFUGO_ADMIN_PASSWORD=secure_admin_password_hereCENTRIFUGO_ADMIN_SECRET=secure_admin_secret_key_hereCENTRIFUGO_API_KEY=your_api_key_hereCENTRIFUGO_TOKEN_SECRET=your_token_secret_key_here
# LoggingCENTRIFUGO_LOG_LEVEL=infoCENTRIFUGO_LOG_FORMAT=json
# PerformanceCENTRIFUGO_CLIENT_CHANNEL_LIMIT=128CENTRIFUGO_CLIENT_QUEUE_MAX_SIZE=10485760CENTRIFUGO_MAX_REQUEST_BODY_SIZE=65536Production Optimization
For production deployments with Redis and advanced features:
# Redis BrokerREDIS_HOST=redis.example.comREDIS_PORT=6379REDIS_PASSWORD=your_redis_passwordREDIS_DB=0
# Centrifugo Engine (redis for clustering)CENTRIFUGO_ENGINE=redis
# Connection LimitsCENTRIFUGO_CLIENT_CHANNEL_LIMIT=256CENTRIFUGO_CLIENT_QUEUE_MAX_SIZE=16777216CENTRIFUGO_MAX_REQUEST_BODY_SIZE=131072
# Proxy Settings (if using backend proxy)CENTRIFUGO_PROXY_CONNECT_TIMEOUT=10000CENTRIFUGO_PROXY_REQUEST_TIMEOUT=10000
# WebSocket SettingsCENTRIFUGO_WEBSOCKET_COMPRESSION=trueCENTRIFUGO_WEBSOCKET_READ_BUFFER_SIZE=4096CENTRIFUGO_WEBSOCKET_WRITE_BUFFER_SIZE=4096
# TLS Settings (if terminating TLS in Centrifugo)CENTRIFUGO_TLS_ENABLED=falseCENTRIFUGO_TLS_CERT=/etc/certs/cert.pemCENTRIFUGO_TLS_KEY=/etc/certs/key.pem
# MetricsCENTRIFUGO_PROMETHEUS_ENABLED=trueCENTRIFUGO_PROMETHEUS_ADDRESS=:9090Code 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 asyncioimport jsonfrom 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 usageconst 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_sizeif 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:
-
Check Latest Version
Terminal window # Visit GitHub releasescurl -s https://api.github.com/repos/centrifugal/centrifugo/releases/latest | grep tag_name -
Update Dockerfile Update the image tag in your Dockerfile:
FROM centrifugo/centrifugo:v6.5.1 # Update version here -
Test Configuration
Terminal window # Test with new version locallydocker run -it centrifugo/centrifugo:v6.5.1 centrifugo --check -c config.json -
Push Changes
Terminal window git add Dockerfilegit commit -m "Update Centrifugo to v6.5.1"git push origin main -
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
-
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
- Official Centrifugo Documentation
- Centrifugo GitHub Repository
- Getting Started Guide
- WebSocket Chat Tutorial
- Centrifugo Blog
- Official Client Libraries
- Centrifugo Discord Community
- Centrifugo Telegram Group
- Prometheus Metrics Guide
- Redis Engine Documentation
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