Accounts and extensions
An account is a credential a phone registers with. An extension is a number inside a tenant, backed by a dialplan file. An account names the extension it belongs to, and several accounts may name the same one.
accounts:
- username: alice
password: "change-me"
extension: "100"
display_name: Alice
- username: alice-mobile
password: "change-me-too"
extension: "100" # same extension: both devices ring
- username: bob
password: "and-me"
extension: "101"
| Field | Required | Purpose |
|---|---|---|
username | yes | The SIP username, unique within the tenant. |
password | yes | Digest password, stored in plain text in the file. |
extension | yes | The extension number this account belongs to. |
display_name | no | Caller name shown on internal calls. |
Registration
Phones register to the tenant's SIP domain with the PBX as their outbound proxy:
| Field | Value |
|---|---|
| Username | the account username |
| Domain / SIP server | the tenant domain, e.g. acme.pbx.example.com |
| Outbound proxy | the PBX address, e.g. 192.0.2.10:5060 |
The domain in the request selects the tenant and becomes the digest realm. A registration whose domain matches no tenant is refused with a log line naming the domain it offered.
Bindings are keyed tenant/extension, so nothing that looks up "extension 100"
without a tenant can ever be right.
Expiry
The requested expiry comes from the Contact expires parameter, or from the
Expires header, and is clamped:
| Value | |
|---|---|
| Minimum | 60s |
| Default when the phone asks for nothing | 300s |
| Maximum | 3600s |
A REGISTER with Expires: 0 removes the binding; Contact: * with
Expires: 0 removes every binding for that account. The 200 OK echoes the
current bindings with their remaining lifetime.
NAT
Endpoints are dialled at the source address observed during REGISTER, not the address advertised in the Contact header, because NAT clients advertise private addresses. Nothing needs configuring for the phone side of NAT.
If the PBX itself is behind NAT, set sip.external_host and
media.external_ip — see Running behind NAT.
Several devices on one extension
Every registered device for an extension rings in parallel. The first to answer wins and the others are cancelled. This is how a desk phone and a softphone share extension 100 without any group configuration.
Extensions without an account
An extension number does not need an account. Extension 200 in the quick start is a dialplan entry point reached from a DID: it plays a greeting and rings other extensions, but nothing registers as "200". This is the normal shape for hunt groups, out-of-hours announcements and IVR-style entry points.
Conversely, an account whose extension has no dialplan file can register and
place calls, but calls to it have nowhere to go — so give every extension you
intend to reach a file, even if it holds a single dial step:
extension: "100"
name: Alice
steps:
- id: ring
type: dial
timeout: 30s
target:
kind: endpoint
endpoint: "100"
Passwords
Passwords are stored in plain text; digest authentication needs them. Lyno
writes configuration files with mode 0600 and the container image runs as a
non-root user, but the operational rule is simple: treat the tenant directory
as a secret, and keep it out of any public repository.