Skip to content

DID Routing Environments

Every DID in did_numbers has a routing_environment flag that decides where inbound calls for that number land: prod, staging, or OSS. This lets one Tata trunk serve all three environments with a clean separation.

The three environments

Value Where inbound lands Managed by
prod (default) Prod cloud, local org_*_incoming context Prod dispatcher auto-generated from DB
staging Staging cloud via WireGuard (cloud-endpoint-stage) Prod dispatcher auto-generated from DB
oss OSS VPS (185.252.235.208) via public SIP from NUC NUC oss-did-routemanual config

How the flag drives dispatch

The dispatcher generator lives in api/src/services/asterisk/configDeploymentService.js → deployGatewayRouting(). It regenerates /etc/asterisk/ext_tata_gateway.conf on each config deploy. Pseudocode:

for each assigned DID:
  if didEnv === myEnv:
    Goto(org_<prefix>__incoming, <did>, 1)      // local routing
  elif myEnv === 'prod' && didEnv === 'staging':
    Dial(PJSIP/<did>@cloud-endpoint-stage, 120) // forward over WG
  else:
    fallback: log + local Goto

myEnv is derived from process.env.ASTRADIAL_ENV at runtime — "staging" on staging, default "prod" on prod.

Format aliases

Indian DIDs are stored as either 08065978002 (local) or 918065978002 (international). The dispatcher generator emits both aliases for every Indian DID so customers calling either format reach the same org:

exten => 08065978002,1,Goto(org_mnd5khym__incoming,08065978002,1)
exten => 918065978002,1,Goto(org_mnd5khym__incoming,918065978002,1)

Generator helper: indianAliases(num) — prepends 91 to 11-digit leading-0 numbers and vice versa.

Managing the flag

Via admin UI (primary path)

  1. Log into editor as admin → Admin → DID Management
  2. Click the Environment dropdown on the DID row
  3. Pick Prod / Staging / OSS
  4. Backend flow: PUT /api/v1/did-pool/admin/<id> + POST /api/v1/admin/regenerate-gateway
  5. Dispatcher regenerates + Asterisk reloads in place (no call drops)

Via SQL (emergency / bulk)

-- Single DID
UPDATE did_numbers SET routing_environment='staging' WHERE number='+918065978001';

-- Range allocation
UPDATE did_numbers SET routing_environment='staging' WHERE number IN ('918065978021','918065978022','918065978023','918065978024');
UPDATE did_numbers SET routing_environment='oss' WHERE number LIKE '91806597802_';

Then: curl -X POST -H "X-Internal-Key: $INTERNAL_API_KEY" http://localhost:8000/api/v1/admin/regenerate-gateway

Allocation convention

Astradial owns 30 DIDs (91806597 8000 – 8029). The current split:

Range Environment Count Notes
78000 – 78020 prod 21 Customer DIDs + reserved
78021 – 78024 staging 4 Testing pool
78025 – 78029 oss 5 OSS demo pool

Convention — not enforced. Any DID can move between environments via the UI.

How prod forwards staging traffic (WireGuard)

Tata PSTN → NUC (10.10.10.2) → Prod Cloud (10.10.10.1)
                                     │ if routing_environment='staging':
                                     │   Dial(PJSIP/<did>@cloud-endpoint-stage,120)
                            cloud-endpoint-stage endpoint on prod
                                     │ (PJSIP contact: sip:10.10.10.3:5060)
                            WireGuard tunnel prod ↔ staging
                            Staging Cloud (10.10.10.3)
                              tata_gateway endpoint
                              identify match: 10.10.10.1, 10.10.10.2
                              tata-inbound → tata-did-route → org_*_incoming

Required setup for staging forwarding to work

  • Prod has cloud-endpoint-stage PJSIP endpoint + cloud-aor-stage AOR (sip:10.10.10.3:5060)
  • WireGuard tunnel prod (10.10.10.1) ↔ staging (10.10.10.3) — wg show wg0 must show recent handshake
  • Staging's tata_gateway_identify must include match=10.10.10.1 (added during Apr 17 cutover)
  • ASTRADIAL_ENV=staging in staging's api .env → generator produces local Goto for staging-env DIDs

OSS routing — kept on NUC deliberately

OSS is NOT dispatched from prod for security reasons:

  • If OSS VPS is compromised (credentials leak, exploit), attacker must not reach prod SIP
  • If OSS VPS is unreachable (downtime, DDoS, misconfig), prod must continue working for real customers

Current OSS flow:

Tata → NUC (192.168.0.13) → NUC's oss-did-route context
                               │  exten => 918065978015,1,
                               │  Dial(PJSIP/${TATA_DID}@185.252.235.208:5060,30)
                         Public internet (SIP auth)
                               │ username nuc_oss_gateway
                       OSS VPS (185.252.235.208)
  • NUC's oss-did-route is manually maintained (one exten => line per OSS DID)
  • Prod has no knowledge of OSS routing
  • routing_environment='oss' flag on prod DIDs is purely informational
  • When adding a new OSS DID, admin must SSH NUC and add the routing entry

When OSS grows to real customers, revisit this with a WireGuard tunnel prod ↔ OSS — defence in depth via SIP auth + WG private key + IP whitelist. Until then, NUC-only isolation is the right call.

Troubleshooting

"I changed routing_environment but dispatcher didn't update"

  • Confirm PUT hit the API: pm2 logs astrapbx --lines 30 --nostream | grep PUT
  • Known-bug fix landed in fix/did-admin-put-allow-routing-env (Apr 17) — verify routing_environment is in the allowed array at api/src/routes/didPool.js PUT handler
  • Manually trigger regen: curl -X POST -H "X-Internal-Key: $KEY" http://localhost:8000/api/v1/admin/regenerate-gateway
  • Then grep <did> /etc/asterisk/ext_tata_gateway.conf to confirm

"Staging-flagged DID not reaching staging"

  1. Prod dispatcher emits Dial(PJSIP/.../cloud-endpoint-stage) — check file
  2. asterisk -rx 'pjsip show endpoint cloud-endpoint-stage' → Status: Avail
  3. wg show wg0 | grep -A 3 '10.10.10.3' → recent handshake
  4. On staging: asterisk -rx 'pjsip show identifies' → must include 10.10.10.1
  5. Check staging's asterisk log for 'from-tata' / 'tata-inbound' entries

"OSS DID reaching prod (shouldn't happen)"

  • Means NUC failed to intercept it before forwarding. Check NUC's extensions.conf for an oss-did-route entry matching the DID.