Analizăm FreePBX și îl integrăm cu Bitrix24 și nu numai

Bitrix24 — este un amalgam uriaș care combină atât CRM cât și gestionarea documentelor, contabilitatea și multe alte funcții care plac foarte mult managerilor și nu prea personalului IT. Portalul este utilizat de foarte multe companii mici și mijlocii, inclusiv clinici mici, producători și chiar saloane de înfrumusețare. Funcția principală pe care managerii o "îndrăgesc" este integrarea telefoniei cu CRM, când fiecare apel este înregistrat imediat în CRM, se creează fișe pentru clienți, iar la un apel incoming se afișează informații despre client și se poate vedea imediat cine este, ce poate fi vândut și cât datorie are. Dar telefonia de la Bitrix24 și integrarea sa cu CRM costă bani, uneori mulți. În acest articol voi povesti despre experiența integrării cu instrumente open-source și cu populara IP PBX FreePBX, și voi analiza logica funcționării diferitelor părți

Lucrez în outsourcing pentru o companie care se ocupă cu vânzarea, configurarea și integrarea telefoniei IP. Când m-au întrebat dacă putem propune acelei companii ceva pentru integrarea Bitrix24 cu PBX-urile pe care le au clienții, precum și cu PBX-uri virtuale pe diferite VDS ale companiei, am început să caut pe Google. Și, desigur, acesta mi-a oferit un link către un articol pe Habr, care conține atât descriere, cât și github, și se pare că totul funcționează. Dar, la încercarea de a folosi această soluție, am descoperit că Bitrix24 nu mai este la fel ca înainte și trebuie refăcut multe. În plus, FreePBX nu este un simplu Asterisk, aici trebuie să gândești cum să combine confortul utilizării cu un dialplan complex în fișierele de configurare.

Studiem logica funcționării

Așadar, să vedem cum ar trebui să funcționeze totul. La primirea unui apel extern în PBX (eveniment SIP INVITE de la furnizor) începe procesarea dialplan-ului — regulile pentru ce și în ce ordine să facem cu apelul. Din primul pachet se pot obține multe informații care pot fi folosite ulterior în reguli. Un instrument excelent pentru studierea detaliilor SIP este analizatorul sngrep (linkul) care se instalează ușor în distribuții populare prin apt install/yum install și altele, dar poate fi compilat și din surse. Să ne uităm la log-ul apelului în sngrep

Analizăm FreePBX și îl integrăm cu Bitrix24 și nu numai

În termeni simpli, diagrama de apeluri se ocupă în principal de primul pachet, iar uneori, în timpul apelului, se efectuează transferuri de apeluri, apăsări de butoane (DTMF) și diverse caracteristici precum FollowMe, RingGroup, IVR și altele.

Ce este inclus în pachetul Invite

Analizăm FreePBX și îl integrăm cu Bitrix24 și nu numai

În esență, majoritatea diagramelor de apeluri funcționează cu primele două câmpuri, iar toată logica se învârte în jurul DID și CallerID. DID - unde sunăm, CallerID - cine sună.

Dar avem o firmă și nu doar un telefon - ceea ce înseamnă că în sistemul PBX există probabil grupuri de apeluri (apeluri simultane/secuențiale la mai multe aparate) pe numerele de telefon fixe (Ring Group), IVR (Bună ziua, ați sunat la... Apăsați unu pentru...), mesaje vocale (Phrases), condiții temporale (Time Conditions), redirecționare către alte numere sau către un telefon mobil (FollowMe, Forward). Asta înseamnă că este foarte greu să se determine exact cui va ajunge apelul și cu cine va avea loc conversația odată ce apelul este primit. Iată un exemplu de început al unui apel tipic în sistemul PBX al clienților noștri.

Analizăm FreePBX și îl integrăm cu Bitrix24 și nu numai

După ce apelul intră cu succes în PBX, acesta călătorește prin diagrama de apeluri în diferite „contexte”. Contextul, din perspectiva Asterisk, este un set numerotat de comenzi, fiecare dintre ele conținând un filtru pentru numărul compus (numit exten, pentru apelul extern la etapa inițială exten=DID). Comenzile din linia diagramei de apeluri pot fi orice - funcții interne (de exemplu, a suna un abonat intern - Dial(), a închide apelul - Hangup()), operatori condiționali (IF, ELSE, ExecIF și similare), tranziții către alte reguli din acest context (Goto, GotoIF), tranziții către alte contexte sub formă de apeluri de funcții (Gosub, Macro). În mod special, directivele include nume_context, adaugă comenzi din alt context la sfârșitul contextului curent. Comenzile incluse prin include sunt întotdeauna executate după de către comenzile contextului curent.

Toată logica de funcționare a FreePBX se bazează pe includerea unii în altele a diferitelor contexte prin include și apeluri prin Gosub, Macro și gestionare Handler. Să analizăm contextul apelurilor primite în FreePBX.

Analizăm FreePBX și îl integrăm cu Bitrix24 și nu numai

Apelul trece prin toate contextele de sus în jos, în ordinea lor, în fiecare context pot exista apeluri către alte contexte sub formă de macro-uri (Macro), funcții (Gosub) sau tranziții simple (Goto), de aceea arborele real al ceea ce este apelat poate fi urmărit doar în jurnale.

Schema standard de configurare a unei centrale telefonice tipice de birou este prezentată mai jos. La apel, în rutele de intrare se caută DID, se verifică condițiile temporale, iar dacă totul este în regulă — se pornește meniul vocal. Din acesta, prin apăsarea tastei 1 sau prin expirarea timpului, se ajunge la grupul de operatori. După încheierea apelului, se apelează macro-ul hangupcall, după care nu se va putea executa nimic altceva în diagrama de apel, cu excepția handler-elor speciale (hangup handler).

Analizăm FreePBX și îl integrăm cu Bitrix24 și nu numai

Unde în acest algoritm al apelului ar trebui să furnizăm informațiile despre începutul apelului în CRM, unde să începem înregistrarea, unde să încheiem înregistrarea și să o trimitem împreună cu informațiile despre apel către CRM?

Integrarea cu sisteme externe

Ce este integrarea dintre centrală și CRM? Acesta este setările și programele care convertesc datele și evenimentele între aceste două platforme și le transmit reciproc. Cea mai comună metodă de interacțiune a sistemelor independente este API-ul, iar cea mai populară metodă de acces la API este HTTP REST. Dar nu pentru Asterisk.

În interiorul Asterisk există:

  • AGI — apel sincron al programelor/componenților externe, utilizat în principal în diagrama de apel, există biblioteci precum phpagi, PAGI

  • AMI — un socket TCP text, care funcționează pe baza principiului de abonare la evenimente și introducerea de comenzi text, seamănă cu SMTP din interior, poate urmări evenimentele și gestiona apelurile, există biblioteca PAMI — cea mai populară pentru crearea unei legături cu Asterisk

Exemplu de ieșire AMI

Event: Newchannel
Privilege: call,all
Channel: PJSIP/VMS_pjsip-0000078b
ChannelState: 4
ChannelStateDesc: Ring
CallerIDNum: 111222
CallerIDName: 111222
ConnectedLineNum:
ConnectedLineName:
Language: en
AccountCode:
Context: from-pstn
Exten: s
Priority: 1
Uniqueid: 1599589046.5244
Linkedid: 1599589046.5244

  • ARI — o combinație a celor două, totul prin REST, WebSocket, în format JSON — dar cu biblioteci și wrapper-uri recente nu este foarte bine, la o primă vedere au fost găsite (phparia, phpari) care s-au oprit în dezvoltarea lor acum 3 ani.

Exemplu de ieșire ARI la inițierea apelului

{ "variable":"CallMeCallerIDName", "value":"111222", "type":"ChannelVarset", "timestamp":"2020-09-09T09:38:36.269+0000", "channel":{ "id":"1599644315.5334", "name":"PJSIP/VMS_pjsip-000007b6", "state":"Ring", "caller":{ "name":"111222", "number":"111222" }, "connected":{ "name":"", "number":"" }, "accountcode":"", "dialplan":{"context":"from-pstn", "exten":"s", "priority":2, "app""name":"Stasis", "app""data":"hello-world" }, "creationtime":"2020-09-09T09:38:35.926+0000", "language":"ru" }, "asterisk"id":"48:5b:aa:aa:aa:aa", "application":"hello-world" }id": "48:5b:aa:aa:aa:aa", "application": "hello-world" }

Conveniență sau inconvenient, posibilitate sau imposibilitate de a lucra cu anumite API-uri sunt determinate de sarcinile care trebuie rezolvate. Sarcinile pentru integrarea cu CRM sunt următoarele:

  • Urmăriți începutul apelului, unde a fost redirecționat, extrageți CallerID, DID, timpii de început și sfârșit, poate fi date din director (pentru a găsi legătura dintre telefon și utilizatorul CRM)

  • Începeți și terminați înregistrarea apelului, salvați în formatul necesar, informați la sfârșitul înregistrării unde se află fișierul

  • Inițiați un apel printr-un eveniment extern (din program), sunați un număr intern, extern și conectați-le

  • Opțional: integrați cu CRM, grupuri de apel și FollowME pentru a redirecționa automat apelurile în absență (pe baza informațiilor CRM)

Toate aceste sarcini pot fi rezolvate prin AMI sau ARI, dar ARI oferă mult mai puține informații, nu sunt urmărite multe evenimente și variabile care există în AMI (de exemplu, apeluri de macrocomenzi, setarea variabilelor în interiorul macrocomenzilor, inclusiv înregistrarea apelurilor). Prin urmare, pentru o urmărire corectă și precisă — să alegem deocamdată AMI (dar nu definitiv). În plus (dar la ce ne-ar ajuta, suntem oameni leneși) — în munca inițială (articol pe Habr) folosesc PAMI. *Apoi trebuie să încercăm să rescriem pe ARI, dar nu este sigur că va reuși.

Inventăm integrarea de la zero

Pentru ca FreePBX-ul nostru să poată comunica în AMI în moduri simple despre începutul apelului, timpul de încheiere, numerele, numele fișierelor înregistrate, calcularea duratei apelului este cel mai simplu să folosim aceeași metodă ca și autorii inițiali — introduceți propriile variabile și analizați ieșirea pentru prezența lor. PAMI oferă să faceți aceasta pur și simplu printr-o funcție-filtru.

Iată un exemplu de setare a propriei variabile pentru timpul de început al apelului (s — acesta este un număr special în planul de apel, care se execută ÎNAINTE de începerea căutării pe DID)

[ext-did-custom]

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

Exemplu de eveniment AMI pentru această linie

Event: Newchannel

Privilege: call,all

Channel: PJSIP/VMS_pjsip-0000078b

ChannelState: 4

ChannelStateDesc: Ring

CallerIDNum: 111222

CallerIDName: 111222

ConnectedLineNum:

ConnectedLineName:

Language: en

AccountCode:

Context: from-pstn

Exten: s

Priority: 1

Uniqueid: 1599589046.5244

Linkedid: 1599589046.5244

Aplicație: Set AppData:

CallStart=1599571046

Dat fiind că FreePBX rescrie fișierele extention.conf și extention_additional.conf, vom folosi fișierul extention_custom.conf

Codul complet extention_custom.conf

[globals]	
;; Verificați căile și permisiunile pentru foldere - utilizatorul asterisk trebuie să aibă drepturi de scriere
;; Aici vor fi salvate convorbirile
WAV=\/var\/www\/html\/callme\/records\/wav 
MP3=\/var\/www\/html\/callme\/records\/mp3

;; Convorbirile vor fi redate și descărcate de la aceste căi
URLRECORDS=https:\/\/www.host.ru\/callmeplus\/records\/mp3

;; Adresa pentru callback la apelurile externe
URLPHP=https:\/\/www.host.ru\/callmeplus

;; Da, înregistrăm convorbirile
RECORDING=1

;; Acesta este un macro pentru înregistrarea convorbirilor în folderul nostru.
;; Se poate folosi și înregistrarea sistemică, dar deocamdată să rămână aceasta - 
;; funcționează
[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()


;; Acesta este contextul principal pentru începerea convorbirii
[ext-did-custom]

;; Este o prostie să facem asta așa aici, dar funcționează - adăugăm '8' la număr
exten =>  s,1,Set(CALLERID(num)=8${CALLERID(num)})

;; Aici sunt diverse variabile pentru script
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)})

;; Cel mai important! Handler-ul pentru sfârșitul convorbirii.
;; Cărțile obișnuite de procesare a încheierii prin (exten=>h,1,ceva) în FreePBX nu funcționează - Macro(hangupcall,) strică tot.
;; Așadar, atașăm Hangup_Handler la terminarea apelului
exten => s,n,Set(CHANNEL(hangup_handler_push)=sub-call-from-cid-ended,s,1(${CALLERID(num)},${EXTEN}))

;; Handler-ul pentru încheierea apelului primit
[sub-call-from-cid-ended]

;; Informăm despre valori la sfârșitul apelului
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)})

;; Statutul apelului - Răspuns, ne-răspuns...
exten => s,n,Set(CallMeDISPOSITION=${CDR(disposition)})
exten => s,n,Return


;; Handler pentru apeluri externe - totul este similar
[outbound-allroutes-custom]

;; Înregistrare
exten => _.,1,Gosub(recording,~~s~~,1(${CALLERID(number)},${EXTEN}))
;; Variabile
exten => _.,n,Set(__CallIntNum=${CALLERID(num)})
exten => _.,n,Set(CallExtNum=${EXTEN})
exten => _.,n,Set(CallStart=${STRFTIME(epoch,,%s)})
exten => _.,n,Set(CallmeCALLID=${SIPCALLID})

;; Atașăm Hangup_Handler la terminarea apelului
exten => _.,n,Set(CHANNEL(hangup_handler_push)=sub-call-internal-ended,s,1(${CALLERID(num)},${EXTEN}))

;; Handler-ul pentru încheierea apelului extern
[sub-call-internal-ended]

;; variabile
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)})

;; Apelăm scriptul, care va raporta apelul în CRM - acesta este extern, 
;; deci, la sfârșit
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

Caracteristica și diferența față de planul de apel original al autorilor articolului inițial —

  • Planul de apel în format .conf, așa cum dorește FreePBX (da, acesta acceptă .ael, dar nu toate versiunile și nu întotdeauna este convenabil)

  • În loc de procesarea sfârșitului prin exten=>h, a fost introdusă procesarea prin hangup_handler, deoarece planul de apel FreePBX a funcționat doar cu acesta

  • Linia de apel a scriptului a fost corectată, au fost adăugate ghilimele și numărul extern de apel ExtNum

  • Procesele au fost scoase în contexte _custom și permit să nu se atingă și să nu se modifice configurațiile FreePBX — apelurile de intrare prin [ext-did-custom], apelurile de ieșire prin [outbound-allroutes-custom]

  • Nu există legături cu numere - fișierul este universal și necesită configurarea doar a căii și a referinței la server

Pentru a începe lucrul, trebuie să permiteți scripturilor în AMI prin login și parolă — pentru aceasta, în FreePBX există de asemenea un fișier _custom

Fișierul manager_custom.conf

;;  acesta este loginul
[callmeplus]
;; acesta este parola
secret = trampampamturlala
deny = 0.0.0.0/0.0.0.0

;; lucrez cu mașina locală - dar dacă este necesar, se pot introduce și altele
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

Ambele fișiere trebuie plasate în /etc/asterisk, apoi să se citească din nou configurațiile (sau să se repornească asterisk-ul)

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

Acum să trecem la PHP

Inițializarea scripturilor și crearea serviciului

Deoarece schema de lucru cu Bitrix 24, serviciul pentru AMI nu este foarte simplă și transparentă, trebuie să ne oprim asupra ei în mod separat. Asterisk, la activarea AMI, pur și simplu deschide un port și atât. La conectarea unui client, se solicită autorizarea, apoi clientul se abonează la evenimentele dorite. Evenimentele vin sub formă de text simplu, pe care PAMI le transformă în obiecte structurate și oferă posibilitatea de a defini funcția de filtrare doar pentru evenimentele de interes, câmpuri, numere etc.

De îndată ce apelul este primit, apare evenimentul NewExten începând cu contextul părinte [from-pstn], apoi urmează toate evenimentele în ordinea în care sunt prezentate liniile în contexte. La primirea informațiilor din variabilele de tip _custom CallMeCallerIDName și CallStart definite în planul de apel, se face apel.

  1. Funcția de solicitare UserID, corespunzătoare numărului intern la care a venit apelul. Dar ce se întâmplă dacă este un grup de apeluri? Aceasta este o întrebare politică; trebuie să creăm un apel către toți simultan (când sună toți în același timp) sau să creăm pe măsură ce sună în ordine? Majoritatea clienților au strategia Fisrt Available, așa că nu sunt probleme în acest sens, sună doar unul. Dar trebuie să rezolvăm această problemă.

  2. Funcția de înregistrare a apelurilor în Bitrix24, care returnează CallID, necesar ulterior pentru a comunica parametrii apelului și linkul pentru înregistrare. Necesită fie numărul intern, fie UserID.

Analizăm FreePBX și îl integrăm cu Bitrix24 și nu numai

După terminarea apelului, se apelează funcția de încărcare a înregistrării, care informează simultan despre statusul finalizării apelului (Ocupat, Fără răspuns, Succes), precum și încarcă linkul la fișierul mp3 cu înregistrarea (dacă există).

Deoarece modulul CallMeIn.php trebuie să funcționeze continuu, a fost creat un fișier SystemD pentru pornire. callme.service, care trebuie plasat în /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

#aici trebuie să ne uităm ce drepturi au folderele
#User=www-data  #Ubuntu - debian
#User=nginx #Centos

[Install]
WantedBy=multi-user.target

inițializarea și lansarea scriptului se face prin systemctl sau service.

# systemctl enable callme
# systemctl start callme

Serviciul se va reporni singur dacă este necesar (în caz de prăbușire). Serviciul de monitorizare a apelurilor incoming nu require instalarea unui server web, este necesar doar php (care cu siguranță există pe serverul FeePBX). Dar în absența accesului la înregistrările apelurilor prin serverul web (încă și cu https) nu va fi posibil să ascultăm înregistrările convorbirilor.

Acum să discutăm despre apelurile externe. Scriptul CallMeOut.php are două funcții:

  • Inițierea apelului la primirea unei solicitări pentru scriptul php (inclusiv prin butonul „Sunați” în Bitrix). Fără server web nu funcționează, solicitările vin prin HTTP POST, în solicitare se află un token.

  • Mesajul despre apel, parametrii săi și înregistrările în Bitrix. Acesta se desfășoară la inițiativa Asterisk în dialplan [sub-call-internal-ended] la finalizarea apelului.

Analizăm FreePBX și îl integrăm cu Bitrix24 și nu numai

Serverul web este necesar doar pentru două lucruri - încărcarea fișierelor înregistrărilor de către Bitrix (prin HTTPS) și apelarea scriptului CallMeOut.php. Se poate folosi serverul încorporat FreePBX, fișierele pentru care se află în /var/www/html, se poate instala un alt server sau se poate specifica un alt drum.

Server web

Vom lăsa configurarea serverului web pe seama studiului individual (clic, clic, clic). Dacă nu aveți un domeniu, puteți încerca FreeDomain( https://www.freenom.com/ru/index.html), care vă va oferi gratuit un nume pentru IP-ul dvs. public (nu uitați să redirecționați porturile 80, 443 prin router, dacă adresa externă este disponibilă doar pe acesta). Dacă ați creat recent un domeniu DNS, trebuie să așteptați (între 15 minute și 48 de ore) până când toate serverele se vor actualiza. Din experiența cu furnizorii locali — de la 1 oră la o zi.

Automatizarea instalării

Pe GitHub a început dezvoltarea unui installer, pentru a putea fi instalat și mai ușor. Dar a fost ușor doar pe hârtie — deocamdată instalăm totul manual, însă, după câteva încercări, a devenit evident cine se integrează cu cine, unde își desfășoară activitatea și cum se debugează. Installerul nu este disponibil încă (

Docker

Dacă doriți să încercați rapid soluția — există o opțiune cu Docker — creați rapid un container, expunându-i porturile, adăugați fișierele de configurare și testați (aceasta este opțiunea cu containerul LetsEncrypt, dacă certificatul există deja, trebuie doar să redirecționați proxy-ul invers către serverul web FreePBX (lui i-am alocat un alt port — 88), LetsEncrypt în Docker pe baza acestui articol

Trebuie să rulați fișierul în folderul descărcat al proiectului (după git clone), dar înainte trebuie să verificați configurațiile Asterisk (folderul asterisk) și să specificați acolo căile către înregistrări și URL-ul site-ului dvs.

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 # pentru configurare
      - 5060:5060\/udp
      - 5160:5160\/udp
      - 127.0.0.1:5038:5038 # pentru 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:

Acest fișier docker-compose.yaml se rulează prin

docker-compose up -d

Dacă nginx nu a pornit, înseamnă că ceva nu este în regulă cu configurația din folderul nginx\/ssl_docker.conf

Alte integrații

Și de ce să nu încercăm să includem câteva CRM-uri în scripturi, ne-am gândit. Am studiat câteva API-uri ale altor CRM-uri, în special gratis, încorporate în anumite centrale telefonice — ShugarCRM și Vtiger, și da! se poate, principiul este același. Dar aceasta este o altă poveste, pe care o vom încărca pe GitHub separat.

Linkuri

Declinarea responsabilității: orice asemănări cu realitatea sunt fictive și nu eu sunt responsabil pentru asta,

Sursa: habr.com

Cumpără un hosting fiabil pentru site-uri cu protecție DDoS, servere VPS VDS 🔥 Cumpără un hosting fiabil pentru site-uri cu protecție DDoS, servere VPS VDS | ProHoster