Skip to main content
Version: 0.9.18

Operate the telephony edge (TelPro)

Use this page to keep the TelPro edge healthy. TelPro is the public telephony entry point: it accepts SIP from carriers and browser voice from Janus, and it forwards calls to the Voice hosts over the private network.

Availability: From 0.9.18, unknown-trunk rejections are logged at warn level and SIP trunks have a maintenance mode; neither needs a flag. Two-edge operation is controlled by TELPRO_HA_ENABLED (default false) on each TelPro host and also needs HCLOUD_TOKEN. Without it, each edge runs alone. To plan a pair, read Run two edges.

Edge components​

All TelPro containers use host networking and run from /opt/services/telpro.

ContainerComponentRole on the edge
voiceai-telproKamailioSIP proxy: trunk identification, routing, drain gate, TLS for SIP
voiceai-rtpengineRTPEngineMedia relay for carrier calls
voiceai-webrtcJanusBrowser voice gateway; sends SIP to Kamailio
voiceai-turncoturnTURN relay for browsers behind restrictive networks
voiceai-otel-collectorTelemetry collectorExports edge telemetry to SigNoz
log-to-spanLog converterTurns structured Kamailio log events into trace spans

Configuration sources​

SourceContents
Container imagesKamailio routing logic, RTPEngine and Janus builds, tied to ECR_TAG
TelPro configuration bundleCompose file, collector settings, TURN start script, refresh reconciler
Parameter and secrets storesPorts, addresses, TURN credentials, edge certificates, Redis connection
RedisTrunk definitions, trunk order, maintenance settings, instance drain flags and heartbeats
Bootstrap filePUBLIC_IP, PRIVATE_IP, floating addresses and the host identity

Trunk and routing changes that you save in the administration interface reach Kamailio through Redis and need no restart. Changes to parameters, secrets or the bundle need a refresh of the edge. The Environment variable reference lists every TelPro variable.

Initialization sets the instance identity from TELPRO_INSTANCE_ID, then KAMAILIO_INSTANCE_ID, then the host name, and passes the same value to Kamailio and the reconciler. Keep it unique per edge.

Restart order​

Compose starts the containers in dependency order:

  1. RTPEngine.
  2. Kamailio, after RTPEngine has started.
  3. coturn.
  4. Janus, after Kamailio is healthy and coturn has started.

A restart of Kamailio or RTPEngine interrupts calls on that edge. For a planned change, use the drain path in Drain an edge instance instead of restarting containers by hand.

Check edge health​

ContainerHealth check
voiceai-rtpengineRTPENGINE_LISTEN_PORT listens and rtpengine-ctl lists sessions
voiceai-telprokamcmd core.uptime answers
voiceai-webrtcThe container's main process is Janus
voiceai-turnTURN_PORT accepts a TCP connection

Run this command on the edge to see the state of each container:

cd /opt/services/telpro
docker compose ps

A healthy container proves only that the process answers locally. To confirm call handling, follow Service health and place a test call.

Read edge logs​

cd /opt/services/telpro
docker compose logs -f telpro

Replace telpro with rtpengine, webrtc, turn or otel-collector for the other components.

  • Kamailio writes structured events when STRUCTURED_LOGGING_ENABLED is true, which initialization sets by default. The log-to-span sidecar turns these events into trace spans in SigNoz.
  • Docker keeps SIP_CAPTURE_TELPRO_LOG_MAX_FILES files of SIP_CAPTURE_TELPRO_LOG_MAX_SIZE each for Kamailio; see TelPro variables for the defaults.
  • The refresh reconciler logs to the systemd journal. Its lines start with [config-refresh] component=telpro-reconciler and include a phase= field.
journalctl -u telpro-config-refresh.service

For log levels, field meanings and searching, see Logs and Telemetry and monitoring.

Recognize unknown-trunk rejections​

When an INVITE arrives from an address that matches no configured trunk, Kamailio answers 403 Forbidden - Unknown Trunk. It logs Rejecting call from unknown trunk with the source address, From header and user agent.

From 0.9.18, the structured trunk_identify_failed event for this case has level warn instead of error. The telemetry collector marks it as an authorization security event. Kamailio treats these as expected rejections of unwanted traffic, so they no longer appear among error-level events.

Identification failures on a configured trunk, such as TLS or authentication problems, stay at error level. Investigate those first. For the full response table, see Routing responses.

Put an inbound trunk into maintenance​

From 0.9.18, you can put an inbound trunk into maintenance so that Kamailio rejects its new calls with a response code you choose; see Maintain an inbound trunk to set it up.

Drain an edge instance​

Each edge runs telpro-config-refresh.timer, which starts the reconciler every 30 seconds. The reconciler picks up refresh commands that the platform queues for this instance from Service Refresh.

The reconciler stops new calls on the edge, waits for existing calls to end, restarts the edge with fresh configuration and reports the result.

While the drain flag is set, Kamailio answers new INVITEs with 503 Service Unavailable and logs Rejecting new INVITE during TelPro maintenance drain. Existing calls continue. The drain-restart strategy needs at least two ready edges, so that new calls have somewhere to go.

To follow a drain, read the reconciler journal. The phases are acknowledged, draining, waiting, fetching_env, restarting, verifying and completed, or failed with a detail= reason.

Run two edges​

Two-edge operation runs Kamailio, RTPEngine, Janus and coturn on both TelPro hosts and moves two floating addresses between them.

  • SIP floating address: Only the host that owns it accepts carrier signaling, browser signaling and carrier registrations. Point the SIP, SIP-over-TLS and browser WebSocket DNS names at it.
  • Media floating address: RTPEngine, Janus and coturn advertise it in SDP and ICE.
  • Host-local values: Each host needs its own TELPRO_INSTANCE_ID and TELPRO_PROVIDER_SERVER_ID, the peer's identities, the shared floating address IDs and the shared TELPRO_INITIAL_ACTIVE_INSTANCE_ID. TelPro variables describes each one.

Both hosts configure both addresses locally so that services can bind before ownership moves. The cloud provider's assignment decides which host receives the traffic.

EventWhat happens
Kamailio maintenanceSIP ownership moves to the peer; existing media stays on the old host.
RTPEngine maintenanceNew sessions move away; the engine restarts when its sessions reach zero.
Full-host maintenanceBoth addresses move after dialogs and media sessions drain.
Active peer stops reportingA healthy standby takes both addresses. Calls whose media engine failed cannot be recovered.
Edge certificate reload failsSIP moves to the peer and Kamailio restarts.

A Redis lease serializes maintenance, so only one edge changes at a time. Carrier registrations stay off until Redis holds an elected owner.

After a certificate reload, the edge opens a new TLS connection to TELPRO_TLS_VERIFY_ENDPOINT and checks the served fingerprint. The default endpoint is DOMAIN_TELPRO on SIPS_PORT. For certificate preparation, see Verify platform TLS.

Common failures​

SymptomLikely causeAction
Initialization stops with PUBLIC_IP not foundThe bootstrap file lacks the public addressAdd PUBLIC_IP to /opt/deployment/.env and rerun initialization.
All new calls get 503 from one edgeThe drain flag is still set after a refreshRead the reconciler journal for a failed phase, then rerun the refresh or recover the edge.
Many 403 Forbidden - Unknown Trunk responsesScanners, or a carrier sending from an address you have not configuredCompare the source address with the trunk's configured addresses.
Calls connect without audioMedia ports blocked, or a wrong advertised addressCheck the RTP port ranges in Network ports and NAT and media addresses.
Browser voice connects signaling but no mediaTURN or Janus media ports blockedCheck TURN_PORT, the TURN relay range and the Janus RTP range.
voiceai-webrtc never startsKamailio is not healthy, so Janus waitsFix Kamailio first; check docker compose logs telpro.
Reconciler reports peer_not_ready or peer_identity_not_configuredThe two-edge peer is missing or not readyCheck the peer's health and its host-local identity values.

For caller-facing SIP responses and call traces, use SIP diagnostics.

Verify the edge​

  1. Run docker compose ps in /opt/services/telpro and confirm that all containers are running and healthy.
  2. Confirm that the reconciler journal shows no failed phase since the last change.
  3. Place an inbound test call through each configured trunk and confirm that it reaches the expected flow.
  4. If browser voice is enabled, start a browser call and confirm audio in both directions.