VoIP Infrastructure Asterisk 20 · WebRTC · PJSIP VitalPBX · Debian 12

VoIP infrastructure: deploying corporate telephony with WebRTC

An international company, remote employees, calls through the browser. A critical DTLS/ECDSA incompatibility fixed through a non-standard transport configuration — properly, without workarounds.

DTLS
root cause — a handshake issue at the transport layer
RSA fix
self-signed instead of ECDSA, full compatibility
2 ext
SIP extensions, WebRTC through the browser
live
two-way audio, system in production
Context
An international company: a corporate PBX with WebRTC calls through the browser, external DID numbers via voip.ms, support for remote employees. Stack: VitalPBX + Asterisk 20 on Debian 12, VitXi WebRTC client.
VitXi WebRTC voip.ms DID Remote workers
Problem
Asterisk 20 + ECDSA = no two-way audio. The connection establishes, the DTLS handshake completes, but the RTP stream drops. The standard documentation offered no solution.
ECDSA incompatible No audio RTP NAT traversal fail
Solution architecture
Final stack: Browser → nginx → Asterisk → voip.ms
Each layer handles a separate concern: TLS termination, DTLS media, NAT, SIP trunk
🌐
Browser
VitXi WebRTC
WSS
HTTPS/WSS
nginx
reverse proxy
SSL termination
Let's Encrypt
WS + DTLS
Asterisk 20
PJSIP · WebRTC
RSA self-signed
RSA cert
SIP/TLS
📡
voip.ms
SIP trunk
sub-account
SIP trunk
PSTN
📞
DID
external number
+1 (904) xxx
PSTN
Fix 1 — DTLS Certificate
ECDSA → RSA self-signed
Asterisk 20 mishandled ECDSA during the DTLS handshake with VitXi — switching to RSA solved the problem completely
root cause
DTLS / ECDSA
pjsip — ECDSA (broken)
;; /etc/asterisk/pjsip__20-transport.conf [transport-wss] type=transport protocol=wss cert_file=/etc/letsencrypt/live/ domain/fullchain.pem priv_key_file=/etc/letsencrypt/ live/domain/privkey.pem ;; ❌ ECDSA — Asterisk 20 bug ;; no two-way audio method=tlsv1_2
pjsip — RSA self-signed (✓)
;; /etc/asterisk/pjsip__20-transport.conf [transport-wss] type=transport protocol=wss cert_file=/etc/asterisk/ dtls-cert.pem priv_key_file=/etc/asterisk/ dtls-key.pem ;; ✓ RSA 2048 self-signed ;; fully compatible with Asterisk 20 method=tlsv1_2
Generating an RSA self-signed cert for DTLS
# RSA 2048, valid 10 years, for DTLS in Asterisk openssl req -x509 -newkey rsa:2048 \ -keyout /etc/asterisk/dtls-key.pem \ -out /etc/asterisk/dtls-cert.pem \ -days 3650 -nodes \ -subj "/CN=asterisk-dtls" # permissions — only asterisk can read the key chown asterisk:asterisk /etc/asterisk/dtls-*.pem chmod 600 /etc/asterisk/dtls-key.pem
Fix 2 — NAT traversal
The (+) append syntax in pjsip NAT
The standard external_media_address didn't work in a non-standard topology — the append syntax produced correct SDP without STUN
issue
NAT / SDP
pjsip__15-nat.conf (broken)
[global] type=global ;; ❌ overwrites the default values external_media_address=159.198.74.173 external_signaling_address=159.198.74.173 ;; ❌ RTP is sent to the internal IP ;; SDP contains 192.168.x.x → audio fail
pjsip__15-nat.conf — (+) append (✓)
[global](+) ;; (+) = append to the existing section external_media_address=159.198.74.173 external_signaling_address=159.198.74.173 ;; ✓ SDP advertises the public IP ;; RTP reaches the browser without STUN [transport-wss](+) local_net=10.0.0.0/8 local_net=192.168.0.0/16
Fix 3 — nginx reverse proxy
WebSocket upgrade + SSL for VitXi
Properly proxying the WebSocket connection with the right headers for the WebRTC client
config
nginx / WSS
/etc/nginx/sites-enabled/vitalpbx — WebRTC proxy
# WebSocket → Asterisk PJSIP WSS transport location /ws { proxy_pass https://127.0.0.1:8089; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header Host $host; proxy_ssl_verify off; # self-signed DTLS cert } # SSL — Let's Encrypt (ECDSA) for the browser # Asterisk only sees the RSA self-signed cert internally ssl_certificate /etc/letsencrypt/live/domain/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/domain/privkey.pem; ssl_protocols TLSv1.2 TLSv1.3;
Issues resolved: ✓ DTLS/ECDSA fix ✓ NAT append ✓ nginx WSS ✓ two-way RTP
Live ✓
Result
The system went live on schedule. Two-way audio through the browser works reliably. Handover documentation was prepared for the client, covering all the non-standard solutions — the DTLS fix, the NAT configuration, and the nginx proxying scheme.
VitalPBX 4.5
Asterisk 20 · PJSIP
WebRTC · VitXi client
DTLS-SRTP · RSA fix
nginx · reverse proxy
voip.ms · SIP trunk
Debian 12

Have a project? Let's break it down

Tell us what's going on — we'll tell you whether we can help and what it looks like in terms of budget and timeline. No strings attached.