PearlPBX2
← All posts

PearlPBX2 2.7.3: AGPL-3.0, live Asterisk upgrades, TLS for WebRTC

Version 2.7.3 is a big one: a new license, a safe way to upgrade Asterisk itself without reinstalling, automatic TLS for WebRTC, and a substantial expansion of the REST API.

License: moving to GNU AGPL-3.0

PearlPBX2 no longer ships under the PolyForm Shield License 1.0.0 — it’s now the GNU Affero General Public License v3.0-or-later, an OSI-recognized open license. The restriction on competing use is gone; instead, network-use copyleft applies: a modified version deployed as a network service must be disclosed to that service’s users. For the full breakdown, see the dedicated post on the license change.

Upgrading Asterisk without reinstalling: update-asterisk.sh

Before this release, bumping asterisk_version in ansible/group_vars/all.yml did nothing on an already-installed host — the build block in the asterisk role only ran when /usr/sbin/asterisk was absent. The new update-asterisk.sh (role asterisk_update) closes that gap: it backs up /etc/asterisk, the binaries, the modules, and /var/lib/asterisk into a timestamped directory with a ledger in state.json; compiles the new version while the current Asterisk keeps serving calls; gracefully drains active calls (core stop gracefully, configurable timeout, --no-wait for an immediate stop); runs only make install, leaving configuration, sounds, logs, spool, and recordings untouched; and restarts Asterisk and the AMI-connected services, verifying the version after startup. update-asterisk.sh --rollback restores the previous binaries from the backup, and -l/--list shows the upgrade history.

Automatic TLS certificates for WebRTC (wss)

The nginx role now provisions a working HTTPS/wss:// certificate on install by itself, with no manual steps, in three tiers: if a domain is given (--domain), Let’s Encrypt via HTTP-01, a 90-day certificate with standard renewal; if there’s no domain but a public IPv4 address is detected, Let’s Encrypt’s short-lived IP-address certificate (6 days, renewed every 4 hours via a systemd timer); if neither is reachable, a self-signed certificate with a proper subjectAltName (previously CN-only, which modern browsers reject). install.sh and quickstart-install.sh gained --domain/--email flags.

REST API now covers nearly the whole admin

This release adds CRUD for resources that used to be editable only in the Django admin: dialplan contexts, extensions, and macros (/api/v1/dialplan-*), phone devices with a provisioning endpoint (/api/v1/phone-devices/<id>/provision/), queues and queue members, routing tables, trunk groups, SIP transports, SIP peers, and SIP users, plus a wrapper around Apply Changes (GET /api/v1/config/preview/, POST /api/v1/config/apply/ with a required mode: "soft"|"hard" field, superuser only). The secret/md5_cred/priv_key_file fields are now hidden in list responses (GET .../ returns null) and only shown when requesting a single object — closing off a credential leak in bulk list dumps.

Demo WebRTC users right after install

seed_quickstart now creates a transport-wss transport and ten webrtcuser1–webrtcuser10 users with random passwords — a fresh install has working browser-calling accounts from the start.

Smaller changes that still matter

  • install.sh/quickstart-install.sh is now fully unattended: the firewall role no longer stops to confirm the detected SSH port (previously, that could hang a run with no TTY, e.g. ansible-pull or CI) — the port is just logged now.
  • WebRTC SIP users used to get a context based on their username, which never actually existed in extensions.ael, so inbound calls from them went nowhere; they now use the user’s routing table, same as regular SIP accounts.
  • Let’s Encrypt HTTP-01 validation used to break on the server’s own HTTP → HTTPS redirect: a request to /.well-known/acme-challenge/ was also caught by the return 301, because it ran before location matching. The redirect is now wrapped in a location / block.
  • Debian installs were missing the cron package, so the daily backups and reports set up by other roles had nothing to run them — it worked on Ubuntu by accident, since cron usually ships preinstalled there.
  • A new python manage.py mail_report sends a daily email listing the previous day’s longest calls with links to the recordings, to MAIL_REPORT_RECIPIENTS.
  • The AEL dialplan validator now checks goto/Goto() targets — previously, goto +0681231231,1; passed web validation but Asterisk rejected it at dialplan compile time.