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.
- 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 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 Flow
Step-by-step: from SIP INVITE to ringing phone.
- 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
PBX sends INVITE
When someone calls the user, the PBX routes the SIP INVITE to the gateway (the registered contact).
- 3
Gateway sends 100 Trying
The gateway immediately responds with 100 Trying to prevent the PBX from timing out.
- 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
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
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
Gateway sends 200 OK
The gateway sends 200 OK to the PBX, embedding the mobile app's SDP answer in the response body.
- 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 Call Flow
Step-by-step: from dial button to connected call.
- 1
App generates SDP offer
The mobile app creates an SDP offer with its preferred codecs, RTP port, and public IP address.
- 2
App calls POST /v1/calls
The app sends the destination URI, SDP offer, and SIP credentials to the gateway's REST API.
- 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
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
PBX sends 200 OK
The PBX accepts the call and responds with 200 OK containing its SDP answer (codec, RTP port, IP).
- 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
RTP flows directly
RTP media flows directly between the PBX and the mobile app. The gateway only handled SIP signaling.
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.
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
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.