Configuration

Every environment variable, its default, and what breaks when it is wrong.

Configuration is read from the environment once, at startup, into a single validated struct. Everything downstream reads that struct, never the environment — which is also why a test can construct one directly.

Validation reports every problem at once, so a misconfigured deployment does not have to be fixed one restart at a time.

Required

VariableDescription
ULAI_CONTROL_PLANE_URLBase URL of the Ulai control plane, e.g. https://stgcp.ulai.co.in. Rooms are created, joined and terminated here.
SIP_ROUTING_REDIS_URLThe routing store every call is resolved against. REDIS_URL is accepted as a fallback.
SIP_PUBLIC_IPThe address advertised in SDP and Contact. Must be routable by the carrier. 0.0.0.0 is rejected — it is not a listen address, it is what the carrier is told to stream media to.

SIP signalling

VariableDefaultDescription
SIP_LISTEN_ADDR0.0.0.0:5060What sipgo binds to. host:port; the host may be 0.0.0.0.
SIP_TRANSPORTudpudp, tcp or tls.
SIP_TLS_CERT_PATHRequired when SIP_TRANSPORT=tls.
SIP_TLS_KEY_PATHRequired when SIP_TRANSPORT=tls.
SIP_SESSION_HEADERX-Session-IdThe INVITE header that may point a call at an existing room. Must not be blank.

RTP media

VariableDefaultDescription
SIP_RTP_HOST0.0.0.0What RTP sockets bind to, as distinct from SIP_PUBLIC_IP, which is what is advertised. On most cloud VMs the public IP is attached at a NAT or load-balancer layer and is not on any interface inside the VM, so binding to it fails with cannot assign requested address. The default is right nearly everywhere.
SIP_RTP_PORT_LOW10000Bottom of the RTP allocation range.
SIP_RTP_PORT_HIGH10500Top of the range. Must be above the low end, and both within 1–65535. Even ports only, by RTCP convention.
SIP_RTP_TIMEOUT_SECONDS30End a call whose inbound audio has stopped for this long, as if the far end had hung up — the backstop for a BYE that never arrives. Paused while the call is on hold. 0 disables it.

HTTP API

VariableDefaultDescription
SIP_HTTP_PORT8082Port for /health, /calls and /sip/originate. Chosen clear of the worker (8080) and the Tata gateway (8081).

Rooms

VariableDefaultDescription
ULAI_PROJECT_IDDefault project for POST /sip/originate when the body omits project_id. The single-tenant deployment’s answer to sending it every time.
ULAI_MAX_PARTICIPANTS8Size of a room the gateway creates. Overridden per request by max_participants. Must be positive.
SIP_TERMINATE_SESSION_ON_HANGUPtrueEnd the whole session — every participant, every transport — when the SIP leg drops, rather than merely leaving the room. Set false only when a room reached via X-Session-Id or session_id is genuinely shared. A room the gateway created is always terminated regardless.

ICE

The gateway is STUN-only by default (stun:stun.l.google.com:19302), which is fine on a public host and will fail behind symmetric NAT.

VariableDefaultDescription
TURN_URLSComma-separated TURN URLs. Appended to the STUN default.
TURN_USERNAMETURN credential.
TURN_PASSWORDTURN credential.

Go runtime

At startup the process aligns the Go runtime with its cgroup limits — two defaults that are correct on a bare host become latency or OOM bugs inside a container. An explicit environment variable always wins.

VariableBehaviour when unset
GOMAXPROCSPinned to ceil(cgroup CPU quota) when that is below the host core count. Left alone otherwise.
GOMEMLIMITSet to 85% of the cgroup memory limit, or of total system RAM when there is none. The headroom covers goroutine stacks and the off-heap libopus and resampler allocations GOMEMLIMIT cannot see.
GOGCRaised to 200, trading memory for fewer GC cycles and less latency jitter, bounded by the limit above.

Each decision is logged at startup:

[runtime] GOMAXPROCS=4 (cgroup CPU quota=4.00, host cores=8)
[runtime] GOMEMLIMIT=3481MiB (cgroup limit=4096MiB, 85%)
[runtime] GOGC=200

Built-in timeouts

Not configurable — they are constants, listed here because they explain the behaviour you will observe.

ConstantValueBounds
ResolveTimeout5 sOne routing-store lookup
CreateTimeout15 sCreating a room
JoinTimeout15 sJoining a room
DialTimeout15 sThe WebRTC signalling dial
OriginateTimeout60 sAn outbound INVITE, through ring
TerminateTimeout5 sTerminating a room, or hanging up a leg
DrainTimeout60 sThe shutdown drain
CancelGrace5 sExtra time after the drain deadline cancels calls
MaxRequestBytes8 KiBAn originate body — it is a control API, not an upload
publish timeout2 sOne event publish, best-effort
control-plane HTTP timeout10 sAny single control-plane request

Example

# Required
ULAI_CONTROL_PLANE_URL=https://stgcp.ulai.co.in
SIP_ROUTING_REDIS_URL=redis://user:password@redis.example.com:6379/0
SIP_PUBLIC_IP=203.0.113.10

# SIP + RTP
SIP_LISTEN_ADDR=0.0.0.0:5060
SIP_TRANSPORT=udp
SIP_RTP_PORT_LOW=10000
SIP_RTP_PORT_HIGH=10500
SIP_RTP_TIMEOUT_SECONDS=30

# HTTP
SIP_HTTP_PORT=8082

# Rooms
SIP_TERMINATE_SESSION_ON_HANGUP=true
Last modified September 21, 2026: sip module (0ee6a81)