sidetone

Usage

Running it day to day

Where to look when something is wrong, how to keep it safe, and what to copy elsewhere.

Watching it

  • The dashboard: calls in progress, phones online, queues, voicemail, trunks. Calls lists what is in progress, and ends one if need be (GET /v1/calls, DELETE /v1/calls/{id}).
  • Call records (GET /v1/cdrs, with from, to, caller, callee and disposition as filters, and GET /v1/cdrs.csv for a spreadsheet). cdr_retention_days says how long they are kept. A record carries who answered, which queue, how long the wait was, and how many packets went each way, which is how you tell silence from a missing route.
  • Metrics at GET /metrics, for Prometheus: registrations, calls, media sessions, SIP requests, bans, emergency calls. GET /healthz for liveness. Neither needs a token.
  • The wallboard, described under queues.

When a call fails

Debug in the console (GET /v1/debug/log and GET /v1/debug/sip, both taking contains= and after=) keeps the recent log, debug lines included whatever the log level says, and the recent SIP messages as they were on the wire. It is in memory only and for administrators only; digest responses, SRTP keys and typed digits are taken out. Calls and problems are kept apart from keep-alives, and one address can fill only so much, so a scanner cannot push out what you came to see. Look here first.

SymptomLook at
A phone will not registerDebug → SIP messages with registrations ticked; GET /v1/bans; is the realm what the phone expects?
A call from the provider is refused with 404Debug says "no inbound number matches" and what the number was sent as: add exactly that under inbound numbers.
A call from the provider is challenged with 401It came from an address that is not the trunk's: see the INVITE's source under Debug, and add it to source_cidrs or fix the host.
One-way or no audioThe address in the SDP: public address learned in the log, or -external-ip; the audio range open in the firewall and, behind NAT, forwarded.
Calls refused with 403 "Number Not Allowed"The user's deny_prefixes or allow_prefixes.
Calls refused with 404No route matches, or the number has characters other than digits, +, * and #.
Calls refused with 488Codec (only G.711 is carried, G.722 with hd_audio), or the SRTP policy: the reason phrase says which.
A trunk shows last_errorCredentials, or the provider wants from_user; see what a provider refuses.
Calls drop after a fixed timemax_call_duration; media_timeout if there was silence.
The message lamp does not lightSome phones accept message-waiting only inside a subscription of their own; see the task list in the repository.

Encryption and certificates

Add tls://0.0.0.0:5061 (and wss://… for WebSocket clients that want a port of their own) to -sip-listen. The first start creates a self-signed certificate, which phones accept only with verification off. Install a real one at any time, live, with calls undisturbed:

$ jq -n --rawfile c fullchain.pem --rawfile k privkey.pem '{certificate:$c, private_key:$k}' | api -X PUT -d @- localhost:8080/v1/tls/certificate

Or let the server get one. With a public DNS name that points at it and port 80 reachable from the internet, start it with -acme-domain pbx.example.com (and -acme-email if you like): it obtains a certificate from Let's Encrypt, installs it, and renews it a month before it runs out, without a restart. Until the first one arrives the self-signed certificate is served; if the authority cannot be reached the installed certificate simply stays, and the log says why. -acme-listen moves the challenge listener (to bind port 80 as a non-root user, setcap cap_net_bind_service=+ep sidetone, or forward the port), and -acme-directory names another authority.

The same certificate serves the console over HTTPS on -api-tls-addr, which the browser phone needs. Set "srtp": true on a user or trunk to make encrypted audio mandatory for them; their phones must then register over tls or wss with SRTP switched on. The other party of a call may still be unencrypted: encryption is per leg, because the server is in the middle of every call.

Backups

The database, which is the configuration, the call records, voicemail and the audit log, is backed up into backups/ under the data directory every backup_every_hours (24), keeping the newest backup_keep (7). POST /v1/backups, or Back up now, takes one now; those made by hand are never removed. Backups are consistent copies taken while the server runs.

They are on the same disk as the original: copy them elsewhere with rsync, restic or a cron job. Not included are recordings/, which is large, so copy that folder too, and acme/, which is re-obtained if lost. A backup contains password hashes and, in between a phone's creation and its first fetch, that phone's password: treat backups as secrets.

To restore, stop the server, put a backup in place of sidetone.db, and start it. To move only the configuration between servers, use GET and PUT /v1/config instead.

Keeping it safe

  • Keep the API on localhost or behind TLS; the token must never travel in the clear on a network.
  • Open only the SIP ports and the audio range to the world. Phones and providers need nothing else.
  • Set the toll-fraud limits to what you actually need before the first weekend.
  • Switch test mode off when the phones are real, and not before.
  • Watch the audit log now and then: every change and every refused attempt is in it, with who and from where.