SipFlow Cluster Deployment
SipFlow is RustPBX’s built-in SIP+RTP signaling capture and replay system, supporting local mode and standalone cluster mode.
1. Feature Overview
| Capability | Description |
|---|---|
| SIP signaling capture | Complete SIP request/response messages |
| RTP media capture | Optional, triggered by recording policy |
| WAV replay | Generate call recordings from RTP packets |
| Timeline viewer | View complete signaling flow by call_id in the web console |
| S3/HTTP upload | Upload to object storage after call ends |
2. Local Mode (Single Node)
2.1 Configuration
[sipflow]
[sipflow.local]
subdirs = "daily" # none / daily / hourly
flush_count = 100 # Flush to disk every 100 packets
flush_interval_secs = 5 # Max 5 seconds between flushes
id_cache_size = 10000 # Call-ID cache size
2.2 Storage Structure
sipflow/
├── 20260526/
│ ├── 20260526.sqlite # Metadata index
│ └── 20260526.raw # Raw packets (zstd compressed)
├── 20260527/
│ ├── 20260527.sqlite
│ └── 20260527.raw
*.sqlite: each record containscall_id, timestamp, source/destination IP/port, SIP method*.raw: binary packet data, zstd compressed
2.3 RTP Recording Generation
Generate WAV from captured data:
GET /api/sipflow/media?call_id=xxx&start=0&end=3600&format=wav
Supports PCMU, PCMA, G722, L16 codec to WAV conversion.
2.4 Upload Configuration
Automatic upload after call ends:
[sipflow.upload]
type = "s3"
bucket = "sipflow-archives"
region = "us-east-1"
endpoint = "https://s3.amazonaws.com"
access_key = "AKIA..."
secret_key = "secret..."
# Or upload via HTTP
# [sipflow.upload]
# type = "http"
# url = "https://api.example.com/sipflow/upload"
3. Standalone Cluster Mode
For multi-node deployments, SipFlow can be deployed as a standalone service with consistent hash routing.
3.1 Architecture
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ RustPBX │ │ RustPBX │ │ RustPBX │
│ Node 1 │ │ Node 2 │ │ Node 3 │
└──────┬──────┘ └──────┬──────┘ └──────┬──────┘
│ │ │
│ UDP packets + HTTP queries │
▼ ▼ ▼
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ SipFlow │ │ SipFlow │ │ SipFlow │
│ Server A │ │ Server B │ │ Server C │
│ :3000/3001 │ │ :3000/3001 │ │ :3000/3001 │
└─────────────┘ └─────────────┘ └─────────────┘
- RustPBX nodes select a SipFlow Server via
call_idconsistent hashing - Each SipFlow Server stores data independently
- Queries are automatically routed to the correct server
3.2 SipFlow Server Deployment
SipFlow Server is a standalone binary (sipflow), compiled from the RustPBX source:
cargo build --release --bin sipflow
Launch parameters:
/static/docs/addons/sipflow \
--addr 0.0.0.0 \
--port 3000 \ # UDP receive port
--http-port 3001 \ # HTTP API port
--root /data/sipflow \ # Storage directory
--flush-count 200 \ # Flush packet count
--flush-interval 5 \ # Flush interval seconds
--buffer-size 65536 # UDP receive buffer
Docker deployment:
docker run -d --name sipflow-a \
-v /data/sipflow:/data/sipflow \
-p 3000:3000/udp -p 3001:3001 \
docker.cnb.cool/miuda.ai/rustpbx:latest \
/app/sipflow --addr 0.0.0.0 --port 3000 --http-port 3001 --root /data/sipflow
3.3 SipFlow Server HTTP API
| Endpoint | Method | Description |
|---|---|---|
/health | GET | Health check |
/flow | GET | Query SIP signaling (callid, start, end parameters) |
/media | GET | Generate WAV recording (callid, start, end, format parameters) |
3.4 RustPBX Node Configuration
Each RustPBX node configures the SipFlow remote backend:
[sipflow]
[sipflow.remote]
flush_interval_secs = 5
[[sipflow.remote.nodes]]
udp = "10.0.1.1:3000"
http = "http://10.0.1.1:3001"
[[sipflow.remote.nodes]]
udp = "10.0.1.2:3000"
http = "http://10.0.1.2:3001"
[[sipflow.remote.nodes]]
udp = "10.0.1.3:3000"
http = "http://10.0.1.3:3001"
Routing rules:
- Write:
hash(call_id) % node_count→ select target server, send via UDP - Query: same hash routing to the correct server, HTTP GET request
3.5 Consistent Hashing
SipFlow uses simple modulo hashing (not a consistent hash ring):
- When adding/removing nodes, approximately
1/Nof call_ids will change routing - Recommend determining node count during planning to avoid frequent changes
- After node changes, querying historical data may require per-node traversal
4. Web Console Viewer
Console → Call Records → Click Call → SIP Flow:
Click any call in the CDR list to view the complete SIP signaling timeline:
- Timing of each SIP message
- Request/response pairing
- RTP stream information
- Playable call recordings
5. Storage Planning
5.1 Disk Space Estimation
| Data Type | Size per Call | 10K calls/day/month |
|---|---|---|
| SIP signaling | ~5 KB | ~150 MB |
| RTP media (optional) | ~50-200 KB | ~1.5-6 GB |
| SQLite index | ~500 B | ~15 MB |
5.2 Retention Policy
Recommend cleaning expired data via a scheduled task:
# Delete data older than 90 days
find /data/sipflow -maxdepth 1 -type d -name "20*" -mtime +90 -exec rm -rf {} \;
Or configure upload to S3 with automatic local cleanup.
6. Network Requirements
| Port | Protocol | Purpose |
|---|---|---|
| 3000 | UDP | RustPBX → SipFlow packet transport |
| 3001 | HTTP | RustPBX → SipFlow query API |
RustPBX nodes must be able to reach all SipFlow Server UDP and HTTP ports.
7. Recording Policy vs SipFlow
SipFlow capture and call recording are independent:
| Configuration | Description |
|---|---|
[recording] | Call recording (WAV/MP3) |
[sipflow] | Signaling capture (SIP+RTP packets) |
- SipFlow RTP capture follows the recording policy (only captures RTP for recorded calls)
- SIP signaling is always captured (regardless of recording)
- SipFlow-generated WAV can serve as a recording backup