Docs navigation

Architecture overview

An Exovo deployment is a set of cooperating containers managed by Docker Compose. Understanding what each one does makes logs easier to read, firewall rules easier to reason about, and troubleshooting much faster.

The container stack

                     Internet
                        │
        80/443          │           5060/5061/5080 (SIP)
      ┌─────────────────┤           5090 (tunnel)  5091 (VPN)
      ▼                 │           16384–16484 (RTP)
 ┌─────────┐            │                 │
 │ traefik │            │                 ▼
 │ (proxy) │            │      ┌──────────────────────────┐
 └────┬────┘            │      │  core (FreeSWITCH)       │
      │ HTTP            │      │  + tunnel   (sidecar)    │
      ▼                 │      │  + phoneproxy (sidecar)  │
 ┌─────────┐   ESL/API  │      └──────────┬───────────────┘
 │   web   │◄───────────┼─────────────────┘
 │ console │            │      3478/5349 + 49152–49252
 └────┬────┘            │                 │
      │ SQL             │                 ▼
      ▼                 │           ┌─────────┐
 ┌─────────┐            └──────────►│  turn   │ (media relay,
 │   db    │                        └─────────┘  browser calls)
 └─────────┘
Service Image Role
traefik Traefik 3 Reverse proxy: TLS termination, automatic certificates, HTTP→HTTPS
web Exovo web The web console and web client, provisioning, APIs, background workers
core Exovo core FreeSWITCH — SIP registration, call routing, media, voicemail, faxing
db PostgreSQL All configuration and history (users, rules, CDRs, chat, settings)
turn coturn Media relay so browsers behind NAT can send/receive call audio
tunnel Exovo tunnel The :5090 front door for mobile apps and on-site SBCs (mutual TLS)
phoneproxy Exovo phoneproxy Lets admins open a desk phone's own web UI through the console
dockerproxy socket proxy A locked-down, read-mostly window onto Docker for status and update checks

The telephony core (FreeSWITCH)

core owns everything real-time: SIP registrations from phones and trunks, call routing, RTP media, music on hold, voicemail and fax. It exposes SIP on 5060 (phones), 5061 (SIP over TLS) and 5080 (trunks), plus the RTP range 16384–16484/udp. It doesn't make routing decisions on its own — for each call it asks the web app for dialplan instructions, so all configuration lives in one place (the database) and takes effect without reloads.

Two sidecars share the core's network namespace:

  • tunnel terminates the Exovo tunnel on port 5090 — the single mutual-TLS port that mobile apps and on-site SBCs use for SIP and media. It fetches its certificates from the web app on startup and holds no secrets of its own.
  • phoneproxy reaches phone web UIs on the LAN or over the remote-phone VPN — networks the hardened web container deliberately can't see — so the console's "open phone UI" button works without exposing phones directly.

The web console and web client

web is a single ASP.NET application serving both the admin console and the end-user web client, plus phone provisioning, the REST endpoints FreeSWITCH calls back into, and background workers (backups, CRM sync, update checks, the license phone-home). It's the only service that talks to the database, and it never faces the internet directly — Traefik fronts it.

Database and persistence

Everything configurable lives in PostgreSQL. Bulky media lives on the filesystem:

Path on host Contents
/var/lib/exovo/db PostgreSQL data
/var/lib/exovo/recordings Call recordings
/var/lib/exovo/ivr Digital-receptionist and system prompts
/var/lib/exovo/fax Sent/received faxes
/var/lib/exovo/certs, acme TLS certificates
/var/lib/exovo/keys Data-protection keys (encrypts stored secrets)
/var/lib/exovo/logs FreeSWITCH logs

Backing up /var/lib/exovo plus the database covers the entire system — which is exactly what the built-in backup does.

Reverse proxy and TLS

Traefik owns ports 80 and 443, redirects HTTP to HTTPS, and either maintains an automatic certificate for your FQDN or serves the custom one you provided during onboarding. Everything web-ish — console, provisioning, phone-UI proxy — flows through it; internal services are never published directly.

How a call flows through the system

  1. A phone (or trunk) sends SIP to core on 5060/5080.
  2. core asks web how to route the call; web answers from the database — user, ring group, queue, IVR, office-hours rules.
  3. Media (RTP) flows directly between the endpoint and core. Browser calls relay through turn; mobile-app and SBC calls arrive inside the tunnel on 5090.
  4. When the call ends, core reports the call record to web, which stores the CDR, triggers recording transcription and CRM journaling, and updates live dashboards.

Security posture, in brief

Containers run with dropped capabilities and no-new-privileges; the web app has no Docker socket (the deny-by-default dockerproxy allows only status reads and a scoped restart); the internet-facing tunnel holds no keys; and actions that need root on the host (updates, restores) are performed by small systemd watchers reacting to marker files — the containers themselves can't touch the host. Details in the security section.