Centrifugo
Overview
Centrifugo is a scalable, open-source real-time messaging server. It keeps persistent connections open to your online users over WebSocket, Server-Sent Events, HTTP streaming and other transports. It instantly delivers messages to everyone subscribed to a channel.
Centrifugo follows a language-agnostic publish and subscribe model, so your real-time transport layer stays completely separate from your application. Your backend publishes events through a simple server-side HTTP API, and your users connect with short-lived JSON Web Tokens. It is a single Go binary, so it stays lightweight and starts instantly.
The SecureAnyCloud image installs Centrifugo 6.9.1 and puts it behind an nginx reverse proxy that binds the server to loopback and already handles WebSocket upgrades.
The appliance is secure by default, with no default login. On first boot, centrifugo-firstboot.service generates four unique per-VM secrets, injects them into the configuration, and writes them to a root-only file at /root/centrifugo-info.txt. Nothing is baked into the image.
What you get:
- Centrifugo 6.9.1 single Go binary (
/usr/local/bin/centrifugo) centrifugo.servicerunning ascentrifugo, bound to loopback127.0.0.1:8000nginx.servicereverse proxy on TCP 80, TLS ready, with WebSocket upgrade configuredcentrifugo-firstboot.servicegenerating four per-VM secrets on first boot- Built-in admin web UI for inspecting nodes and channels
- A server HTTP API for publishing, broadcasting, presence and channel history
- A
smokechannel namespace preconfigured with history, ready to test - Ubuntu 24.04 LTS base, latest patches, unattended security upgrades enabled
- 24/7 SecureAnyCloud support, 24h response SLA
Prerequisites
You need an active Azure subscription, an SSH key, and a VNet with a subnet.
The recommended VM size is Standard_B2s. Centrifugo is very light, and 4 GB RAM is plenty for tens of thousands of connections.
Deploy from the Azure Portal
Search the Azure Marketplace for Centrifugo, choose the plan, and create the VM.
In the networking step, attach a network security group (NSG) that allows inbound TCP 22 (SSH) and TCP 80 (the admin UI, server API and client transports) from your client networks only. Put a TLS reverse proxy in front of port 80 for production.
Deploy from the Azure CLI
RG="centrifugo-prod"; LOCATION="eastus"; VM_NAME="centrifugo-01" IMAGE_URN="sac1647283583153:centrifugo-ubuntu-24-04:default:latest" SSH_KEY="$(cat ~/.ssh/id_rsa.pub)" az group create --name "$RG" --location "$LOCATION" az network vnet create -g "$RG" --name cf-vnet --address-prefix 10.108.0.0/16 --subnet-name cf-subnet --subnet-prefix 10.108.1.0/24 az network nsg create -g "$RG" --name cf-nsg az network nsg rule create -g "$RG" --nsg-name cf-nsg --name allow-ssh --priority 100 \
--source-address-prefixes "<your-mgmt-cidr>" --destination-port-ranges 22 --access Allow --protocol Tcp az network nsg rule create -g "$RG" --nsg-name cf-nsg --name allow-web --priority 110 \
--source-address-prefixes "<your-mgmt-cidr>" --destination-port-ranges 80 --access Allow --protocol Tcp
# Accept the Marketplace terms once per subscription (required before the first CLI deploy)
az vm image terms accept --urn sac1647283583153:centrifugo-ubuntu-24-04:default:latest
az vm create -g "$RG" --name "$VM_NAME" --image "$IMAGE_URN" \
--size Standard_B2s --storage-sku StandardSSD_LRS \
--admin-username azureuser --ssh-key-values "$SSH_KEY" \
--vnet-name cf-vnet --subnet cf-subnet --nsg cf-nsg --public-ip-sku StandardConnect via SSH
ssh azureuser@<vm-ip>centrifugo.service, nginx.service and centrifugo-firstboot.service all start automatically on first boot.
Verify the Service
sudo systemctl is-active centrifugo nginx centrifugo-firstboot
sudo test -f /var/lib/sac/data/centrifugo-firstboot.done && echo FIRSTBOOT_DONE
sudo ss -tlnp | grep -E ':80 |:8000 'Expected output: all three services are active, nginx is bound to the public port 80, and Centrifugo is bound to loopback 127.0.0.1:8000 only:
active active active FIRSTBOOT_DONE LISTEN 0 4096 127.0.0.1:8000 0.0.0.0:* users:(("centrifugo",...)) LISTEN 0 511 0.0.0.0:80 0.0.0.0:* users:(("nginx",...))Get Your Secrets
Centrifugo has no default login. On first boot, four unique secrets are generated and written to a root-only note: the admin password, the server API key, the client token signing key and the admin session secret. None of them is baked into the image:
sudo cat /root/centrifugo-info.txt
sudo ss -tlnp | grep 8000The note contains all four secrets and the resolved URL, all unique to this machine:
CENTRIFUGO_ADMIN_PASSWORD=<CENTRIFUGO_ADMIN_PASSWORD> CENTRIFUGO_API_KEY=<per-VM api key> CENTRIFUGO_TOKEN_HMAC_SECRET_KEY=<per-VM jwt signing key> CENTRIFUGO_ADMIN_SECRET=<per-VM admin session secret> CENTRIFUGO_URL=http://<vm-ip>/Publish a Message with the Server API
Your backend publishes events through the server HTTP API, authenticated with the API key in the X-API-Key header. Publish a message to the preconfigured smoke namespace, then read it back from channel history. This is exactly what your application does to push a real-time event:
API_KEY=$(sudo grep '^CENTRIFUGO_API_KEY=' /root/centrifugo-info.txt | cut -d= -f2-)
curl -s -H "X-API-Key: $API_KEY" -H 'Content-Type: application/json' \
--data '{"channel":"smoke:demo","data":{"message":"hello from sac"}}' \
http://127.0.0.1/api/publish | jq .
curl -s -H "X-API-Key: $API_KEY" -H 'Content-Type: application/json' \
--data '{"channel":"smoke:demo","limit":5}' \
http://127.0.0.1/api/history | jq '.result.publications'The publish returns a stream position, and the history call returns the message you just published:
{ "result": { "offset": 1, "epoch": "YDgviNmM" } } [ { "data": { "message": "hello from sac" }, "offset": 1 } ]Log In to the Admin UI
Open the admin web UI in a browser and log in with the admin password from Step 5. The admin UI has no username, only a password:
open http://<vm-ip>/The Status Dashboard
After you log in, the Status tab shows live metrics: how many nodes are running and the total number of connected clients and subscriptions. A per-node table lists the Centrifugo version, uptime, client count and channel count. This is your at-a-glance health and scale view:
The Actions Console
The Actions tab is a console for calling the server API straight from the browser. Pick a method (Publish, Broadcast, Presence, History, Channels and more), fill in the form, and submit. This is useful for testing channels and inspecting state without writing any code:
Publish from the Console
Set the method to Publish, enter a channel such as smoke:demo, type a small JSON payload, and click PUBLISH. The request and the server response appear below the form, so you can watch a real-time message go out live:
Connect a Client
Your users connect from the browser (or a mobile or server SDK) over WebSocket, authenticating with a short-lived JWT signed with the client token signing key from Step 5. Generate a test token on the server and point a client at the WebSocket endpoint:
# generate a connection JWT for user "alice" (valid for the client SDK)
sudo /usr/local/bin/centrifugo gentoken -c /etc/centrifugo/config.json -u alice
# your browser client then connects to: ws://<vm-ip>/connection/websocketOfficial client SDKs are available for JavaScript, Dart, Swift, Java, Python, Go and .NET. Point them at your server's /connection/websocket endpoint and subscribe to a channel to start receiving events.
Server Components
Component Path
Centrifugo binary /usr/local/bin/centrifugo
Config file /etc/centrifugo/config.json
Systemd unit /etc/systemd/system/centrifugo.service
Firstboot script /usr/local/sbin/centrifugo-firstboot.sh
Per VM secrets note /root/centrifugo-info.txt (mode 0600)
Sentinel /var/lib/sac/data/centrifugo-firstboot.done
/usr/local/bin/centrifugo version ls /usr/local/bin/centrifugo /etc/centrifugo/config.json /etc/systemd/system/centrifugo.serviceManaging the Service
sudo systemctl restart centrifugo.service
sudo systemctl is-active centrifugo.serviceCentrifugo restarts in well under a second because it is a single binary that uses the built-in in-memory engine. The service is hardened with NoNewPrivileges, ProtectSystem=strict and ProtectHome, and writes nothing to disk.
Because the engine is in memory, channel history and presence reset on restart. Attach Redis in the configuration if you need history to survive a restart or to scale across multiple nodes.
Configuration
Centrifugo is configured through /etc/centrifugo/config.json. Useful keys already set by the image:
Setting Meaning Image default
http_server.address Bind address 127.0.0.1 (loopback)
http_server.port Bind port 8000
admin.enabled Admin web UI true
admin.password Admin login password generated at first boot
http_api.key Server API key generated at first boot
client.token.hmac_secret_key Client JWT signing key generated at first boot
channel.namespaces Channel namespaces a smoke namespace with history enabled
After you edit the file, apply the changes with sudo systemctl restart centrifugo.service.
Before you connect browser clients from your own web app, set client.allowed_origins to your app's origins so that cross-origin WebSocket connections are accepted.
Add TLS (Optional)
For production, terminate TLS at nginx. Point a DNS record at the VM, then use the packaged nginx with a certificate from Let's Encrypt:
sudo apt-get install -y certbot python3-certbot-nginx
sudo certbot --nginx -d <your-domain>certbot installs the certificate, rewrites the nginx server block to listen on 443, and sets up automatic renewal. Real-time transports run cleanly over the resulting wss:// and https:// endpoints.
Security Recommendations
- Restrict the NSG so ports 80 and 22 only reach trusted networks.
- Terminate TLS at nginx (Step 15) so tokens, API keys and messages travel encrypted.
- Set
client.allowed_originsto your application's origins so only your web app can open browser WebSocket connections. - Keep the API key secret. It is the key to publishing on every channel. If it is ever exposed, rotate it in
/etc/centrifugo/config.jsonand restart. - Use short-lived client JWTs signed with the token signing key, so a leaked client token expires quickly.
- Patch the OS monthly with
sudo apt-get update && sudo apt-get upgrade. Unattended security upgrades are already enabled.
Support and Licensing
Centrifugo is distributed under the Apache License 2.0, with no per-CPU or per-user fee. SecureAnyCloud provides commercial support separately.
- Email: sales@secureanycloud.com
- Website: secureanycloud.com
- Support hours: 24/7, 24h response SLA
Deploy on Azure
Launch Centrifugo on Ubuntu 24.04 with 24/7 support from SecureAnyCloud.
View on Marketplace
Need Help?
Our support team is available 24/7. sales@secureanycloud.com
Deploy on Azure
Launch Centrifugo on Ubuntu 24.04 LTS on Azure with 24/7 support from SecureAnyCloud.
View this image
Need Help?
Our support team is available 24/7.
sales@secureanycloud.com
Overview
Centrifugo is a scalable, open-source real-time messaging server. It keeps persistent connections open to your online users over WebSocket, Server-Sent Events, HTTP streaming and other transports. It instantly delivers messages to everyone subscribed to a channel.
Centrifugo follows a language-agnostic publish and subscribe model, so your real-time transport layer stays completely separate from your application. Your backend publishes events through a simple server-side HTTP API, and your users connect with short-lived JSON Web Tokens. It is a single Go binary, so it stays lightweight and starts instantly.
The SecureAnyCloud image installs Centrifugo 6.9.1 and puts it behind an nginx reverse proxy that binds the server to loopback and already handles WebSocket upgrades.
The appliance is secure by default, with no default login. On first boot, centrifugo-firstboot.service generates four unique per-instance secrets, injects them into the configuration, and writes them to a root-only file at /root/centrifugo-info.txt. Nothing is baked into the image.
What you get:
- Centrifugo 6.9.1 single Go binary (
/usr/local/bin/centrifugo) centrifugo.servicerunning ascentrifugo, bound to loopback127.0.0.1:8000nginx.servicereverse proxy on TCP 80, TLS ready, with WebSocket upgrade configuredcentrifugo-firstboot.servicegenerating four per-instance secrets on first boot- Built-in admin web UI for inspecting nodes and channels
- A server HTTP API for publishing, broadcasting, presence and channel history
- A
smokechannel namespace preconfigured with history, ready to test - Ubuntu 24.04 LTS base, latest patches, unattended security upgrades enabled
- 24/7 SecureAnyCloud support, 24h response SLA
Connecting to your instance
Connect over SSH on port 22 as the default login user for your AMI variant. Use the key pair you selected at launch and the instance's public IP or DNS name.
OS variant SSH login user Example
Ubuntu 24.04 LTS ubuntu ssh ubuntu@<public-ip>
Prerequisites
You need an AWS account, an EC2 key pair in your target Region, and a VPC with a subnet.
The recommended instance type is m5.large. Centrifugo is very light, and a couple of GB of RAM is plenty for tens of thousands of connections. Larger types scale the connection count.
Launch from the EC2 Console
Find the Centrifugo listing in AWS Marketplace, subscribe, and launch it. In the launch wizard, choose your instance type, key pair and subnet.
Attach a security group that allows inbound TCP 22 (SSH) and TCP 80 (the admin UI, server API and client transports) from your client networks only. For production, put a TLS reverse proxy, or a load balancer with TLS, in front of port 80.
Launch from the AWS CLI
AMI_ID="ami-0123456789abcdef0"
# the Centrifugo AMI id in your region KEY_NAME="my-keypair"; SUBNET_ID="subnet-abc123"; SG_ID="sg-abc123" aws ec2 run-instances --image-id "$AMI_ID" --instance-type m5.large \
--key-name "$KEY_NAME" --subnet-id "$SUBNET_ID" --security-group-ids "$SG_ID" \
--metadata-options 'HttpTokens=required' \
--tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=centrifugo-01}]'Create the security group first with inbound TCP 22 and TCP 80 restricted to your own networks.
Connect via SSH
ssh ubuntu@<public-ip>centrifugo.service, nginx.service and centrifugo-firstboot.service all start automatically on first boot.
Verify the Service
sudo systemctl is-active centrifugo nginx centrifugo-firstboot
sudo test -f /var/lib/sac/data/centrifugo-firstboot.done && echo FIRSTBOOT_DONE
sudo ss -tlnp | grep -E ':80 |:8000 'Expected output: all three services are active, nginx is bound to the public port 80, and Centrifugo is bound to loopback 127.0.0.1:8000 only:
active active active FIRSTBOOT_DONE LISTEN 0 4096 127.0.0.1:8000 0.0.0.0:* users:(("centrifugo",...)) LISTEN 0 511 0.0.0.0:80 0.0.0.0:* users:(("nginx",...))Get Your Secrets
Centrifugo has no default login. On first boot, four unique secrets are generated and written to a root-only note: the admin password, the server API key, the client token signing key and the admin session secret. None of them is baked into the image:
sudo cat /root/centrifugo-info.txtThe note contains all four secrets and the resolved URL, all unique to this instance:
CENTRIFUGO_ADMIN_PASSWORD=<CENTRIFUGO_ADMIN_PASSWORD> CENTRIFUGO_API_KEY=<per-instance api key> CENTRIFUGO_TOKEN_HMAC_SECRET_KEY=<per-instance jwt signing key> CENTRIFUGO_ADMIN_SECRET=<per-instance admin session secret> CENTRIFUGO_URL=http://<public-ip>/Publish a Message with the Server API
Your backend publishes events through the server HTTP API, authenticated with the API key in the X-API-Key header. Publish a message to the preconfigured smoke namespace, then read it back from channel history. This is exactly what your application does to push a real-time event:
API_KEY=$(sudo grep '^CENTRIFUGO_API_KEY=' /root/centrifugo-info.txt | cut -d= -f2-)
curl -s -H "X-API-Key: $API_KEY" -H 'Content-Type: application/json' \
--data '{"channel":"smoke:demo","data":{"message":"hello from sac"}}' \
http://127.0.0.1/api/publish | jq .
curl -s -H "X-API-Key: $API_KEY" -H 'Content-Type: application/json' \
--data '{"channel":"smoke:demo","limit":5}' \
http://127.0.0.1/api/history | jq '.result.publications'The publish returns a stream position, and the history call returns the message you just published:
{ "result": { "offset": 1, "epoch": "nPGuReDz" } } [ { "data": { "message": "hello from sac" }, "offset": 1 } ]Log In to the Admin UI
Open the admin web UI in a browser and log in with the admin password from Step 5. The admin UI has no username, only a password:
http://<public-ip>/The Status Dashboard
After you log in, the Status tab shows live metrics: how many nodes are running and the total number of connected clients and subscriptions. A per-node table lists the Centrifugo version, uptime, client count and channel count. This is your at-a-glance health and scale view:
The Actions Console
The Actions tab is a console for calling the server API straight from the browser. Pick a method (Publish, Broadcast, Presence, History, Channels and more), fill in the form, and submit. This is useful for testing channels and inspecting state without writing any code:
Publish from the Console
Set the method to Publish, enter a channel such as smoke:demo, type a small JSON payload, and click PUBLISH. The request and the server response appear below the form, so you can watch a real-time message go out live:
Connect a Client
Your users connect from the browser (or a mobile or server SDK) over WebSocket, authenticating with a short-lived JWT signed with the client token signing key from Step 5. Generate a test token on the server and point a client at the WebSocket endpoint:
# generate a connection JWT for user "alice" (valid for the client SDK)
sudo /usr/local/bin/centrifugo gentoken -c /etc/centrifugo/config.json -u alice
# your browser client then connects to: ws://<public-ip>/connection/websocketOfficial client SDKs are available for JavaScript, Dart, Swift, Java, Python, Go and .NET. Point them at your server's /connection/websocket endpoint and subscribe to a channel to start receiving events.
Server Components
Component Path
Centrifugo binary /usr/local/bin/centrifugo
Config file /etc/centrifugo/config.json
Systemd unit /etc/systemd/system/centrifugo.service
Firstboot script /usr/local/sbin/centrifugo-firstboot.sh
Per instance secrets note /root/centrifugo-info.txt (mode 0600)
Sentinel /var/lib/sac/data/centrifugo-firstboot.done
/usr/local/bin/centrifugo version ls /usr/local/bin/centrifugo /etc/centrifugo/config.json /etc/systemd/system/centrifugo.serviceCentrifugo reports version 6.9.1 and the installed component paths:
Centrifugo v6.9.1 (Go version: go1.26.5) /etc/centrifugo/config.json /etc/systemd/system/centrifugo.service /usr/local/bin/centrifugoManaging the Service
sudo systemctl restart centrifugo.service
sudo systemctl is-active centrifugo.serviceCentrifugo restarts in well under a second because it is a single binary that uses the built-in in-memory engine. The service is hardened with NoNewPrivileges, ProtectSystem=strict and ProtectHome, and writes nothing to disk.
Because the engine is in memory, channel history and presence reset on restart. Attach Redis in the configuration if you need history to survive a restart or to scale across multiple nodes.
Configuration
Centrifugo is configured through /etc/centrifugo/config.json. Useful keys already set by the image:
Setting Meaning Image default
http_server.address Bind address 127.0.0.1 (loopback)
http_server.port Bind port 8000
admin.enabled Admin web UI true
admin.password Admin login password generated on first boot
http_api.key Server API key generated on first boot
client.token.hmac_secret_key Client JWT signing key generated on first boot
channel.namespaces Channel namespaces a smoke namespace with history enabled
After you edit the file, apply the changes with sudo systemctl restart centrifugo.service.
Before you connect browser clients from your own web app, set client.allowed_origins to your app's origins so that cross-origin WebSocket connections are accepted.
Add TLS (Optional)
For production, terminate TLS at nginx. Point a DNS record at the instance, then use the packaged nginx with a certificate from Let's Encrypt:
sudo apt-get install -y certbot python3-certbot-nginx
sudo certbot --nginx -d <your-domain>certbot installs the certificate, rewrites the nginx server block to listen on 443, and sets up automatic renewal. Real-time transports run cleanly over the resulting wss:// and https:// endpoints.
Security Recommendations
- Restrict the security group so ports 80 and 22 only reach trusted networks.
- Terminate TLS at nginx (Step 15) so tokens, API keys and messages travel encrypted.
- Set
client.allowed_originsto your application's origins so only your web app can open browser WebSocket connections. - Keep the API key secret. It is the key to publishing on every channel. If it is ever exposed, rotate it in
/etc/centrifugo/config.jsonand restart. - Use short-lived client JWTs signed with the token signing key, so a leaked client token expires quickly.
- Patch the OS monthly with
sudo apt-get update && sudo apt-get upgrade. Unattended security upgrades are already enabled.
Support and Licensing
Centrifugo is distributed under the Apache License 2.0, with no per-CPU or per-user fee. SecureAnyCloud provides commercial support separately.
- Email: sales@secureanycloud.com
- Website: secureanycloud.com
- Support hours: 24/7, 24h response SLA
Deploy on AWS
Launch Centrifugo on Ubuntu 24.04 with 24/7 support from SecureAnyCloud.
View on Marketplace
Need Help?
Our support team is available 24/7. sales@secureanycloud.com
Deploy on AWS
Launch Centrifugo Realtime Messaging Server by SecureAnyCloud with 24/7 support from SecureAnyCloud.
View on Marketplace
Need Help?
Our support team is available 24/7.
sales@secureanycloud.com