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_id to 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:

DatabaseMin VersionRecommendedNotes
MySQL8.0+8.4 LTSCharset utf8mb4, collation utf8mb4_unicode_ci
PostgreSQL14+16Enable 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_id consistent hashing
  • Deploy the standalone sipflow binary (from src/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.peers lists 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_registry from the event hub, enabling CTI control endpoints (hold, transfer, record, mute) to function reliably. Previously these could return 503 in 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_size must not exceed database max_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}:

MethodPathDescription
POST/cluster/pingPing all peer nodes for health
GET/cluster/reload_configSSE-based cluster config reload stream
POST/cluster/reload_syncSync JSON reload payload to a specific peer
POST/cluster/dispatch_commandDispatch 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_callsList 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.