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.
7.0.1 Backup de configuración de Asterisk
Sección titulada «7.0.1 Backup de configuración de Asterisk»cd /etc/asteriskcp -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»ufw allow 5060/udpufw allow 10000:20000/udp# Permite solo la IP de tu proveedor (recomendado)ufw allow from IP_PROVEEDOR_SIP to any port 5060 proto udpufw allow from IP_PROVEEDOR_SIP to any port 10000:20000 proto udp7.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.
7.1.1 Backup, Como Siempre
Sección titulada «7.1.1 Backup, Como Siempre»cd /etc/asterisk/cp -R . ../asterisk-bk-$(date +%F-%H%M)7.1.2 Moviendo la Lógica de los Endpoints
Sección titulada «7.1.2 Moviendo la Lógica de los Endpoints»Edita pjsip.conf para dejar solo global/transport y mover endpoints al Wizard.
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_pjsipuser_agent=AulaUtilPBX-v22 ; Cadena que verá tu proveedor en la cabecera User-Agentdefault_realm=aulautil.com ; Dominio usado para autenticación digest
[transport-udp-nat]type=transport ; Tipo de objeto PJSIPprotocol=udp ; Protocolo de señalización soportadobind=0.0.0.0:5060 ; Puerto/IP donde Asterisk escucha peticiones SIPlocal_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 RTPexternal_signaling_address=TU_IP_PUBLICA ; IP pública que anunciará para SIP
[system]type=systemthreadpool_initial_size=50 ; Hilos creados al iniciar PJSIP (capacidad base)threadpool_auto_increment=10 ; Hilos adicionales por cada pico de cargathreadpool_max_size=400 ; Límite superior para proteger la CPU del servidorthreadpool_idle_timeout=90 ; Segundos antes de reciclar hilos inactivosCrea pjsip_wizard.conf y define una plantilla y tus extensiones:
cd /etc/asterisk/touch pjsip_wizard.confnano pjsip_wizard.conf;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ANEXOS ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
[phone-template](!)type=wizard ; Declara una plantilla reutilizabletransport=transport-udp-nat ; Hereda el transporte definido en pjsip.confaccepts_auth=yes ; Genera objeto auth para registrar softphonesaccepts_registrations=yes ; Permite que los endpoints se registren en Asteriskendpoint/allow=!all,ulaw,alaw,opus ; Habilita códecs preferidos (ordénalos por prioridad)endpoint/context=cat2 ; Contexto de dialplan por defectoendpoint/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 NATendpoint/rewrite_contact=yes ; Asegura que el Contact apunte a la IP/puerto correctosaor/max_contacts=1 ; Límite de dispositivos simultáneos por extensión
[1001](phone-template)endpoint/context=cat1 ; Sobrescribe el contexto por permisos avanzadosendpoint/mailboxes=1001@default ; Vincula el buzón de voz configurado en voicemail.confendpoint/callerid="Usuario Oficina <1001>" ; Nombre que verá quien reciba la llamadainbound_auth/username=1001 ; Usuario SIP del softphoneinbound_auth/password=pass1001 ; Contraseña (usa contraseñas fuertes en producción)
[1002](phone-template)endpoint/mailboxes=1002@defaultendpoint/callerid="Agente Soporte <1002>"inbound_auth/username=1002inbound_auth/password=pass1002aor/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énendpoint/mailboxes=1003@defaultendpoint/callerid="Almacen <1003>"inbound_auth/username=1003inbound_auth/password=pass1003El 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.
7.1.3 Reiniciar Asterisk
Sección titulada «7.1.3 Reiniciar Asterisk»systemctl restart asteriskVerifica 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.
7.2.1 Preparar la plantilla de troncales
Sección titulada «7.2.1 Preparar la plantilla de troncales»Edita pjsip_wizard.conf para añadir la troncal.
nano /etc/asterisk/pjsip_wizard.conf;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; TRONCALES ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
[trunk-template](!)type=wizard ; Plantilla base para cada carrier SIPsends_auth=yes ; Crea objeto de autenticación salientesends_registrations=yes ; Genera registro automático hacia el proveedorendpoint/allow=!all,ulaw,alaw ; Códecs habilitados por defecto (añade g729 si aplica)endpoint/context=from-trunk ; Contexto que recibirá las llamadas entrantesendpoint/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 Asteriskendpoint/language=es ; Locuciones en español por defecto para esta troncalaor/qualify_frequency=60 ; Envía OPTIONS cada 60 s para validar que el carrier respondeaor/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 registraroutbound_auth/username=USUARIO_SIP ; Usuario SIP entregado por el proveedoroutbound_auth/password=PASSWORD_SIP ; Contraseña SIPendpoint/from_user=USUARIO_SIP ; Usuario que saldrá en la cabecera Fromendpoint/from_domain=FQDN_PROVEEDOR ; Dominio SIP del carrier (evita 403)endpoint/allow=!all,ulaw,alaw,g729 ; Incluye g729 si compraste la licencia/códecidentify/endpoint=mi-proveedor-sip ; Vincula la IP de origen con este endpointidentify/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ícitoAquí tienes algunas fuentes útiles para ampliar la configuración: PJSIP Configuration Wizard (Asterisk Docs) y Performance Tuning.
Recarga y verifica registro:
asterisk -rx "pjsip reload"asterisk -rvvv*CLI> pjsip show registrations*CLI> pjsip show endpoint mi-proveedor-sip*CLI> pjsip show identify mi-proveedor-sip-identify7.3 El Dialplan: Rutas de Entrada y Salida
Sección titulada «7.3 El Dialplan: Rutas de Entrada y Salida»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 archivowriteprotect=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 Hangupclearglobalvars=no ; Mantiene las variables globales entre recargas de dialplanpriorityjumping=no ; Recomendado: evita saltos implícitos de prioridad
[globals]IDTRUNK=TU_NUMERO_DID ; Valor que reutilizaremos como CallerID de la troncalCONTEXT_ENTRADAS=from-trunk ; Contexto centralizado para llamadas entrantes
#include extensions_anexos.conf#include extensions_salidas.conf#include extensions_funciones.conf#include extensions_categorias.conf7.3.1 Contexto para Llamadas Entrantes
Sección titulada «7.3.1 Contexto para Llamadas Entrantes»Puedes usar extensions_salidas.conf o crear extensions_entradas.conf.
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-internosinclude => funciones-voicemailinclude => salidas-fijoinclude => salidas-celularinclude => salidas-ldninclude => salidas-ldi
[cat2]include => anexos-internosinclude => funciones-voicemailinclude => salidas-fijoinclude => salidas-celular
[cat3]include => anexos-internosinclude => funciones-voicemailinclude => salidas-celular7.3.3 Recarga y Firewall
Sección titulada «7.3.3 Recarga y Firewall»asterisk -rx "dialplan reload"
# Permite el tráfico desde la IP del proveedorufw allow from IP_PROVEEDOR_SIP to any port 5060 proto udpufw allow from IP_PROVEEDOR_SIP to any port 10000:20000 proto udp7.4 ¡A Probar la Conexión con el Mundo!
Sección titulada «7.4 ¡A Probar la Conexión con el Mundo!»7.4.1 Prueba de Salida
Sección titulada «7.4.1 Prueba de Salida»- Abre el CLI:
asterisk -rvvv. - Desde la extensión
1001(permisocat1), marca un número real. - Observa ejecución de AGI, cambio de CallerID y envío por
mi-proveedor-sip. - Ejecuta
sngreppara validar la señalización. - Comprueba el estado con
pjsip show channelspara ver la llamada activa.
7.4.2 Prueba de Entrada
Sección titulada «7.4.2 Prueba de Entrada»- Desde tu celular, llama a tu DID.
- Observa ingreso en
from-trunky timbrado en1001. - Usa
asterisk -rx "core show channel <canal>"para confirmar códecs y variables. - Verifica que el
endpointcorrecto atiende la llamada conpjsip show channel <ID>.
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»7.5.1 Afinar el desempeño de PJSIP
Sección titulada «7.5.1 Afinar el desempeño de PJSIP»- Threadpool:
asterisk -rx "core show threads"ycore show taskprocessorspara monitorear. - Timers SIP: Ajusta
timer_t1=500,timer_b=32000si tienes retardos. - Sorcery cache: En
sorcery.confusamemory_cacheoredispara cientos de endpoints.
7.5.2 Descriptores de archivo (asterisk.conf)
Sección titulada «7.5.2 Descriptores de archivo (asterisk.conf)»[options]maxfiles = 32768maxload = 5.0corelimit = 1000000- Reinicia Asterisk y verifica con
asterisk -rx "core show settings". - Sincroniza
LimitNOFILEensystemdcreando/etc/systemd/system/asterisk.service.d/limits.conf.
7.5.3 Checklist operativo
Sección titulada «7.5.3 Checklist operativo»- Firewall: Documenta IPs del carrier y automatiza actualizaciones.
- Logs: Configura
logger.confpara canalpjsip_wizard. - Auditoría:
pjsip show historypara limpiar endpoints sin uso.