Self-Hosted SIP B2BUA

Aria Push Gateway

A lightweight Rust server that bridges your SIP infrastructure with mobile push notifications. It maintains SIP registrations on behalf of mobile devices, intercepts incoming calls, and delivers instant VoIP push via APNs and FCM β€” so your users never miss a call.

The Problem and the Solution

Mobile operating systems aggressively kill background processes to preserve battery life. A traditional SIP softphone cannot keep a persistent connection to the PBX.

The Problem
  • iOS and Android kill background SIP connections within seconds to minutes
  • Without an active REGISTER, the PBX has nowhere to route incoming calls
  • Incoming calls are silently dropped β€” users never know they were called
The Solution
  • The gateway maintains SIP registrations on behalf of every mobile device, 24/7
  • When a call arrives, the gateway intercepts the INVITE and sends a VoIP push notification (APNs for iOS, FCM for Android)
  • The mobile app wakes instantly, retrieves call details via REST API, and accepts or rejects
  • For outgoing calls, the app sends SDP to the gateway, which originates a SIP INVITE to the PBX
  • RTP media always flows directly between the PBX and the mobile app β€” the gateway is never in the media path

Architecture

The gateway is composed of several internal managers that handle SIP, push delivery, REST API, and call coordination.

Incoming Call Path
PBX
SIP Server
SIP Proxy Manager
REGISTER + INVITE handling
Push Notification Manager
APNs + FCM delivery
APNs / FCM
Apple + Google
Mobile App
Wakes + rings
Outgoing Call Path
Mobile App
SDP + destination
REST API
Axum HTTP server
Call Handoff Manager
SIP INVITE origination
PBX
SIP Server
SQLite Device Registry
Push tokens, SIP creds, state
Connected to all managers. Stores device push tokens, SIP credentials, registration state, and active call sessions. Embedded SQLite β€” no external database required.
RTP media flows directly between PBX and mobile app β€” the gateway is signaling-only
Incoming Calls

Incoming Call Flow

Step-by-step: from SIP INVITE to ringing phone.

  1. 1

    Gateway maintains REGISTER

    The gateway sends periodic SIP REGISTER requests to the PBX on behalf of each mobile device, keeping the registration alive.

  2. 2

    PBX sends INVITE

    When someone calls the user, the PBX routes the SIP INVITE to the gateway (the registered contact).

  3. 3

    Gateway sends 100 Trying

    The gateway immediately responds with 100 Trying to prevent the PBX from timing out.

  4. 4

    Device lookup + VoIP push

    The gateway looks up the device in SQLite and sends a VoIP push notification β€” APNs PushKit for iOS, high-priority FCM data message for Android.

  5. 5

    App wakes, fetches SDP offer

    The mobile app wakes from push, calls GET /v1/calls/{token} to retrieve the SDP offer and caller info (From header, display name).

  6. 6

    App sends SDP answer

    The user accepts. The app calls POST /v1/calls/{token}/accept with its SDP answer (codec choices, RTP port, IP address).

  7. 7

    Gateway sends 200 OK

    The gateway sends 200 OK to the PBX, embedding the mobile app's SDP answer in the response body.

  8. 8

    RTP flows directly

    The PBX sends ACK. RTP media flows directly between the PBX and the mobile app. The gateway is out of the media path.

Outgoing Calls

Outgoing Call Flow

Step-by-step: from dial button to connected call.

  1. 1

    App generates SDP offer

    The mobile app creates an SDP offer with its preferred codecs, RTP port, and public IP address.

  2. 2

    App calls POST /v1/calls

    The app sends the destination URI, SDP offer, and SIP credentials to the gateway's REST API.

  3. 3

    Gateway sends SIP INVITE

    The gateway opens a UDP socket and sends a SIP INVITE to the PBX with the app's SDP offer.

  4. 4

    Auth challenge handling

    The PBX responds with 401/407 requiring digest auth. The gateway sends ACK, then re-sends the INVITE with proper Authorization credentials.

  5. 5

    PBX sends 200 OK

    The PBX accepts the call and responds with 200 OK containing its SDP answer (codec, RTP port, IP).

  6. 6

    Gateway sends ACK, returns SDP

    The gateway sends ACK to the PBX, then returns the SDP answer and a call_token to the mobile app via the REST response.

  7. 7

    RTP flows directly

    RTP media flows directly between the PBX and the mobile app. The gateway only handled SIP signaling.

API Reference

REST API

All endpoints are served by the Axum HTTP server. Authentication uses JWT bearer tokens (except /health and /v1/auth/token).

Method Endpoint Description
POST /v1/auth/token Create JWT token
POST /v1/devices Register device for push
GET /v1/devices/{id} Get device + SIP registration status
DELETE /v1/devices/{id} Unregister device
POST /v1/calls Initiate outgoing call
GET /v1/calls/{token} Get incoming call offer
POST /v1/calls/{token}/accept Accept incoming call
POST /v1/calls/{token}/reject Reject incoming call
POST /v1/calls/{token}/hangup Hang up active call
GET /health Health check

Technical Specifications

Built for reliability and minimal resource consumption.

Language
Rust
Memory-safe, zero-cost abstractions
HTTP Framework
Axum
Async, built on Tokio runtime
Database
SQLite
Embedded, no external DB required
Authentication
JWT + API Key
HMAC-SHA256 token signing
iOS Push
Apple APNs
VoIP push via .p8 auth key
Android Push
Google FCM
Service account JSON credentials
SIP Library
aria-sip-core
Custom parser + digest auth
SIP Transport
UDP
TCP/TLS support planned
Binary Size
~10 MB
Static release binary
Min CPU
1 vCPU
Handles hundreds of registrations
Min RAM
256 MB
SQLite + async runtime overhead
Min Disk
~10 MB
Binary + SQLite database file
Deployment

Self-Hosting Guide

Deploy the push gateway on your own infrastructure. Full control, no third-party dependencies.

1 Build from Source

# Clone the repository
git clone https://github.com/5060-Solutions/aria-push-gateway.git
cd aria-push-gateway

# Build release binary (requires Rust toolchain)
cargo build --release

# Binary is at target/release/aria-gateway

2 Configuration

All configuration is in a single gateway.toml file.

[server]
host = "0.0.0.0"
port = 8080

[auth]
secret = "your-jwt-secret-here"
api_key = "your-api-key-here"

[database]
path = "/data/gateway.db"

[apns]
key_path = "/data/AuthKey_XXXXXXXXXX.p8"
key_id = "XXXXXXXXXX"
team_id = "XXXXXXXXXX"
topic = "com.example.aria.voip"

[fcm]
service_account_path = "/data/firebase-service-account.json"

[sip]
transport = "udp"
local_port = 5060

3 Docker Deployment

The Dockerfile builds from the parent 5060/ directory because the gateway depends on the aria-sip-core sibling crate.

# Build from the parent directory (contains both repos)
docker build -f push-gateway/Dockerfile -t aria-gateway .

# Run with mounted data directory
docker run -d \
  --name aria-gateway \
  -p 8080:8080 \
  -p 5060:5060/udp \
  -v /path/to/data:/data \
  aria-gateway --config /data/gateway.toml

4 Network Requirements

Outbound UDP
SIP server (PBX) Port 5060 (or your SIP server's port)
SIP REGISTER, INVITE, ACK, BYE
Outbound HTTPS
Apple APNs api.push.apple.com:443
VoIP push notification delivery
Outbound HTTPS
Google FCM fcm.googleapis.com:443
High-priority data message delivery
Inbound TCP
Mobile clients Port 8080 (configurable)
REST API β€” TLS termination via reverse proxy
Inbound UDP
SIP server (PBX) Port 5060 (configurable)
Incoming SIP INVITE from PBX

5 DNS and TLS

Point a subdomain at your gateway server and terminate TLS with a reverse proxy.

# DNS A record
gateway.example.com  A  203.0.113.10

# Caddy reverse proxy (automatic TLS)
gateway.example.com {
    reverse_proxy localhost:8080
}

# Or nginx
server {
    server_name gateway.example.com;
    listen 443 ssl;
    ssl_certificate /etc/letsencrypt/live/gateway.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/gateway.example.com/privkey.pem;

    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

Important: The mobile apps connect to the REST API over HTTPS. TLS must be terminated at the reverse proxy β€” the gateway itself serves plain HTTP.

Deploy Your Own Push Gateway

The entire codebase is open source under the MIT license. Clone, build, deploy, and start receiving calls on mobile in minutes.