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 / LAN
                        │
    80 / HTTPS port     │           5060/5061 (SIP — LAN only)
      ┌─────────────────┤           5080 (public trunks), 5082 (LAN peers)
      │                 │           5090 (tunnel)
      ▼                 │           5091 (VPN)  16384-16584 (media)
 ┌─────────┐            │                 │
 │ traefik │            │                 ▼
 │ (proxy) │            │      ┌──────────────────────────┐
 └────┬────┘            │      │  core (FreeSWITCH)       │
      │ HTTP            │      │  + tunnel   (sidecar)    │
      ▼                 │      │  + phoneproxy (sidecar)  │
 ┌─────────┐   ESL/API  │      └──────────┬───────────────┘
 │   web   │◄───────────┼─────────────────┘
 │ console │            │      3478 + 16485-16584
 └────┬────┘            │                 │
      │ 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 the Exovo 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

Port reference

Every port the system listens on, and who is meant to reach it. Only the ports whose audience includes the internet ever need router forwarding — the per-scenario forwarding list is in the installation guide. In particular, 5060/5061 are for LAN phones and registering gateways only: remote phones come in through the SBC tunnel (5090) or VPN (5091), never by forwarding SIP.

Port Protocol Service Audience Purpose
80 TCP traefik Internet HTTP redirects and automatic certificate issuance
Configured HTTPS port (default 443) TCP traefik Internet + LAN Web console and client, provisioning and HTTPS APIs
5060 UDP + TCP core LAN only SIP — local phone and gateway registration (internal profile)
5061 TCP core LAN only SIP over TLS — local phones
5080 UDP + TCP core Trunk providers SIP — public external/trunk profile
5082 UDP + TCP core LAN only SIP — LAN trunks and gateway outbound calls (external-lan profile)
5090 TCP + UDP tunnel Internet Exovo tunnel — SBC sites and the Exovo apps (mutual TLS)
5091 UDP core Internet Remote-phone VPN (OpenVPN)
8443 TCP core Internet Cisco phone VPN (AnyConnect via ocserv)
443 UDP core Internet Cisco phone VPN — DTLS media path (optional)
69, 6970 UDP, TCP core LAN only Cisco Enterprise provisioning (TFTP + HTTP config service), when enabled
16384-16484 UDP core Trunk providers + LAN RTP call media
16485-16584 UDP turn Internet + LAN TURN relay range (contiguous with RTP — forward 16384-16584 as one block)
3478 UDP + TCP turn Internet + LAN TURN/STUN — media relay for browser calling

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 (public trunks) / 5082 (LAN peers), 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). Routing changes take effect dynamically; SIP address changes require a core restart. The LAN peer guide explains how local peers advertise the configured Host IP Address independently of the public IP.

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

Users, routing and application settings live in PostgreSQL. Deployment settings such as the HTTPS port live in /opt/exovo/.env; media and telephony state also live 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, voicemail audio and the 3CX voicemail import ledger
/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

The built-in backup has configuration and full profiles. Choose Full to include voicemail and other bulk media; use that guide to confirm the profile and restore scope you need.

Reverse proxy and TLS

Traefik owns port 80 and the configured HTTPS TCP port (443 by default), redirects HTTP to the full HTTPS address, 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 registering gateway sends SIP to core on 5060; IP-authenticated public trunks use 5080 and IP-authenticated LAN peers use 5082.
  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.