Saltearse al contenido

Taller 7: Troncal SIP con PJSIP Wizard y Enrutamiento de Salida

Conecta tu PBX Asterisk 22 al mundo con PJSIP Wizard: troncales, rutas de entrada/salida y AGI para CallerID dinámico

🌉 Taller 7: Troncal SIP con PJSIP Wizard y Enrutamiento de Salida

Sección titulada «🌉 Taller 7: Troncal SIP con PJSIP Wizard y Enrutamiento de Salida»

🗺️ El Escenario: De una Isla a un Continente

Sección titulada «🗺️ El Escenario: De una Isla a un Continente»

Hasta ahora, nuestra PBX ha sido una isla: llamadas internas, AGI para lógica dinámica y notificaciones de voicemail por WhatsApp. En este taller, construimos el puente a la PSTN con una Troncal SIP.


7.0 Buenas Prácticas: Backup y Seguridad Primero

Sección titulada «7.0 Buenas Prácticas: Backup y Seguridad Primero»

Previo a refactor y conexión con proveedor, realiza respaldo y asegura el servidor.

Terminal window
cd /etc/asterisk
cp -rfv . ../asterisk.bk-$(date +%F-%H%M)

7.0.2 Cortafuegos (UFW) para señalización y media

Sección titulada «7.0.2 Cortafuegos (UFW) para señalización y media»
Terminal window
ufw allow 5060/udp
ufw allow 10000:20000/udp
# Permite solo la IP de tu proveedor (recomendado)
ufw allow from IP_PROVEEDOR_SIP to any port 5060 proto udp
ufw allow from IP_PROVEEDOR_SIP to any port 10000:20000 proto udp

7.1 Refactorización a pjsip_wizard.conf para Máxima Eficiencia

Sección titulada «7.1 Refactorización a pjsip_wizard.conf para Máxima Eficiencia»

El Wizard es la forma moderna y limpia de configurar PJSIP. Migremos nuestras extensiones al Wizard y documentemos cómo se relacionan los objetos que genera con pjsip.conf.

Terminal window
cd /etc/asterisk/
cp -R . ../asterisk-bk-$(date +%F-%H%M)

Edita pjsip.conf para dejar solo global/transport y mover endpoints al Wizard.

Terminal window
nano /etc/asterisk/pjsip.conf
; Este archivo ahora solo define la configuración global y los transportes.
; Toda la lógica de endpoints y troncales vivirá en pjsip_wizard.conf.
[global]
type=global ; Objeto raíz de res_pjsip
user_agent=AulaUtilPBX-v22 ; Cadena que verá tu proveedor en la cabecera User-Agent
default_realm=aulautil.com ; Dominio usado para autenticación digest
[transport-udp-nat]
type=transport ; Tipo de objeto PJSIP
protocol=udp ; Protocolo de señalización soportado
bind=0.0.0.0:5060 ; Puerto/IP donde Asterisk escucha peticiones SIP
local_net=192.168.1.0/24 ; Redes locales aceptadas (ajusta a tu topología)
external_media_address=TU_IP_PUBLICA ; IP pública que anunciará para RTP
external_signaling_address=TU_IP_PUBLICA ; IP pública que anunciará para SIP
[system]
type=system
threadpool_initial_size=50 ; Hilos creados al iniciar PJSIP (capacidad base)
threadpool_auto_increment=10 ; Hilos adicionales por cada pico de carga
threadpool_max_size=400 ; Límite superior para proteger la CPU del servidor
threadpool_idle_timeout=90 ; Segundos antes de reciclar hilos inactivos

Crea pjsip_wizard.conf y define una plantilla y tus extensiones:

Terminal window
cd /etc/asterisk/
touch pjsip_wizard.conf
nano pjsip_wizard.conf
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ANEXOS ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
[phone-template](!)
type=wizard ; Declara una plantilla reutilizable
transport=transport-udp-nat ; Hereda el transporte definido en pjsip.conf
accepts_auth=yes ; Genera objeto auth para registrar softphones
accepts_registrations=yes ; Permite que los endpoints se registren en Asterisk
endpoint/allow=!all,ulaw,alaw,opus ; Habilita códecs preferidos (ordénalos por prioridad)
endpoint/context=cat2 ; Contexto de dialplan por defecto
endpoint/dtmf_mode=rfc4733 ; Envía tonos DTMF por RFC4733 (teclas fiables)
endpoint/rtp_symmetric=yes ; Obliga RTP simétrico (NAT traversal)
endpoint/force_rport=yes ; Reescribe el puerto RTP para clientes detrás de NAT
endpoint/rewrite_contact=yes ; Asegura que el Contact apunte a la IP/puerto correctos
aor/max_contacts=1 ; Límite de dispositivos simultáneos por extensión
[1001](phone-template)
endpoint/context=cat1 ; Sobrescribe el contexto por permisos avanzados
endpoint/mailboxes=1001@default ; Vincula el buzón de voz configurado en voicemail.conf
endpoint/callerid="Usuario Oficina <1001>" ; Nombre que verá quien reciba la llamada
inbound_auth/username=1001 ; Usuario SIP del softphone
inbound_auth/password=pass1001 ; Contraseña (usa contraseñas fuertes en producción)
[1002](phone-template)
endpoint/mailboxes=1002@default
endpoint/callerid="Agente Soporte <1002>"
inbound_auth/username=1002
inbound_auth/password=pass1002
aor/max_contacts=2 ; Permite 2 dispositivos (PC + móvil) para la misma ext.
[1003](phone-template)
endpoint/context=cat3 ; Contexto restringido: solo llamadas internas/almacén
endpoint/mailboxes=1003@default
endpoint/callerid="Almacen <1003>"
inbound_auth/username=1003
inbound_auth/password=pass1003

El objeto Wizard genera automáticamente los bloques endpoint, auth, aor y, si lo indicamos, identify y registration. Así evitamos duplicar secciones y logramos configuraciones consistentes. Cada sección hija puede sobrescribir valores de la plantilla con la sintaxis endpoint/clave=valor.

Terminal window
systemctl restart asterisk

Verifica que los teléfonos registren correctamente.


7.2 Configuración de la Troncal SIP con el Wizard

Sección titulada «7.2 Configuración de la Troncal SIP con el Wizard»

Vamos a crear una plantilla reutilizable para proveedores, explicar cada parámetro y añadir herramientas de diagnóstico.

Edita pjsip_wizard.conf para añadir la troncal.

Terminal window
nano /etc/asterisk/pjsip_wizard.conf
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; TRONCALES ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
[trunk-template](!)
type=wizard ; Plantilla base para cada carrier SIP
sends_auth=yes ; Crea objeto de autenticación saliente
sends_registrations=yes ; Genera registro automático hacia el proveedor
endpoint/allow=!all,ulaw,alaw ; Códecs habilitados por defecto (añade g729 si aplica)
endpoint/context=from-trunk ; Contexto que recibirá las llamadas entrantes
endpoint/dtmf_mode=rfc4733 ; Envía tonos fuera de banda (DTMF fiable para IVR)
endpoint/rtp_symmetric=yes ; Usa la misma IP/puerto para RTP de ida y vuelta (NAT)
endpoint/force_rport=yes ; Obliga a usar el puerto fuente del paquete (NAT conservador)
endpoint/direct_media=no ; Mantén el audio pasando por Asterisk (grabación/monitor)
endpoint/timers=yes ; Re-INVITEs controlados por Asterisk
endpoint/language=es ; Locuciones en español por defecto para esta troncal
aor/qualify_frequency=60 ; Envía OPTIONS cada 60 s para validar que el carrier responde
aor/authenticate_qualify=no ; No solicita auth extra en el qualify (según carrier)
identify_by=ip ; Correlaciona llamadas entrantes usando la IP de origen
[mi-proveedor-sip](trunk-template)
transport=transport-udp-nat ; Usa el transporte definido en `pjsip.conf`
remote_hosts=IP_PROVEEDOR_SIP ; IP o FQDN del SBC del carrier (admite lista separada por comas)
registration/contact_user=TU_NUMERO_DID ; DID que anunciarás al registrar
outbound_auth/username=USUARIO_SIP ; Usuario SIP entregado por el proveedor
outbound_auth/password=PASSWORD_SIP ; Contraseña SIP
endpoint/from_user=USUARIO_SIP ; Usuario que saldrá en la cabecera From
endpoint/from_domain=FQDN_PROVEEDOR ; Dominio SIP del carrier (evita 403)
endpoint/allow=!all,ulaw,alaw,g729 ; Incluye g729 si compraste la licencia/códec
identify/endpoint=mi-proveedor-sip ; Vincula la IP de origen con este endpoint
identify/match=IP_PROVEEDOR_SIP/32 ; IP autorizada (ajusta máscara según rango)
; outbound_proxy=sip:IP_PROVEEDOR_SIP:5060 ; Descomenta si tu carrier exige proxy explícito

Aquí tienes algunas fuentes útiles para ampliar la configuración: PJSIP Configuration Wizard (Asterisk Docs) y Performance Tuning.

Recarga y verifica registro:

Terminal window
asterisk -rx "pjsip reload"
asterisk -rvvv
*CLI> pjsip show registrations
*CLI> pjsip show endpoint mi-proveedor-sip
*CLI> pjsip show identify mi-proveedor-sip-identify

Antes de continuar, confirma que extensions.conf incluye los archivos modulares creados en el Taller 5 y que defines el identificador de troncal en [globals].

[general]
static=yes ; Si es 'yes', Asterisk no sobrescribe este archivo
writeprotect=no ; Ajusta a 'yes' si deseas impedir cambios desde CLI (dialplan save)
autofallthrough=yes ; Evita que la llamada quede colgada si una extensión termina sin Hangup
clearglobalvars=no ; Mantiene las variables globales entre recargas de dialplan
priorityjumping=no ; Recomendado: evita saltos implícitos de prioridad
[globals]
IDTRUNK=TU_NUMERO_DID ; Valor que reutilizaremos como CallerID de la troncal
CONTEXT_ENTRADAS=from-trunk ; Contexto centralizado para llamadas entrantes
#include extensions_anexos.conf
#include extensions_salidas.conf
#include extensions_funciones.conf
#include extensions_categorias.conf

Puedes usar extensions_salidas.conf o crear extensions_entradas.conf.

Terminal window
nano /etc/asterisk/extensions_salidas.conf
[from-trunk]
exten => s,1,NoOp(Llamada entrante desde ${CALLERID(num)} a nuestro DID)
same => n,Dial(PJSIP/1001,30)
same => n,Hangup()
; Estructura sugerida con comentarios
[from-trunk]
exten => s,1,NoOp(Llamada entrante desde ${CALLERID(num)} a nuestro DID)
same => n,Set(CHANNEL(language)=es) ; Asegura locuciones en español
same => n,Set(CDR(accountcode)=TRONCAL_SIP) ; Marca las llamadas para reportes
same => n,Dial(PJSIP/1001,30) ; Ruta al anexo 1001 durante 30 s
same => n,Hangup()

7.3.2 Contextos de Salida (extensions_salidas.conf)

Sección titulada «7.3.2 Contextos de Salida (extensions_salidas.conf)»

En el Taller 5 separamos la lógica de salida en extensions_salidas.conf. Aquí lo extendemos para manejar teléfonos fijos, celulares, larga distancia nacional (LDN) e internacional (LDI) usando la troncal mi-proveedor-sip y el IDTRUNK definido en [globals].

; /etc/asterisk/extensions_salidas.conf
[salidas-fijo]
exten => _[2-7]XXXXXX,1,NoOp(Llamada saliente a fijo peruano: ${EXTEN})
same => n,Set(CALLERID(num)=${IDTRUNK})
same => n,Dial(PJSIP/${EXTEN}@mi-proveedor-sip,45,T)
same => n,Hangup()
[salidas-celular]
exten => _9XXXXXXXX,1,NoOp(Llamada saliente a celular: ${EXTEN})
same => n,NoOp(CallerID original: ${CALLERID(num)})
same => n,AGI(callerid_roulette.py) ; Taller 5: rota CallerID
same => n,Set(CHANNEL(language)=es)
same => n,NoOp(CallerID luego de AGI: ${CALLERID(num)})
same => n,Dial(PJSIP/${EXTEN}@mi-proveedor-sip,45,T)
same => n,Hangup()
[salidas-ldn]
exten => _0NX[2-7]XXXXX,1,NoOp(Llamada LDN (larga distancia nacional): ${EXTEN})
same => n,Set(CALLERID(num)=${IDTRUNK})
same => n,Dial(PJSIP/${EXTEN}@mi-proveedor-sip,45,T)
same => n,Hangup()
[salidas-ldi]
exten => _00.,1,NoOp(Llamada LDI (internacional): ${EXTEN})
same => n,Set(CALLERID(num)=${IDTRUNK})
same => n,Dial(PJSIP/${EXTEN}@mi-proveedor-sip,60,T)
same => n,Hangup()

Si necesitas lógica adicional para los celulares (música en espera, bloqueo cuando 1001 está ocupado) puedes extender solo ese contexto:

; Variante avanzada para [salidas-celular]
[salidas-celular]
exten => _9XXXXXXXX,1,NoOp(Llamada saliente a celular: ${EXTEN})
same => n,ExecIf($["${DEVICE_STATE(PJSIP/1001)}"="BUSY"]?Playback(all-circuits-busy-now))
same => n,AGI(callerid_roulette.py)
same => n,NoOp(CallerID modificado por AGI: ${CALLERID(num)})
same => n,Set(CHANNEL(language)=es)
same => n,Dial(PJSIP/${EXTEN}@mi-proveedor-sip,45,Tb(func-meanwhile,s,1))
same => n,Hangup()

Actualiza extensions_categorias.conf para conceder permisos de manera progresiva, tal como definimos en talleres anteriores:

; /etc/asterisk/extensions_categorias.conf
[cat1]
include => anexos-internos
include => funciones-voicemail
include => salidas-fijo
include => salidas-celular
include => salidas-ldn
include => salidas-ldi
[cat2]
include => anexos-internos
include => funciones-voicemail
include => salidas-fijo
include => salidas-celular
[cat3]
include => anexos-internos
include => funciones-voicemail
include => salidas-celular
Terminal window
asterisk -rx "dialplan reload"
# Permite el tráfico desde la IP del proveedor
ufw allow from IP_PROVEEDOR_SIP to any port 5060 proto udp
ufw allow from IP_PROVEEDOR_SIP to any port 10000:20000 proto udp

  • Abre el CLI: asterisk -rvvv.
  • Desde la extensión 1001 (permiso cat1), marca un número real.
  • Observa ejecución de AGI, cambio de CallerID y envío por mi-proveedor-sip.
  • Ejecuta sngrep para validar la señalización.
  • Comprueba el estado con pjsip show channels para ver la llamada activa.
  • Desde tu celular, llama a tu DID.
  • Observa ingreso en from-trunk y timbrado en 1001.
  • Usa asterisk -rx "core show channel <canal>" para confirmar códecs y variables.
  • Verifica que el endpoint correcto atiende la llamada con pjsip show channel <ID>.

¡Tu PBX ya está conectada al mundo exterior usando las mejores prácticas!


7.5 Rendimiento, Límites del Sistema y Buenas Prácticas

Sección titulada «7.5 Rendimiento, Límites del Sistema y Buenas Prácticas»
  • Threadpool: asterisk -rx "core show threads" y core show taskprocessors para monitorear.
  • Timers SIP: Ajusta timer_t1=500, timer_b=32000 si tienes retardos.
  • Sorcery cache: En sorcery.conf usa memory_cache o redis para cientos de endpoints.

7.5.2 Descriptores de archivo (asterisk.conf)

Sección titulada «7.5.2 Descriptores de archivo (asterisk.conf)»
[options]
maxfiles = 32768
maxload = 5.0
corelimit = 1000000
  • Reinicia Asterisk y verifica con asterisk -rx "core show settings".
  • Sincroniza LimitNOFILE en systemd creando /etc/systemd/system/asterisk.service.d/limits.conf.
  • Firewall: Documenta IPs del carrier y automatiza actualizaciones.
  • Logs: Configura logger.conf para canal pjsip_wizard.
  • Auditoría: pjsip show history para limpiar endpoints sin uso.