Skip to main content

The dashboard

Running lyno in an interactive terminal without -headless opens a live view of the system. It is the primary operational interface: there is no web UI, and the management API is read-mostly and off by default.

▐ Lyno PBX ▌ v1.4.2 0.0.0.0:5060 · 4/5 online · 1/1 trunks up · uptime 6h12m
Overview Calls 2 Endpoints 5 Trunks 1 Security 1 Logs tenant acme
╭──────────────────────────────────────────────────────────────────────────────────────────╮
│ active calls endpoints trunks calls finished banned ips │
│ 2 4/5 1/1 148 1 │
│ in progress registered reachable 15 missed 412 rejected │
│ │
│ Tenants │
│ TENANT DOMAIN ONLINE CALLS DIDS │
│ acme acme.pbx.example.com 3/3 2 2 active │
│ globex globex.pbx.example.com 1/2 0 1 idle │
╰──────────────────────────────────────────────────────────────────────────────────────────╯
tab switch · t tenant · / filter · ? help · q quit

The banned-addresses tile only appears once there is something to report. An always-present "0 banned" is a number nobody reads.

The header

Always visible, and always describing what is currently on screen rather than the whole system — see filters below.

FieldMeaning
host:portThe address the PBX is listening on.
n/m onlineEndpoints with a live registration, out of all configured accounts.
n/m trunks upTrunks that are reachable and, where configured, registered.
uptimeTime since the process started.

The six views

#ViewShows
1OverviewTiles, a per-tenant summary and recent calls.
2CallsCalls in progress, plus finished ones.
3EndpointsEvery account, its registration state, contact and user agent.
4TrunksTrunk state, registration and the addresses inbound calls are accepted from.
5SecurityThe source addresses the guard is holding at arm's length.
6LogsThe live log, scrollable, with a level floor.

The tab bar carries a count badge per view, so Calls 2 means two calls are visible under the current filters.

There is no queue view and no do-not-disturb view. Queue depth and feature state are not surfaced anywhere at run time; the log is the only place a queued call appears.

Overview

Four tiles, then a tenant table, then recent calls.

The calls since start tile breaks down as answered · missed · live, and the breakdown adds up to the total — a glance never leaves you wondering where the missing calls went.

The tenant table answers the two questions an operator asks first: is anyone online, and is anything happening.

Calls

Calls currently in progress, with tenant, direction, from, to, state and duration. State colours are consistent everywhere: a colour means the same thing on every screen.

Endpoints

One row per configured account. An account that never registered still appears, which is how you tell "the phone is off" from "the account does not exist". Includes the contact address actually being used — the source address seen at REGISTER, not the advertised Contact.

Trunks

Per trunk: reachability, registration state and expiry, and the discovered INBOUND FROM addresses. This is the first place to look when inbound calls are rejected while outbound works.

Security

One row per address the guard is tracking:

SOURCE STATE REASON STRIKES FAILURES EXPIRES DROPPED TENANT
198.51.100.9 banned auth failures 2 7 18m 412 acme

The security guard is not enabled and Nothing is being blocked are different messages on purpose — the first means security.enabled is off.

A ban that could not be attributed to a tenant survives the tenant filter, the same way a shared trunk does. An attacker is not a customer, and hiding that row would hide the one thing an operator filtering for trouble is looking for.

These numbers are polled once a second rather than pushed over the event bus, because the bus drops events under exactly the flood they describe.

See The security guard.

Logs

The live log, newest at the bottom. Scrolling back with pauses following; the footer says so and resumes. L cycles the level floor (DEBUG → INFO → WARN → ERROR, starting at INFO) when info is too noisy.

Keys

KeyAction
tab / shift+tabNext or previous view
/ h lSame as tab / shift+tab
16Jump straight to a view
/ k jMove the row cursor, or scroll the log
x / dAct on the selected row — see below
rTrunks only: re-resolve the provider addresses now
tCycle the tenant filter
/Filter by text — enter applies, esc clears
LCycle the log level floor
escClear all filters
?Help
q / ctrl+cQuit, stopping the PBX

Acting on the running system

The dashboard is not only a viewer. x stages a destructive action on the selected row, and it always asks first, naming what it is about to do:

hang up 100 → 101 (acme)? y confirm · any other key cancel

y, Y or enter confirms; any other key cancels.

Viewx does
CallsHang up the selected call.
EndpointsDrop the endpoint's registration.
SecurityLift the ban on the selected address.
TrunksNothing — use r to re-resolve, which is not destructive and needs no confirmation.

Dropping a registration clears an endpoint's bindings so the phone registers again, which is the usual way to clear a stuck registration. Re-resolving a trunk repeats the DNS discovery immediately instead of waiting for the five-minute refresh. Lifting a ban is there because banning is the feature most likely to shut out a real customer at three in the morning, and "restart the PBX" is a worse answer than a keypress.

Hanging up is asynchronous on purpose: a BYE to a peer that has not acknowledged the call can block for a full transaction timeout of about 32 seconds while still reporting success, and the dashboard cannot freeze for that long. The call disappearing from the list is what confirms the outcome.

The same four actions are on the management API behind the operate scope.

Filters are global

This is the design decision worth internalising: the tenant filter and the text filter narrow every view at once. Pressing t until the badge reads tenant acme means the header counts, the tiles, the call list, the endpoints and the logs all describe acme only.

Active filters are shown as badges next to the tab bar precisely because they change what every number on screen means. esc clears both.

Finished calls are kept

The event bus reports state changes; the dashboard turns them into history and counters. That is why a call that failed thirty seconds ago is still on the Overview under "Recent calls" — without it, a failed call vanished the moment it ended, which made the dashboard useless for finding out what just happened.

Counters and history live in memory and reset when the process restarts. The durable record is the call log, which is written to disk from a different code path for exactly that reason.

Quitting

q cancels the PBX context and exits. There is no way to detach the dashboard and leave the PBX running — for a long-lived service, run with -headless under systemd or Docker and read the logs there.