For bare metal, any VPS provider (Hetzner, Vultr, DigitalOcean, Linode, OVH, on-prem, etc.), or an existing Debian 12 host, jambonz publishes a .deb package that installs the whole single-host stack from apt. This is the simplest deployment path when you’re not on AWS / Azure / GCP / OCI and don’t want to use one of the prebuilt images.
This guide installs the jambonz mini all-in-one deployment (every component on a single host). Multi-host topologies — separate SBC, feature-server, web, and monitoring tiers — currently still require the cloud-image guides (AWS, Azure, GCP, OCI). Multi-host Debian packages are in development.
sudo accessHow you open these depends on your provider — security groups on a cloud VPS, an OS-level firewall (ufw, nftables) on bare metal, or a hardware firewall in front. Consult your provider’s documentation.
Four apt sources are required: the jambonz repository itself, plus three upstream sources that ship dependencies Debian doesn’t include directly.
Before installing, you need to decide on the DNS name you’ll use for the jambonz portal (for example portal.example.com). This is required: jambonz uses the portal domain for nginx routing, certbot TLS, and your software license is keyed to it.
Pick a hostname you control DNS for. The installer will configure nginx for that name and these related subdomains:
portal.example.com — the admin webappapi.portal.example.com — the REST APIgrafana.portal.example.com — metrics dashboardsYou should create A records for all of the above pointing at your host’s public IP. You can do this before or after the install, but it must be done before you obtain TLS certificates with certbot. See Post-Install Steps for the DNS record list.
You have three options:
Inline on the install command (recommended / simplest):
The -E flag preserves the environment variable through sudo.
Pre-supply via /etc/jambonz/install.conf (good for terraform / ansible / cloud-init):
Then run the normal install — the postinst will read install.conf automatically.
Configure it after installing, if you forgot:
This idempotent helper:
portal.example.com, api.portal.example.com, grafana.portal.example.com) and reloads nginxJAMBONES_PORTAL_DOMAIN to /var/lib/jambonz/host.envsystem_information row in MySQL (required for drachtio’s license validation)Safe to re-run any number of times. Same logic the postinst runs with the env var set.
If you install without specifying a domain, the install completes but the postinst prints a NO PORTAL DOMAIN configured warning — license validation will not succeed until you run jambonz-configure-domain.
rtpengine includes a kernel module that DKMS will compile on the host, so the matching Linux headers must be installed first. Then run the install with your portal domain:
apt resolves the full dependency tree (jambonz-common, jambonz-monitoring-agent, jambonz-rtpengine, jambonz-rtpengine-dkms, drachtio, jambonz-freeswitch, telegraf, nodejs, MariaDB, Redis, nginx, Grafana).
On some cloud instances, linux-headers-cloud-amd64 will install headers for a newer kernel than the one currently running (because the running kernel image is older than what’s in the repos). DKMS can build the rtpengine module only for kernels whose headers it has, so it builds against the newer one. The postinst detects this and prints a REBOOT RECOMMENDED message at the end of the install. Reboot to use the newer kernel, after which rtpengine will use kernel-mode forwarding. Until you reboot, rtpengine works in userspace-only mode (functional but less efficient).
While apt was running, the jambonz-common and jambonz-mini post-install scripts:
jambonz system user with passwordless sudo and copied the cloud-init user’s SSH authorized_keys so you can ssh jambonz@<host> with the same keypair/var/lib/jambonz/secrets.env (mode 600 — JWT signing key, MySQL password, Homer/heplify credentials, recording auth)/var/lib/jambonz/host.envjambones database, ran the schema and seed, and applied any pending migrationsheplify-server + pcap-server) with a generated heplify role and the homer_data / homer_config databasesupload_recordings C++ daemon with the matching ENCRYPTION_SECRET so it can decrypt bucket credentialsjambonz-apps.target systemd target and its child services, plus drachtio, FreeSWITCH, rtpengine, heplify-server, pcap-server, InfluxDB, and GrafanaOn a clean install this completes in a minute or two.
All jambonz-* units should be active (running). The webapp should return HTTP/1.1 200 OK. The ECONNREFUSED count should be 0.
Before logging in for the first time, complete these steps:
api. and grafana.) and using certbot to obtain a TLS certificate for the portal.support@jambonz.org.Browse to your portal’s DNS name (e.g. https://my-domain.example.com) and log in with:
adminadminYou’ll be required to set a new password on first login.
jambonz userThe install creates a jambonz system user with passwordless sudo and copies the cloud-init user’s SSH keys into /home/jambonz/.ssh/authorized_keys. Day-2 operations are intended to be performed as this user — not as root, admin, ubuntu, or ec2-user.
You should see this user mentioned in the final lines of the install output. Once logged in, the jambonz CLI is on $PATH and sudo works without a password prompt.
jambonz CLIThe jambonz-common package ships a jambonz command at /usr/bin/jambonz for day-2 operations. Run it as the jambonz user:
Common usage:
App-name resolution is forgiving: short forms like feature-server, api-server, inbound, outbound are expanded to their jambonz-* unit names. For drachtio, FreeSWITCH, and rtpengine — which aren’t part of the jambonz Node-app set — pass the full unit name.
Environment variables for the Node apps come from four files, layered in order — later files override earlier ones on conflict:
/etc/jambonz/jambonz.env — shared, customer-editable config/etc/jambonz/<app>.env — per-app overrides (e.g. feature-server.env)/var/lib/jambonz/host.env — per-host runtime (auto-generated; also the right place for terraform/ansible to write)/var/lib/jambonz/secrets.env — generated cluster secrets, mode 600These files are tracked by dpkg. Your edits survive upgrades; if a release ships a new default you’ll be prompted (see Upgrading below).
These get rewritten on every upgrade. Edits will be lost. If you need to change a value, edit the source env file instead.
After editing any of the conffile-protected files above, apply with:
If you need extra Environment= or ExecStartPre= directives on a system unit (for example to enable SIP over TLS on drachtio), don’t edit the shipped service file or the jambonz*.conf drop-ins — both get reset on upgrade. Create your own drop-in whose name does not start with jambonz:
jambonz upgrades will never touch a drop-in not named jambonz*.conf. Your local.conf survives every upgrade.
The simplest path:
This refreshes apt indexes, lists which jambonz packages have new versions, asks for confirmation, runs the upgrade, and finishes with a jambonz health so you immediately see whether anything came back failing. If there’s nothing new, it’s a no-op with a clean message.
The equivalent raw apt commands:
Schema migrations run automatically — the jambonz-mini postinst detects the existing schema_version table, skips the seed, and applies only pending migrations. Existing data is preserved.
If an upgrade ships a new default for a config file under /etc/ and you’ve edited that file, dpkg will prompt you:
The default (N — keep your edits) is almost always the right answer for env files. Press D first to see what changed — sometimes the new version adds variables worth adopting, in which case keep your file with N and add the new variables manually.
For the two third-party conffiles /etc/heplify-server.toml and /etc/default/pcap-server, always pick N. The jambonz-mini postinst sed-edits credential lines into those files. Picking Y would lose the generated credentials and break the services. If you accidentally pick Y, restore with sudo dpkg-reconfigure jambonz-mini.
For production boxes:
If an upgrade breaks something and you need to drop back to a previous version:
Schema migrations do not auto-roll-back — once new tables or columns exist, they persist. That’s safe because the migration policy guarantees backward compatibility (no DROP TABLE, no new NOT NULL columns without defaults), so old code reading a newer schema works correctly. You don’t need to restore the database to roll back code.
If you ever do need the schema rolled back, restore MySQL from your pre-upgrade backup before downgrading the deb.
apt-get purge removes configuration files but does not drop the jambones database — your data is preserved. For a true reset, drop it manually:
Use jambonz crash <app> to see a bracketed journalctl window around the most recent restart of the failing app. This is usually faster than scrolling through journalctl -xe.
Confirm /var/lib/jambonz/secrets.env has the expected password:
If the password and the MySQL user are out of sync, re-run sudo dpkg-reconfigure jambonz-mini to regenerate.
Check the feature-server’s recording websocket URL:
JAMBONZ_RECORD_WS_BASE_URL should be ws://127.0.0.1:3017. Then confirm the recording service is up with jambonz status — upload_recordings should be active.
The drachtio HEP-encapsulation drop-in may have been clobbered. Confirm it still exists:
It should include --homer 127.0.0.1:9060 --homer-id 10. If missing or different, re-run sudo dpkg-reconfigure jambonz-mini.
sudo certbot renew. Certbot installs a systemd timer that handles renewals automatically — only run this manually if you see “Your certificate has expired” in the portal.
Run jambonz health first. It narrows the problem to a specific layer (database, Redis, telegraf, drachtio, FreeSWITCH, or a Node app) much faster than reading logs unaided.
Multi-host topologies (separate SBC, feature-server, web, and monitoring tiers) are not yet supported via apt. Only the single-host jambonz-mini package is currently published. If you need a clustered deployment, use the AWS, Azure, GCP, OCI, or Kubernetes guides instead.