What's New in RustPBX 0.5: Clusters, Transfers, and Call-Level Truth
Three months of steady work went into RustPBX 0.5 — roughly two thousand commits since the 0.4.x series. The theme across all of them: when something goes wrong mid-call, the platform should already know why. This post walks through the changes that matter most for anyone running RustPBX in production, from a single box to a multi-node cluster.
Clusters That Actually Share State
RustPBX 0.5 wires the distributed session registry end to end. A call that lands on node A is now visible to node B, which unlocks three things:
- Cluster-wide session operations — answer, transfer, and hangup requests are routed to the node that owns the call, so a supervisor console can operate any call without knowing where it lives.
- Session
user_datareplication — application-specific data you attach to a call (CRM ticket ids, agent context, campaign tags) survives node handoffs and failovers. Transfer sub-sessions inherit it, so a call that moves between nodes or legs doesn’t lose its business context. - Session heartbeat gauges — every node reports liveness of the sessions it owns, and the locator reports pruned bindings as offline, so a dead node’s calls show up as offline instead of silently ghosting.
Transfers You Can Trust
REFER handling was hardened across the board (the P1a/P1b/R1/R2 series):
- Blind and attended REFER now fall back to a proper B2BUA bridge when the target can’t be reached with plain signaling, and cross-session supervisor takeover works reliably.
- Application handoffs are preserved: an inbound REFER that lands mid-IVR or mid-AI-session carries the application state to the new leg instead of dropping the caller back to a menu.
- Transfer headers (like
Replaces-context or your own routing hints) can be forwarded onto the outbound INVITE, which matters for carriers that price or route based on them. - IVR flows gained an explicit resume event, so a suspended flow continues exactly where it stopped — no more menu replay when a call comes back from a transfer.
Per-Call Media Evidence
Every call now carries a small evidence trail in its CDR:
rtcpPacketsLostandrelayDropcounters collected per leg- A 5-second quality
INFOtrace while the call runs - A
proxy.leg_media_incompleteflag when a leg never actually delivered media — silent legs are flagged instead of counted as healthy answered calls
Combined with the existing call trace timeline and the unified call_error registry, the call record detail page in the console now answers “why did this call sound bad / fail” without opening Wireshark.
For routing, a new per-dialplan relay_only switch forces a leg through media relay (handy behind EIP/NAT setups where direct paths fail), and plain-RTP legs can advertise ICE-lite for strict endpoints such as Teams Direct Routing.
Recording and Storage Grown-Up Features
- Per-segment recording ids and metadata — consult transfers and hold/resume produce separate segments, each independently addressable and downloadable.
- Auto-start exemptions — trunk- or application-level rules can opt specific calls out of automatic recording (compliance use cases).
- Upload retry worker — a recording upload that fails is retried with backoff instead of being lost.
- S3 presigned download URLs — recordings and SipFlow exports can be served through presigned GET URLs, so the PBX no longer proxies large media through the console. Anonymous S3 credentials are supported for public buckets, and the HTTP upload scheme (http/https) is configurable.
AI Voice, Transcription, and Conferencing
- Per-call transcription plans — choose provider, language, and auto-start per call rather than globally; call context is passed to the provider.
- Realtime AI-voice bridge — a bridge leg for LLM-driven realtime voice agents, co-existing with the CC addon so an AI agent can hand off to a human queue in the same platform.
- Network conferences — create a conference room programmatically and have participants join via REFER; an empty-room watchdog reaps abandoned rooms.
- Busy-wait (camp-on) — a caller dialing a busy extension can wait on the line and be connected the moment it frees up, instead of bouncing to voicemail.
Smaller but Welcome
- Built-in scanner User-Agent blacklist in the ACL layer (Sipvicious and friends get rejected at the door).
- PBX-wide
queue_hold_musicandvoicemail_greetingdefaults under[proxy], overridable per queue or app. media.playaccepts aside_onlyparameter to play audio to one leg only — hold prompts that the other party can’t hear.
Upgrading
0.5 is a drop-in upgrade for 0.4 deployments: migrations run on boot, and the config format is backward compatible. If you run a cluster, roll nodes one at a time — the session registry tolerates mixed versions during the window.
As always, the docs cover setup and operations, and the troubleshooting guide maps symptoms to the new diagnostics. Questions? Talk to us.