The quickstart is small on purpose: it creates a test PostgreSQL Deployment, two demo users, one internal dial policy, and two routes. In production, keep the same resource model, but replace the demo pieces with durable infrastructure and real credentials.

Use production PostgreSQL

KubeVoIP expects a PostgreSQL connection Secret with host, port, dbname, user, and password keys. The database can come from a cloud provider, CNPG, another PostgreSQL operator, or your own managed service.

Create the Secret without putting the password in shell history:

printf '%s' "$POSTGRES_PASSWORD" | uvx kubevoip -n telephony secret database postgres-app \
  --host "$POSTGRES_HOST" \
  --port 5432 \
  --db kubevoip \
  --user kubevoip \
  --password-stdin

Then create the gateway against that Secret, or initialize the platform with that database:

printf '%s' "$POSTGRES_PASSWORD" | uvx kubevoip -n telephony init \
  --database existing \
  --postgres-host "$POSTGRES_HOST" \
  --postgres-db kubevoip \
  --postgres-user kubevoip \
  --postgres-password-stdin

PostgreSQL stores runtime routing data and HA1 password hashes. Treat HA1 as credential-equivalent material and protect database backups accordingly.

Create SIP device credentials

Each phone should have its own SIPUser and password Secret:

export SIP_PASSWORD="$(openssl rand -base64 32)"

printf '%s' "$SIP_PASSWORD" | uvx kubevoip -n telephony secret sip-user alice-sip \
  --from-stdin

uvx kubevoip -n telephony user create alice \
  --extension 100 \
  --gateway main \
  --dial-policy internal-only \
  --auth-username alice \
  --caller-id "Alice <100>" \
  --password-secret alice-sip

Configure the SIP client with:

FieldValue
Server / registrarThe main-sip-gateway external address
Usernamealice
Authentication usernamealice
PasswordThe generated Secret value
Extension100

Do not commit raw SIP passwords to Git. If you use GitOps, store credentials through your normal secret-management system and create Kubernetes Secrets from there.

Model who can call what

Use CallScope, DialPolicy, and CallRoute to express the dial plan:

uvx kubevoip -n telephony scope create internal --gateway main

uvx kubevoip -n telephony policy create internal-only \
  --gateway main \
  --scope internal

uvx kubevoip -n telephony route create bob-extension \
  --gateway main \
  --scope internal \
  --priority 10 \
  --match 101 \
  --target-user bob

A caller can only search scopes listed in its DialPolicy. Put outbound trunks or application routes in separate scopes when only some callers should use them.

Expose SIP and RTP deliberately

Before accepting real traffic, read SIP on Kubernetes and LoadBalancer networking. Public SIP and RTP forwarding must preserve ports. KubeVoIP does not configure provider portals, DNS, routers, cloud firewall rules, or perimeter firewalls.

Production checklist

  • Use a durable PostgreSQL database and backups.
  • Protect PostgreSQL because it stores credential-equivalent HA1 values.
  • Use unique SIP credentials per device.
  • Keep Secrets out of ConfigMaps and Git.
  • Confirm SIPGateway, MediaRelay, SIPUser, CallScope, DialPolicy, and CallRoute resources report Ready.
  • Confirm LoadBalancer addresses and firewall rules before testing real calls.
  • Document which dial policies are allowed to reach trunks.