Comprensione di FreePBX e integrazione con Bitrix24 e altro ancora

Bitrix24 è un'enorme combinazione che combina CRM, flusso di lavoro, contabilità e molte altre cose che piacciono molto ai manager e non piacciono molto al personale IT. Il portale è utilizzato da molte piccole e medie imprese, comprese piccole cliniche, produttori e persino saloni di bellezza. La funzione principale che i manager “adorano” è l'integrazione di telefonia e CRM, quando ogni chiamata viene immediatamente registrata nel CRM, vengono create le schede cliente, quando in arrivo vengono visualizzate le informazioni sul cliente e puoi vedere immediatamente chi è, cosa fa può vendere e quanto deve. Ma la telefonia di Bitrix24 e la sua integrazione con il CRM costa denaro, a volte molto. Nell'articolo ti racconterò l'esperienza dell'integrazione con strumenti aperti e il popolare IP PBX FreePBX, e considera anche la logica del lavoro di varie parti

Lavoro come outsourcer in un'azienda che vende e configura, integra la telefonia IP. Quando mi è stato chiesto se potevamo offrire qualcosa a questa e a questa azienda per integrare Bitrix24 con i PBX che i clienti hanno, così come con i PBX virtuali su varie società VDS, sono andato su Google. E ovviamente mi ha dato un link a articolo in habr, dove c'è una descrizione, e github, e tutto sembra funzionare. Ma durante il tentativo di utilizzare questa soluzione, si è scoperto che Bitrix24 non è più lo stesso di prima e molto deve essere rifatto. Inoltre, FreePBX non è un semplice asterisco per te, qui devi pensare a come combinare facilità d'uso e un dialplan hardcore nei file di configurazione.

Studiamo la logica del lavoro

Quindi, per cominciare, come dovrebbe funzionare tutto. Quando viene ricevuta una chiamata dall'esterno del PBX (evento SIP INVITE dal provider), inizia l'elaborazione del dialplan (dial plan, dialplan): le regole su cosa e in quale ordine fare con la chiamata. Dal primo pacchetto è possibile ottenere molte informazioni, che possono poi essere utilizzate nelle regole. Uno strumento eccellente per studiare l'interno di SIP è l'analizzatore sngrep (collegamento) che viene semplicemente installato nelle distribuzioni più diffuse tramite apt install/yum install e simili, ma può anche essere compilato dal sorgente. Diamo un'occhiata al registro delle chiamate in sngrep

Comprensione di FreePBX e integrazione con Bitrix24 e altro ancora

In una forma semplificata, il dialplan si occupa solo del primo pacchetto, a volte anche durante la conversazione, le chiamate vengono trasferite, le pressioni dei pulsanti (DTMF), varie cose interessanti come FollowMe, RingGroup, IVR e altre.

Cosa c'è nel pacchetto di invito

Comprensione di FreePBX e integrazione con Bitrix24 e altro ancora

In realtà, i dialplan più semplici funzionano con i primi due campi e l'intera logica ruota attorno a DID e CallerID. DID - dove stiamo chiamando, CallerID - chi sta chiamando.

Ma dopotutto, abbiamo un'azienda e non un telefono, il che significa che molto probabilmente il PBX ha gruppi di chiamata (squillo simultaneo / consecutivo di più dispositivi) su numeri di città (Ring Group), IVR (Ciao, hai chiamato ... Premi uno per...), Segreterie (Frasi), Condizioni orarie, Inoltro ad altri numeri o ad un cellulare (FollowMe, Forward). Ciò significa che è molto difficile determinare in modo inequivocabile chi riceverà effettivamente una chiamata e con chi avrà una conversazione quando arriva una chiamata. Ecco un esempio dell'inizio di una tipica chiamata nel PBX dei nostri clienti

Comprensione di FreePBX e integrazione con Bitrix24 e altro ancora

Dopo che la chiamata è entrata correttamente nel PBX, viaggia attraverso il dialplan in diversi "contesti". Il contesto dal punto di vista di Asterisk è un insieme numerato di comandi, ognuno dei quali contiene un filtro per il numero composto (si chiama exten, per una chiamata esterna nella fase iniziale exten=DID). I comandi nella riga del dialplan possono essere qualsiasi cosa - funzioni interne (ad esempio, chiamare un abbonato interno - Dial(), metti giù il telefono - Hangup()), operatori condizionali (IF, ELSE, ExecIF e simili), passaggi ad altre regole di questo contesto (Goto, GotoIF), passaggio ad altri contesti sotto forma di chiamata di funzione (Gosub, Macro). Una direttiva separata include имя_контекста, che aggiunge comandi da un altro contesto alla fine del contesto corrente. I comandi inclusi tramite include vengono sempre eseguiti dopo comandi del contesto corrente.

L'intera logica di FreePBX si basa sull'inclusione di diversi contesti l'uno nell'altro attraverso l'inclusione e la chiamata tramite i gestori Gosub, Macro e Handler. Considera il contesto delle chiamate FreePBX in arrivo

Comprensione di FreePBX e integrazione con Bitrix24 e altro ancora

La chiamata attraversa a turno tutti i contesti dall'alto verso il basso, in ogni contesto possono esserci chiamate ad altri contesti come macro (Macro), funzioni (Gosub) o solo transizioni (Goto), quindi il vero albero di ciò che viene chiamato può solo essere rintracciato nei log.

Di seguito è mostrato un tipico diagramma di configurazione per un tipico PBX. Durante la chiamata, il DID viene cercato nelle rotte in entrata, vengono verificate le condizioni temporanee, se tutto è in ordine, viene avviato il menu vocale. Da essa, premendo il tasto 1 o timeout, si esce al gruppo degli operatori dialing. Al termine della chiamata, viene richiamata la macro hangupcall, dopodiché non è possibile eseguire alcuna operazione nel dialplan, ad eccezione dei gestori speciali (gestore hangup).

Comprensione di FreePBX e integrazione con Bitrix24 e altro ancora

Dove in questo algoritmo di chiamata dovremmo fornire informazioni sull'inizio della chiamata al CRM, dove iniziare la registrazione, dove terminare la registrazione e inviarla insieme alle informazioni sulla chiamata al CRM?

Integrazione con sistemi esterni

Cos'è l'integrazione tra PBX e CRM? Si tratta di impostazioni e programmi che convertono dati ed eventi tra queste due piattaforme e li inviano reciprocamente. Il modo più comune per comunicare tra sistemi indipendenti è tramite le API e il modo più popolare per accedere alle API è HTTP REST. Ma non per l'asterisco.

All'interno dell'asterisco c'è:

  • AGI - chiamata sincrona a programmi / componenti esterni, utilizzata principalmente nel dialplan, ci sono librerie come phpagi, PAGI

  • AMI - un socket TCP di testo che funziona secondo il principio della sottoscrizione di eventi e dell'immissione di comandi di testo, assomiglia a SMTP dall'interno, può tenere traccia degli eventi e gestire le chiamate, esiste una libreria PAMI - il più popolare per creare una connessione con Asterisk

Esempio di output dell'AMI

Evento: Nuovo canale
Privilegio: chiama, tutti
Canale: PJSIP/VMS_pjsip-0000078b
Stato del canale: 4
ChannelStateDesc: suoneria
ID chiamante: 111222
ID chiamanteNome: 111222
NumLineaConnessa:
nome linea connesso:
Lingua: it
Codice dell'account:
Contesto: da-pstn
Estensione: s
Priorità: 1
ID univoco: 1599589046.5244
ID collegato: 1599589046.5244

  • ARI è un misto di entrambi, tutto tramite REST, WebSocket, in formato JSON, ma con nuove librerie e wrapper, non molto buoni, trovati a mano libera (pharia, phpari) che è diventato nel loro sviluppo circa 3 anni fa.

Esempio di output ARI quando viene avviata una chiamata

{ "variable":"CallMeCallerIDName", "value":"111222", "type":"ChannelVarset", "timestamp":"2020-09-09T09:38:36.269+0000", "channel":{ "id »:»1599644315.5334″, «nome»:»PJSIP/VMSpjsip-000007b6″, "state":"Squilla", "caller":{ "name":"111222″, "number":"111222″ }, "connected":{ "name":"", "number" :"" }, "accountcode":"", "dialplan":{ "context":"from-pstn", "exten":"s", "priority":2, "appname":"Stasi", "appdata":"ciao-mondo" }, "creationtime":"2020-09-09T09:38:35.926+0000", "language":"it" }, "asteriscoid":"48:5b:aa:aa:aa:aa", "application":"ciao-mondo" }

La convenienza o l'inconveniente, la possibilità o l'impossibilità di lavorare con una particolare API sono determinate dalle attività che devono essere risolte. Le attività per l'integrazione con il CRM sono le seguenti:

  • Traccia l'inizio della chiamata, dove è stata trasferita, estrai CallerID, DID, ora di inizio e fine, forse dati dalla rubrica (per cercare una connessione tra il telefono e l'utente CRM)

  • Avviare e terminare la registrazione della chiamata, salvarla nel formato desiderato, indicare al termine della registrazione dove si trova il file

  • Avviare una chiamata su un evento esterno (dal programma), chiamare un numero interno, un numero esterno e collegarli

  • Opzionale: integrarsi con CRM, gruppi dialer e FollowME per il trasferimento automatico delle chiamate in assenza di posto (secondo CRM)

Tutte queste attività possono essere risolte tramite AMI o ARI, ma ARI fornisce molte meno informazioni, non ci sono molti eventi, molte variabili che AMI ha ancora (ad esempio, chiamate macro, impostazione di variabili all'interno di macro, inclusa la registrazione delle chiamate) non vengono tracciate. Pertanto, per un tracciamento corretto e accurato, scegliamo AMI per ora (ma non completamente). Inoltre (beh, dove sarebbe senza questo, siamo persone pigre) - nell'opera originale (articolo in habr) usa PAMI. *Quindi devi provare a riscrivere in ARI, ma non il fatto che funzionerà.

Reinventare l'integrazione

Affinché il nostro FreePBX sia in grado di segnalare ad AMI in modo semplice l'inizio della chiamata, l'ora di fine, i numeri, i nomi dei file registrati, è più semplice calcolare la durata della chiamata utilizzando lo stesso trucco degli autori originali - inserisci le tue variabili e analizza l'output per la loro presenza. PAMI suggerisce di farlo semplicemente attraverso una funzione di filtro.

Ecco un esempio di impostazione della propria variabile per l'ora di inizio della chiamata (s è un numero speciale nel dialplan che viene eseguito PRIMA di iniziare la ricerca DID)

[ext-did-custom]

exten => s,1,Set(CallStart=${STRFTIME(epoch,,%s)})

Un esempio di evento AMI per questa linea

Evento: Nuovo canale

Privilegio: chiama, tutti

Canale: PJSIP/VMS_pjsip-0000078b

Stato del canale: 4

ChannelStateDesc: suoneria

ID chiamante: 111222

ID chiamanteNome: 111222

NumLineaConnessa:

nome linea connesso:

Lingua: it

Codice dell'account:

Contesto: da-pstn

Estensione: s

Priorità: 1

ID univoco: 1599589046.5244

ID collegato: 1599589046.5244

Applicazione: Imposta AppData:

Inizio chiamata=1599571046

Perché FreePBX sovrascrive i file extension.conf e extension_additional.conf, useremo il file estensione_costume.conf

Codice completo di extension_custom.conf

[globals]	
;; Проверьте пути и права на папки - юзер asterisk должен иметь права на запись
;; Сюда будет писаться разговоры
WAV=/var/www/html/callme/records/wav 
MP3=/var/www/html/callme/records/mp3

;; По этим путям будет воспроизводится и скачиваться запись
URLRECORDS=https://www.host.ru/callmeplus/records/mp3

;; Адрес для калбека при исходящем вызове
URLPHP=https://www.host.ru/callmeplus

;; Да пишем разговоры
RECORDING=1

;; Это макрос для записи разговоров в нашу папку. 
;; Можно использовать и системную запись, но пока пусть будет эта - 
;; она работает
[recording]
exten => ~~s~~,1,Set(LOCAL(calling)=${ARG1})
exten => ~~s~~,2,Set(LOCAL(called)=${ARG2})
exten => ~~s~~,3,GotoIf($["${RECORDING}" = "1"]?4:14)
exten => ~~s~~,4,Set(fname=${UNIQUEID}-${STRFTIME(${EPOCH},,%Y-%m-%d-%H_%M)}-${calling}-${called})
exten => ~~s~~,5,Set(datedir=${STRFTIME(${EPOCH},,%Y/%m/%d)})
exten => ~~s~~,6,System(mkdir -p ${MP3}/${datedir})
exten => ~~s~~,7,System(mkdir -p ${WAV}/${datedir})
exten => ~~s~~,8,Set(monopt=nice -n 19 /usr/bin/lame -b 32  --silent "${WAV}/${datedir}/${fname}.wav"  "${MP3}/${datedir}/${fname}.mp3" && rm -f "${WAV}/${fname}.wav" && chmod o+r "${MP3}/${datedir}/${fname}.mp3")
exten => ~~s~~,9,Set(FullFname=${URLRECORDS}/${datedir}/${fname}.mp3)
exten => ~~s~~,10,Set(CDR(filename)=${fname}.mp3)
exten => ~~s~~,11,Set(CDR(recordingfile)=${fname}.wav)
exten => ~~s~~,12,Set(CDR(realdst)=${called})
exten => ~~s~~,13,MixMonitor(${WAV}/${datedir}/${fname}.wav,b,${monopt})
exten => ~~s~~,14,NoOp(Finish if_recording_1)
exten => ~~s~~,15,Return()


;; Это основной контекст для начала разговора
[ext-did-custom]

;; Это хулиганство, делать это так и здесь, но работает - добавляем к номеру '8'
exten =>  s,1,Set(CALLERID(num)=8${CALLERID(num)})

;; Тут всякие переменные для скрипта
exten =>  s,n,Gosub(recording,~~s~~,1(${CALLERID(number)},${EXTEN}))
exten =>  s,n,ExecIF(${CallMeCallerIDName}?Set(CALLERID(name)=${CallMeCallerIDName}):NoOp())
exten =>  s,n,Set(CallStart=${STRFTIME(epoch,,%s)})
exten =>  s,n,Set(CallMeDISPOSITION=${CDR(disposition)})

;; Самое главное! Обработчик окончания разговора. 
;; Обычные пути обработки конца через (exten=>h,1,чтототут) в FreePBX не работают - Macro(hangupcall,) все портит. 
;; Поэтому вешаем Hangup_Handler на окончание звонка
exten => s,n,Set(CHANNEL(hangup_handler_push)=sub-call-from-cid-ended,s,1(${CALLERID(num)},${EXTEN}))

;; Обработчик окончания входящего вызова
[sub-call-from-cid-ended]

;; Сообщаем о значениях при конце звонка
exten => s,1,Set(CDR_PROP(disable)=true)
exten => s,n,Set(CallStop=${STRFTIME(epoch,,%s)})
exten => s,n,Set(CallMeDURATION=${MATH(${CallStop}-${CallStart},int)})

;; Статус вызова - Ответ, не ответ...
exten => s,n,Set(CallMeDISPOSITION=${CDR(disposition)})
exten => s,n,Return


;; Обработчик исходящих вызовов - все аналогичено
[outbound-allroutes-custom]

;; Запись
exten => _.,1,Gosub(recording,~~s~~,1(${CALLERID(number)},${EXTEN}))
;; Переменные
exten => _.,n,Set(__CallIntNum=${CALLERID(num)})
exten => _.,n,Set(CallExtNum=${EXTEN})
exten => _.,n,Set(CallStart=${STRFTIME(epoch,,%s)})
exten => _.,n,Set(CallmeCALLID=${SIPCALLID})

;; Вешаем Hangup_Handler на окончание звонка
exten => _.,n,Set(CHANNEL(hangup_handler_push)=sub-call-internal-ended,s,1(${CALLERID(num)},${EXTEN}))

;; Обработчик окончания исходящего вызова
[sub-call-internal-ended]

;; переменные
exten => s,1,Set(CDR_PROP(disable)=true)
exten => s,n,Set(CallStop=${STRFTIME(epoch,,%s)})
exten => s,n,Set(CallMeDURATION=${MATH(${CallStop}-${CallStart},int)})
exten => s,n,Set(CallMeDISPOSITION=${CDR(disposition)})

;; Вызов скрипта, который сообщит о звонке в CRM - это исходящий, 
;; так что по факту окончания
exten => s,n,System(curl -s ${URLPHP}/CallMeOut.php --data action=sendcall2b24 --data ExtNum=${CallExtNum} --data call_id=${SIPCALLID} --data-urlencode FullFname='${FullFname}' --data CallIntNum=${CallIntNum} --data CallDuration=${CallMeDURATION} --data-urlencode CallDisposition='${CallMeDISPOSITION}')
exten => s,n,Return

Caratteristica e differenza rispetto al dialplan originale degli autori dell'articolo originale -

  • Dialplan in formato .conf, come lo vuole FreePBX (sì, può .ael, ma non tutte le versioni e non sempre è conveniente)

  • Invece di elaborare la fine tramite exten=>h, l'elaborazione è stata introdotta tramite hangup_handler, perché il dialplan FreePBX funzionava solo con esso

  • Risolto il problema con la stringa di chiamata dello script, aggiunte virgolette e numero di chiamata esterno ExtNum

  • L'elaborazione viene spostata in _contesti personalizzati e consente di non toccare o modificare le configurazioni FreePBX - in entrata tramite [ext-ha-custom], in uscita attraverso [outbound-allroutes-custom]

  • Nessun legame con i numeri: il file è universale e deve essere configurato solo per il percorso e il collegamento al server

Per iniziare, devi anche eseguire gli script nell'AMI tramite login e password: per questo, FreePBX ha anche un file _custom

file manager_custom.conf

;;  это логин
[callmeplus]
;; это пароль
secret = trampampamturlala
deny = 0.0.0.0/0.0.0.0

;; я работаю с локальной машиной - но если надо, можно и другие прописать
permit = 127.0.0.1/255.255.255.255
read = system,call,log,verbose,agent,user,config,dtmf,reporting,cdr,dialplan
write = system,call,agent,log,verbose,user,config,command,reporting,originate

Entrambi questi file devono essere inseriti in /etc/asterisk, quindi rileggere le configurazioni (o riavviare l'asterisco)

# astrisk -rv
  Connected to Asterisk 16.6.2 currently running on freepbx (pid = 31629)
#freepbx*CLI> dialplan reload
     Dialplan reloaded.
#freepbx*CLI> exit

Ora passiamo a PHP

Inizializzazione degli script e creazione di un servizio

Poiché lo schema per lavorare con Bitrix 24, un servizio per AMI, non è del tutto semplice e trasparente, deve essere discusso separatamente. Asterisk, quando l'AMI è attivata, apre semplicemente la porta e il gioco è fatto. Quando un client si unisce, richiede l'autorizzazione, quindi il client si iscrive agli eventi necessari. Gli eventi sono in testo normale, che PAMI converte in oggetti strutturati e fornisce la possibilità di impostare la funzione di filtro solo per eventi di interesse, campi, numeri, ecc.

Non appena arriva la chiamata, l'evento NewExten viene attivato a partire dal contesto genitore [from-pstn], quindi tutti gli eventi vanno nell'ordine delle righe nei contesti. Quando le informazioni vengono ricevute dalle variabili CallMeCallerIDName e CallStart specificate nel dialplan _custom, il

  1. La funzione di richiesta della UserID corrispondente al numero di interno da cui è arrivata la chiamata. E se si tratta di un gruppo dial-up? La domanda è politica, devi creare una chiamata a tutti in una volta (quando tutti chiamano contemporaneamente) o creare mentre chiamano quando chiamano a turno? La maggior parte dei clienti ha la strategia First Available, quindi non ci sono problemi con questo, solo uno chiama. Ma la questione deve essere risolta.

  2. La funzione di registrazione della chiamata in Bitrix24, che restituisce il CallID, a cui poi viene richiesto di riportare i parametri della chiamata e un link alla registrazione. Richiede il numero di interno o l'ID utente

Comprensione di FreePBX e integrazione con Bitrix24 e altro ancora

Al termine della chiamata viene richiamata la funzione di download del record, che riporta contemporaneamente lo stato di completamento della chiamata (Occupato, Nessuna risposta, Successo) e scarica anche un collegamento al file mp3 con il record (se presente).

Poiché il modulo CallMeIn.php deve essere eseguito continuamente, è stato creato per esso un file di avvio SystemD chiamami.servizio, che deve essere inserito in /etc/systemd/system/callme.service

[Unit]
Description=CallMe

[Service]
WorkingDirectory=/var/www/html/callmeplus
ExecStart=/usr/bin/php /var/www/html/callmeplus/CallMeIn.php 2>&1 >>/var/log/callmeplus.log
ExecStop=/bin/kill -WINCH ${MAINPID}
KillSignal=SIGKILL

Restart=on-failure
RestartSec=10s

#тут надо смотреть,какие права на папки
#User=www-data  #Ubuntu - debian
#User=nginx #Centos

[Install]
WantedBy=multi-user.target

l'inizializzazione e l'avvio dello script avviene tramite systemctl o service

# systemctl enable callme
# systemctl start callme

Il servizio si riavvierà automaticamente se necessario (in caso di arresti anomali). Il servizio di monitoraggio della posta in arrivo non richiede l'installazione di un server Web, è necessario solo php (che è sicuramente sul server FeePBX). Ma in assenza di accesso ai record delle chiamate tramite il Web server (anche con https), non sarà possibile ascoltare i record delle chiamate.

Ora parliamo di chiamate in uscita. Lo script CallMeOut.php ha due funzioni:

  • Avvio di una chiamata quando viene ricevuta una richiesta per uno script php (incluso l'utilizzo del pulsante "Chiama" nel Bitrix stesso). Non funziona senza un server web, la richiesta viene ricevuta tramite HTTP POST, la richiesta contiene un token

  • Messaggio sulla chiamata, i suoi parametri e record in Bitrix. Attivato da Asterisk nel dialplan [sub-call-internal-ended] al termine di una chiamata

Comprensione di FreePBX e integrazione con Bitrix24 e altro ancora

Il server Web è necessario solo per due cose: scaricare i file di record Bitrix (tramite HTTPS) e chiamare lo script CallMeOut.php. È possibile utilizzare il server FreePBX integrato, i cui file sono /var/www/html, è possibile installare un altro server o specificare un percorso diverso.

server web

Lasciamo la configurazione del server web per uno studio indipendente (tyts, tyts, tyts). Se non hai un dominio, puoi provare FreeDomain( https://www.freenom.com/ru/index.html), che ti darà un nome gratuito per il tuo IP bianco (non dimenticare di inoltrare le porte 80, 443 attraverso il router se l'indirizzo esterno è solo su di esso). Se hai appena creato un dominio DNS, devi attendere (da 15 minuti a 48 ore) fino a quando tutti i server non vengono caricati. Secondo l'esperienza di lavoro con fornitori nazionali - da 1 ora a un giorno.

Automazione dell'installazione

Un programma di installazione è stato sviluppato su github per rendere l'installazione ancora più semplice. Ma sulla carta è andato liscio, mentre lo installiamo tutto manualmente, poiché dopo aver armeggiato con tutto questo è diventato chiarissimo cos'è l'amico con chi, chi va dove e come eseguire il debug. Non c'è ancora nessun programma di installazione

docker

Se vuoi provare rapidamente la soluzione - c'è un'opzione con Docker - crea rapidamente un contenitore, dagli le porte all'esterno, sposta i file delle impostazioni e prova (questa è l'opzione con il contenitore LetsEncrypt, se hai già un certificato , devi solo reindirizzare il proxy inverso al server Web FreePBX (gli abbiamo dato un'altra porta è 88), LetsEncrypt nella finestra mobile in base a questo articolo

Devi eseguire il file nella cartella del progetto scaricato (dopo git clone), ma prima entra nelle configurazioni dell'asterisco (cartella dell'asterisco) e scrivi lì i percorsi dei record e l'URL del tuo sito

version: '3.3'
services:
  nginx:
    image: nginx:1.15-alpine
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx/ssl_docker.conf:/etc/nginx/conf.d/ssl_docker.conf
  certbot:
    image: certbot/certbot
  freepbx:
    image: flaviostutz/freepbx
    ports:
      - 88:80 # для настройки
      - 5060:5060/udp
      - 5160:5160/udp
      - 127.0.0.1:5038:5038 # для CallMeOut.php
#      - 3306:3306
      - 18000-18100:18000-18100/udp
    restart: always
    environment:
      - ADMIN_PASSWORD=admin123
    volumes:
      - backup:/backup
      - recordings:/var/spool/asterisk/monitor
      - ./callme:/var/www/html/callme
      - ./systemd/callme.service:/etc/systemd/system/callme.conf
      - ./asterisk/manager_custom.conf:/etc/asterisk/manager_custom.conf
      - ./asterisk/extensions_custom.conf:/etc/asterisk/extensions_custom.conf
#      - ./conf/startup.sh:/startup.sh

volumes:
  backup:
  recordings:

Questo file docker-compose.yaml viene eseguito tramite

docker-compose up -d

Se nginx non si avvia, c'è qualcosa che non va nella configurazione nella cartella nginx/ssl_docker.conf

Altre integrazioni

E perché non inserire un po' di CRM negli script allo stesso tempo, abbiamo pensato. Abbiamo studiato diverse altre API CRM, in particolare il PBX integrato gratuito: ShugarCRM e Vtiger, e sì! si, il principio è lo stesso. Ma questa è un'altra storia, che in seguito caricheremo separatamente su github.

riferimenti

Disclaimer: qualsiasi somiglianza con la realtà è fittizia e non sono stato io.

Fonte: habr.com

Aggiungi un commento