Deploying an Asterisk PBX by hand means compiling from source, a dozen config files, secrets you have to generate
somewhere, and a firewall that is easy to configure in a way that locks you out over SSH. PearlPBX2 covers that whole
path with one Ansible playbook and three scripts: install.sh, update.sh and rollback.sh.
The fastest start: one command
On a clean Debian or Ubuntu server, one command run as root is enough:
curl -fsSL https://pearlpbx2.com/quickstart-install.sh | sudo bash
The script clones the repository, runs the Ansible installer without asking any questions, and finishes by creating an admin user with a generated password.
If you only want to look at the product, there is a Docker variant. Docker must already be installed:
curl -fsSL https://pearlpbx2.com/quickstart-docker.sh | bash
It also clones the repository, generates a .env, brings up the stack with Docker Compose and creates an admin user
with a generated password. How the two paths differ in practice is covered in
Docker install vs. install.sh on a clean OS. The rest of this article is about what
happens inside the first one.
One playbook, nine roles
install.sh runs a playbook made of nine Ansible roles: system, postgres, redis, asterisk, pearlpbx2,
services, nginx, tftp, firewall. Each role owns one part of the stack, so an install is repeatable and reads
as a sequence of understandable steps rather than one long script.
A tenth role, asterisk_update, is not part of installation. Only update-asterisk.sh uses it, more on that below.
What install.sh does
install.sh compiles Asterisk 22 from source (the version is pinned to 22.11.0, not “latest”), generates all the
secrets it needs, sets up cron jobs and applies the nftables firewall rules. Compiling takes 15–30 minutes depending
on the CPU, and the script warns you about that up front.
The cron jobs the installer sets up on its own:
- a database backup every day at 01:30;
- an Asterisk configuration backup every day at 02:30;
- Asterisk log rotation;
- conversion of call recordings to mp3 every 15 minutes and a daily offload at 03:00;
- system monitoring every 15 minutes;
- a daily email report of the longest calls at 06:00, if recipients are set in the configuration.
The --domain <fqdn> and --email <address> flags are for the Let’s Encrypt certificate, covered below.
No pauses, no questions
The installer is fully unattended. Before applying the nftables rules it detects the SSH port with sshd -T. That
returns the value sshd will actually listen on, taking every file in sshd_config.d into account, and that is the
port it opens. The detected port goes into the log and the install carries on without asking for confirmation.
This matters when there is no terminal: ansible-pull, CI or any script no longer hangs on an interactive prompt.
The only thing left after installation is creating an admin user with ./manage.sh createsuperuser. The quickstart
script does that for you.
HTTPS and wss:// without manual setup
WebRTC needs a valid TLS certificate. The nginx role obtains one automatically, in three tiers, depending on what the server has:
- If a domain is given (
--domain), a Let’s Encrypt certificate through HTTP-01. - If there is no domain but a public IPv4 address is detected, Let’s Encrypt’s short-lived IP-address certificate.
- Otherwise, a self-signed certificate as a fallback.
For the first two tiers, automatic renewal is handled by the pearlpbx2-certbot-renew timer. There is no manual TLS
step.
update.sh
Updating PearlPBX2 takes two steps. First you update the repository clone:
git pull
sudo ./update.sh
update.sh does not download anything itself. It deploys whichever commit is currently checked out in the clone: it
syncs the code into the install directory, updates Python dependencies, applies migrations, collects static files and
restarts PearlPBX2 and the auxiliary services. That keeps updates reproducible: you know exactly which commit goes
live, because you picked it.
Before migrating, the playbook records the state of applied migrations and adds an entry to the deploy ledger, which
rollback.sh uses later. update.sh only updates the application. It leaves nginx, the firewall and the seed data
alone, so it is safe to run on a live system.
update-asterisk.sh: upgrading Asterisk in place
You can change the Asterisk version separately from PearlPBX2 itself. update-asterisk.sh upgrades an already
installed Asterisk on the same server, with no reinstall. By default the target version comes from
group_vars/all.yml, and you can pass another one with --version X.Y.Z.
The steps are ordered so that anything that can fail happens while the old Asterisk is still taking calls:
- First it backs up
/etc/asterisk, the binaries, modules and headers, and/var/lib/asterisk. - The new version is compiled while Asterisk keeps serving calls.
- Then Asterisk is stopped gracefully: the script waits for active calls to finish (up to 15 minutes by default,
adjustable with
--timeout;--no-waitstops it immediately). - Only the binaries and modules are installed. Configs, sounds, logs and spool are left untouched.
- Asterisk and the services connected through AMI are restarted.
This script has its own rollback too: update-asterisk.sh --rollback restores the previous version from the backup,
and --list shows the upgrade history. --restore-configs and --restore-sounds additionally restore the
configuration and the sounds.
rollback.sh: the deploy-state ledger
If an update goes wrong, rollback.sh -n <number of steps> reverts the code, the database migrations and the
services to a previous deploy state. The mechanism keeps a ledger (the deploy-state ledger) for every deployment, so
a rollback is not an attempt to “restore from a backup and hope” but a controlled operation with a known result.
What is useful to know about rollback:
rollback.sh --listshows the deploy history and changes nothing. Before rolling back you can see which commit you will land on.- The script asks you to type
yesto confirm. The-yflag skips the question, for example in automation. - The ledger keeps the last ten deployments, so you can go back at most ten steps.
- Migrations are reverted first, while the files for the newer migrations are still on disk: Django needs them to work out the way back. Only then does the code return to the target commit.
- If the repository clone has uncommitted changes, the rollback stops and tells you why. Otherwise
git checkoutwould silently destroy your work. - After a rollback, ledger entries newer than the target commit are removed, because they are no longer valid return points.
Docker Compose for evaluation and CI
For a quick look at the product without waiting for a full Ansible deployment, there is docker compose up: Django,
Asterisk, PostgreSQL, Redis, FastAGI and the dashboard listener. The callback daemon is added separately with
--profile callback, because it places real outbound calls. A separate docker-compose file for integration tests
runs the tests/integration directory against a real Asterisk 22 container in CI, not against mocks.
Where the automated installer runs
The Ansible path (install.sh and the production quickstart script) targets Debian and Ubuntu, the supported
distributions for automated installation. For evaluation, development or CI on any other system there is Docker
Compose: the same stack, without depending on a particular host distribution.
Summary
PearlPBX2 installs with one command or one nine-role Ansible playbook, with no pauses, gets its own HTTPS
certificate, updates in a controlled way through update.sh and rolls back from a state ledger with
rollback.sh -n. Asterisk is upgraded separately through update-asterisk.sh. For evaluation and CI there is Docker
Compose with a real Asterisk 22 in a container.