Cluster Deployment
RustPBX supports multi-node clustering for registration state synchronization, distributed SipFlow capture, and cross-node call control.
1. Architecture Overview
┌──────────────┐
│ Load Balancer│
│ (SIP/HTTP) │
└──────┬───────┘
┌───────────┼───────────┐
▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐
│ Node 1 │ │ Node 2 │ │ Node 3 │
│ SIP+HTTP │◄─► SIP+HTTP│◄─► SIP+HTTP│
│ SipFlow │ │ SipFlow │ │ SipFlow │
└──────────┘ └──────────┘ └──────────┘
│ │ │
└───────────┼───────────┘
▼
┌──────────────┐
│ MySQL/PgSQL │
└──────────────┘
Key capabilities:
- Inter-node event sync via SIP MESSAGE for registration/presence
- SipFlow supports consistent hashing by
call_idto route to specific capture nodes - Shared database (MySQL/PostgreSQL) ensures config and CDR consistency
2. Database Requirements
Cluster mode does not support SQLite — a shared database is required:
| Database | Min Version | Recommended | Notes |
|---|---|---|---|
| MySQL | 8.0+ | 8.4 LTS | Charset utf8mb4, collation utf8mb4_unicode_ci |
| PostgreSQL | 14+ | 16 | Enable pg_stat_statements for monitoring |
Connection string examples:
# MySQL
database_url = "mysql://rustpbx:password@10.0.0.100:3306/rustpbx"
# PostgreSQL
database_url = "postgres://rustpbx:password@10.0.0.100:5432/rustpbx"
Important notes:
- All nodes must connect to the same database instance
- SeaORM auto-runs migrations on first startup; subsequent nodes detect and skip completed migrations
- DDL files in the source root (
rustpbx_ddl_*.sql) are available for manual schema creation
3. Cluster Configuration
3.1 Inter-Node Event Sync
Configure peer nodes in [cluster] section of config.toml:
[cluster]
peers = [
{ addr = "10.0.0.2", sip_port = 5060, ami_port = 8080 },
{ addr = "10.0.0.3", sip_port = 5060, ami_port = 8080 },
]
Each node only lists the other nodes — do not include itself. Nodes exchange JSON events via SIP MESSAGE (application/x-rustpbx-cluster-event).
Synced event types:
- Locator events: user registration/unregistration state
- Presence events: user online/offline/busy status
3.2 SipFlow Cluster Mode
[sipflow]
[sipflow.remote]
flush_interval_secs = 5
[[sipflow.remote.nodes]]
udp = "10.0.0.2:6060"
http = "http://10.0.0.2:6060"
[[sipflow.remote.nodes]]
udp = "10.0.0.3:6060"
http = "http://10.0.0.3:6060"
- Each proxy node can read and write; requests are routed by
call_idconsistent hashing - Deploy the standalone
sipflowbinary (fromsrc/bin/sipflow.rs) as the capture server
3.3 Core Config Per Node
http_addr = "0.0.0.0:8080"
database_url = "mysql://rustpbx:password@dbhost:3306/rustpbx"
external_ip = "10.0.0.1"
[proxy]
addr = "0.0.0.0"
udp_port = 5060
modules = ["acl", "auth", "registrar", "call", "presence"]
media_proxy = "auto"
[console]
session_secret = "your-secret-here" # Must be identical across all nodes
4. Load Balancing
4.1 SIP Traffic
Use a SIP Load Balancer (OpenSIPS, Kamailio) or DNS SRV:
- Source IP hash: ensures REGISTER messages from the same user reach the same node (reduces cross-node sync)
- Call-ID hash: ensures signaling for the same call stays on the same node
4.2 HTTP Traffic
Use Nginx/HAProxy reverse proxy:
upstream rustpbx {
ip_hash; # Session affinity
server 10.0.0.1:8080;
server 10.0.0.2:8080;
server 10.0.0.3:8080;
}
5. Deployment Steps
# 1. Prepare shared database
mysql -u root -p -e "CREATE DATABASE rustpbx CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"
# 2. Deploy on each node
docker pull docker.cnb.cool/miuda.ai/rustpbx:latest
# 3. Node 1 (10.0.0.1)
docker run -d --name rustpbx \
-v $(pwd)/config.toml:/app/config.toml \
-v $(pwd)/config:/app/config \
-p 8080:8080 -p 5060:5060/udp \
docker.cnb.cool/miuda.ai/rustpbx:latest
# 4. Node 2/3: same steps, adjust external_ip and cluster.peers
6. Always-On Cluster Event Hub
The cluster event hub is provisioned even in single-node mode (cluster.peers is empty or the entire [cluster] section is omitted). This means:
- Local event dispatch: locator (registration/unregistration) and presence (online/offline/busy) events are always dispatched to addon handlers through the hub, regardless of cluster mode.
- Cross-node sync: only activates when
cluster.peerslists at least one peer node. Events are exchanged via SIP MESSAGE (application/x-rustpbx-cluster-event). - CC addon integration: the Contact Center addon now wires the
active_call_registryfrom the event hub, enabling CTI control endpoints (hold, transfer, record, mute) to function reliably. Previously these could return503in certain topologies.
This design ensures that addons depending on event dispatch work identically in both single-node and clustered deployments.
7. Operations
- Database connection pool: each node’s default pool is managed by SeaORM; total
nodes × pool_sizemust not exceed databasemax_connections - Time sync: all nodes must use NTP — CDR timestamps depend on system clocks
- Config consistency:
config/trunks/,config/routes/etc. should be synced to all nodes via shared storage or GitOps - Rolling restart: restart nodes one at a time, ensuring at least one node remains online
- SipFlow storage: plan disk capacity per capture node independently (~50-200KB signaling data per call)
8. Cluster AMI endpoints (commercial)
Multi-node deployments expose additional cluster management endpoints under {ami_path}:
| Method | Path | Description |
|---|---|---|
POST | /cluster/ping | Ping all peer nodes for health |
GET | /cluster/reload_config | SSE-based cluster config reload stream |
POST | /cluster/reload_sync | Sync JSON reload payload to a specific peer |
POST | /cluster/dispatch_command | Dispatch a call control command to a peer node |
GET | /cluster/show_session/{session_id} | Show detailed call session state on a peer |
GET | /cluster/list_calls | List all active calls across the cluster |
These endpoints enable centralized call control, cross-node session inspection, and coordinated configuration pushes from any peer in the cluster.