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:0.4.5

# 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:0.4.5

# 4. Node 2/3: same steps, adjust external_ip and cluster.peers

6. 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)