The signaling engine behind Fonoster

The SIP server
built for the cloud.

A lightweight SIP proxy, location server, and registrar.

sip trace · INVITE from 1001@sip.local
00.004→INVITE sip:+19103434434@sip.local SIP/2.0
00.006·edgeport-01 → dispatcher (gRPC)
00.007·match req => true → connect
00.011·egress domain-01 › number-01 › trunk-01
00.013←100 Trying
00.412←180 Ringing
04.120←200 OK session established
1.7K

GitHub stars

750K+

Docker pulls

80+

releases shipped

2017

building since

Proven in production

The engine behind Fonoster.

Every call on Fonoster Cloud is signaled by Routr.

Fonoster builds AI that answers the phone. Every call goes through Routr.

fonoster/routr-one:2.15.4helm · routr-connect
See how Fonoster uses it

Scales your media servers

Sits in front of Asterisk and FreeSWITCH and spreads calls across them. Not a replacement.

  • Carriers and CPaaS platforms
  • Office and home phone systems
  • Intercom and paging networks
  • Asterisk and FreeSWITCH clusters
Architecture

Small services. One SIP server.

Small services over gRPC. Replace or scale any of them.

Endpoints
Softphones · Phones
Media servers
Carriers
Phones · Media servers · Carriers
EdgePort
UDP · TCP · TLS
WS · WSS
UDP · TCP · TLS · WS · WSS
Dispatcher
matchFunc:
req => true
matchFunc: req => true
Middlewares
RTPRelay · Auth
Metrics · CDRs
RTPRelay · Auth · Metrics
Processor
Connect, or
one you write
Connect, or one you write
Cooperating services Location Service API Server Registry & Requester
Routr Connect

Your SIP network, as resources.

The built-in Processor for SIP Connect 1.1. Describe your network as resources; Routr does the routing.

Learn more about Connect
number.yaml
apiVersion: v2beta1kind: Numberref: number-01metadata:  name: "(910) 343-4434"  geoInfo:    city: Durham, NC    country: USAspec:  trunkRef: trunk-01  location:    telUrl: tel:+19103434434    aorLink: sip:conference@sip.local    sessionAffinityHeader: X-Room-Id    # calls to this number land on one media server
apiVersion: v2beta1kind: Numberref: number-01metadata:  name: "(910) 343-4434"spec:  trunkRef: trunk-01  location:    telUrl: tel:+19103434434    aorLink: sip:conf@sip.local    sessionAffinityHeader:      X-Room-Id
$ rctl numbers create -f number.yaml
✔ number-01 created
Scale

Stateful at the edge.
Stateless everywhere else.

Only EdgePorts hold state. The Location Service knows which EdgePort each endpoint is on, so a call can land on any of them and still arrive.

00.0001001 → edgeport-01INVITE sip:1002@sip.local
00.002edgeport-01 → dispatcherSIP becomes protobuf; the EdgePort keeps the transaction
00.003dispatcher → connectstateless: match req => true, forward
00.005connectlocation lookup on redis: 1002 is registered on edgeport-02
00.006connectadds Route: edgeport-02 and X-EdgePort-Ref: edgeport-01
00.008edgeport-01 → edgeport-02hands the INVITE to the EdgePort that holds 1002
00.010edgeport-02 → 1002delivered on the existing connection

Across EdgePorts

Any EdgePort takes any call and hands it to the one that holds the target.

Across media servers

A Peer groups Asterisk or FreeSWITCH behind one address: round-robin, least-sessions, session affinity.

Across services

Stateless replicas behind a Kubernetes service. Location shared on Redis.

Resilience

No single point of failure.

Every service is its own pod. Lose an EdgePort, the others keep taking calls. Lose a Processor, the Dispatcher routes around it.

  • EdgePorts: stateful, scaled out, any one can take a call
  • Dispatcher, Processors, Middlewares: stateless replicas
  • Location Service: shared table on Redis
  • API Server: Postgres, backed up like any database
routr · us-east1healthy
1,240active calls
0new calls refused
3 / 3edgeports up
—pod restart
edgeportnew calls land on 01 and 03
dispatcherstateless
connectstateless
locationredis · shared table
apiserverpostgres · primary + standby
10:42:03edgeport-02OOMKilled · pod terminated
10:42:03locationedgeport-02 contacts expire · clients re-register on 01 and 03
10:42:04edgeport-01new calls landing · nothing refused
10:42:05edgeport-02new pod Running · back in rotation
Programmable

Extend it in any language.

Processors and Middlewares are gRPC services. Write one in Node, Go, or Java and swap it in.

Build a Processor
processor.ts
import Processor, { Response } from "@routr/processor" const processor = new Processor({ bindAddr: "0.0.0.0:51904", name: "echo" }) processor.listen((req, res) => {  // every INVITE, REGISTER, and BYE lands here  logger.verbose(req.message.method)  res.sendOk()})
import Processor  from "@routr/processor" new Processor({ bindAddr: ":51904" })  .listen((req, res) => {    // INVITE, REGISTER, BYE…    logger.verbose(req.method)    res.sendOk()  })
$ npm run start:echo
echo listening on 0.0.0.0:51904
Community

Built in the open.

MIT licensed, built on GitHub. Questions and ideas go to Discussions and Discord.

Routr's architecture and design is fantastic. A breath of fresh air. Being Docker and Kubernetes ready is a huge win over a more traditional SIP server setup.

Phil JonesVP of Web Architecture, VQ Communications

I came across Routr, which seems to be the one and only cloud-first Kubernetes-ready SIP server on the planet!

Jessie WadmanCloud Architect, Camanio AB

I think this project has a great promise to become a transformative technology.

jbwill36GitHub Discussions

Your SIP network,
up in one command.