Let’s explore FreePBX and integrate it with Bitrix24 and beyond

Bitrix24 — je velikanska platforma, ki združuje CRM, upravljanje dokumentov, evidenco in še mnoge druge stvari, ki so zelo privlačne za menedžerje in manj za IT osebje. Portal uporabljajo številna mala in srednje velika podjetja, vključno z manjšimi klinikami, proizvajalci in celo frizerskimi saloni. Glavna funkcija, ki jo menedžerji najbolj 'ljubijo', je integracija telefonije in CRM, kjer se vsak klic takoj zabeleži v CRM, ustvarijo se kartice strank, ob vhodnem klicu pa se prikažejo informacije o stranki in takoj je jasno, kdo je, kaj mu lahko prodamo in koliko dolguje. Vendar pa integracija telefonije iz Bitrix24 in njena povezava s CRM stanejo denar, včasih kar precejšnjo vsoto. V članku bom delil izkušnje integracije z odprtimi orodji in priljubljeno IP PBX. FreePBX, ter preučil logiko delovanja različnih delov.

Delam na zunanjih projektih v podjetju, ki se ukvarja s prodajo in nastavitvijo IP telefonije. Ko so me vprašali, ali lahko tistem in onem podjetju ponudimo nekaj za integracijo Bitrix24 s PBX-om, ki ga imajo stranke, ter z virtualnimi PBX-ji na različnih VDS podjetja, sem se obrnil na Googla. Seveda mi je prikazal povezavo do članka na Habr, kjer so opisani postopki, github, in vse naj bi delovalo. Vendar pa je med poskusom uporabe te rešitve prišlo do zavedanja, da Bitrix24 ni več tak, kot je bil prej, in da je potrebno veliko stvari ponovno prilagoditi. Poleg tega FreePBX ni običajni Asterisk, tukaj je potrebno razmišljati, kako uskladiti enostavnost uporabe in zapleteno strukturo dialplanov v konfiguracijskih datotekah.

Preučuję logiko delovanja

Torej, za začetek, kako naj bi vse to delovalo. Ob prejemu klica od zunaj na PBX (dogodek SIP INVITE od ponudnika) se začne obdelava diagrama klicev (dialplan) — pravil, kaj in v kakšnem vrstnem redu naj se naredi s klicem. Iz prvega paketa lahko pridobimo veliko informacij, ki jih lahko kasneje uporabimo v pravilih. Odlično orodje za preučevanje notranjih delov SIP je analizator sngrep (povezava) ki ga enostavno namestimo v priljubljenih distribucijah z apt install/yum install in podobnim, mogoče pa ga je sestaviti tudi iz virov. Oglejmo si log klica v sngrep.

Let’s explore FreePBX and integrate it with Bitrix24 and beyond

Poenostavljeno, dialplan se ukvarja le s prvim paketom, včasih pa se v procesu klica dogajajo tudi prenos klicev, pritiski na gumbe (DTMF), različne zanimivosti, kot so FollowMe, RingGroup, IVR in podobno.

Kaj je dentro Invite paketa

Let’s explore FreePBX and integrate it with Bitrix24 and beyond

Večina preprostih dialplanov deluje z prvima dvema poljema in vsa logika se vrti okoli DID in CallerID. DID je tisti, na katerega kličemo, CallerID pa je tisti, ki kliče.

Ampak mi imamo podjetje in ne le en telefon — to pomeni, da ima PBX verjetno skupine klicev (hkratni/podstantni klici več naprav) na mestnih številkah (Ring Group), IVR (Pozdravljeni, poklicali ste… pritisnite en za…), Avtomatske odgovorilnike (Phrases), Časovne pogoje (Time Conditions), Preusmeritve na druge številke ali mobilne (FollowMe, Forward). To pomeni, da je zelo težko nedvoumno določiti, kdo bo dejansko prejel klic in s kom se bo pogovarjal ob prejemu klica. Tukaj je primer začetka standardnega klica v PBX naših strank.

Let’s explore FreePBX and integrate it with Bitrix24 and beyond

Po uspešnem vstopu klica v PBX se ta potuje po dialplanu v različnih "kontextih". Kontext iz vidika Asteriska je numerirana množica ukazov, od katerih vsak vsebuje filter za vneseno številko (imenuje se exten, za zunanji klic na začetni stopnji je exten=DID). Ukazi v vrstici dialplana so lahko karkoli — notranje funkcije (na primer poklicati notranjega uporabnika — Dial(), obesiti slušalko — Hangup()), pogojni operatorji (IF, ELSE, ExecIF in podobno), prehodi k drugim pravilom tega konteksta (Goto, GotoIF), prehodi v druge kontekste v obliki klicev funkcij (Gosub, Macro). Posebno ureditev predstavlja direktiva include ime_konteksta, ki doda ukaze drugega konteksta na konec trenutnega konteksta. Ukazi, vključeni preko include, se vedno izvajajo po ukazov trenutnega konteksta.

Vsa logika dela FreePBX je zgrajena na vključevanju različnih kontekstov drug v drugega preko include in klicev preko Gosub, Macro in obdelovalcev Handler. Raziščimo kontekst dohodnih klicev FreePBX.

Let’s explore FreePBX and integrate it with Bitrix24 and beyond

Klic prehaja skozi vse kontekste od zgoraj navzdol po vrsti, v vsakem kontekstu so lahko klici drugih kontekstov kot makroji (Macro), funkcij (Gosub) ali preprosto prehodi (Goto), zato je dejansko drevo tega, kar se kliče, mogoče slediti samo v dnevnikih.

Standardna shema konfiguracije tipične kancelarijske PBX systema je prikazana ispod. Kada stigne poziv, na ulaznim rutama se traži DID, proveravaju se vremenski uslovi, a ako je sve u redu — pokreće se glasovni meni. Iz njega, pritiskom na dugme 1 ili nakon isteka vremena, dolazi se do grupe operatera. Nakon završetka poziva poziva se makro hangupcall, nakon čega se već ništa ne može izvršiti u dijal-planu, osim posebnih obrada (hangup handler).

Let’s explore FreePBX and integrate it with Bitrix24 and beyond

Gde u ovom algoritmu poziva treba da dostavimo informacije o početku poziva u CRM, gde da započnemo snimanje, gde da završimo snimanje i da ga pošaljemo zajedno sa informacijama o pozivu na CRM?

Integracija sa eksternim sistemima

Šta je integracija PBX i CRM? To su podešavanja i programi koji konvertuju podatke i događaje između ove dve platforme i šalju ih jedni drugima. Najčešći način interakcije nezavisnih sistema je API, a najpopularniji način pristupa API-ju je HTTP REST. Ali ne i za asterisk.

Unutar Asteriska postoje:

  • AGI — sinhroni poziv eksternih programa/komponenti, koristi se uglavnom u dijal-planu, postoje biblioteke poput phpagi, PAGI

  • AMI — tekstualni TCP soket, koji funkcioniše po principu pretplate na događaje i unosa tekstualnih komandi, podseća na SMTP iznutra, može pratiti događaje i upravljati pozivima, postoji biblioteka PAMI — najpopularnija za uspostavljanje veze sa Asterisk-om

Primer izlaza AMI

Događaj: Newchannel
Ovlašćenje: call,all
Kanal: PJSIP/VMS_pjsip-0000078b
Država kanala: 4
Opis stanja kanala: Ring
CallerIDNum: 111222
CallerIDName: 111222
ConnectedLineNum:
ConnectedLineName:
Jezik: en
AccountCode:
Kontekst: from-pstn
Exten: s
Prioritet: 1
Jedinstveni ID: 1599589046.5244
Povezani ID: 1599589046.5244

  • ARI — mešavina jednog i drugog, sve kroz REST, WebSocket, u JSON formatu — ali sa novim bibliotekama i omotima nije baš sjajno, našli su se (phparia, phpari) koji su se razvijali pre 3 godine.

Primer izlaza ARI prilikom iniciranja poziva

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

Udobnost ali neudobnost, možnost ali nemogočnost dela z določenim API-jem sta odvisni od nalog, ki jih je treba rešiti. Naloge za integracijo s CRM so naslednje:

  • Spremljati začetek klica, kam je bil preusmerjen, pridobiti CallerID, DID, čase začetka in konca, lahko tudi podatke iz imenika (za iskanje povezave med telefonom in uporabnikom CRM)

  • Začeti in končati snemanje klica, shraniti v ustreznem formatu, sporočiti po končanju snemanja, kje leži datoteka

  • Inicializirati klic po zunanjem dogodku (iz programa), poklicati notranjo številko, zunanjo in ju povezati

  • Valgfrit: integrirati s CRM-jem, skupinami za klicanje in FollowME za samodejno preusmerjanje klicev v primeru odsotnosti (na podlagi informacij CRM)

Vse te naloge lahko rešimo preko AMI ali ARI, vendar ARI nudi veliko manj informacij, mnogi dogodki niso sledeni, mnoge spremenljivke, ki jih AMI vseeno vsebuje (na primer klici makrov, dodeljevanje spremenljivk znotraj makrov, vključno s snemanjem klicev). Zato bomo za pravilno in natančno sledenje zaenkrat izbrali AMI (a ne dokončno). Poleg tega (no, kako pa brez tega, smo ljudje leni) — v izvorni nalogi (članek na habru) uporabljajo PAMI. *Pozneje je treba poskusiti prepisati na ARI, vendar ni nujno, da bo uspelo.

Izmišljamo integracijo znova

Da lahko naš FreePBX preprosto obvešča AMI o začetku klica, času konca, številkah, imenih posnetih datotek, je najbolje uporabiti enak trik, kot so ga imeli izvirni avtorji — vnos svojih spremenljivk in analiza izhoda na njihovo prisotnost. PAMI to omogoča preprosto preko funkcije filter.

Tukaj je primer dodelitve svoje spremenljivke za čas začetka klica (s je posebna številka v dialplan-u, ki se izvaja PRED začetkom iskanja po DID)

[ext-did-custom]

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

Primer AMI dogodka po tej vrstici

Događaj: Newchannel

Ovlašćenje: call,all

Kanal: PJSIP/VMS_pjsip-0000078b

Država kanala: 4

Opis stanja kanala: Ring

CallerIDNum: 111222

CallerIDName: 111222

ConnectedLineNum:

ConnectedLineName:

Jezik: en

AccountCode:

Kontekst: from-pstn

Exten: s

Prioritet: 1

Jedinstveni ID: 1599589046.5244

Povezani ID: 1599589046.5244

Aplikacija: Set AppData:

CallStart=1599571046

Ker FreePBX prepisuje datoteke extention.conf in extention_additional.conf, bomo uporabili datoteko extention_custom.conf

Polna koda extention_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

Posebnost i razlika od originalnog dijal plana autora izvorne članka —

  • Dijal plan u .conf formatu, kako to želi FreePBX (da, može i .ael, ali ne u svim verzijama i ne uvijek je to praktično)

  • Umjesto obrade završetka kroz exten=>h, uvedena je obrada putem hangup_handler, jer je FreePBX dijal plan radio samo s njim

  • Ispravljena je linija poziva skripte, dodane su navodnice i vanjski broj poziva ExtNum

  • Obradbe su premještene u _custom kontekste i omogućuju nečakiranje i nepromjenu FreePBX konfiguracija — dolazne kroz [ext-did-custom], odlazne kroz [outbound-allroutes-custom]

  • Nema vezivanja za brojeve — datoteka je univerzalna i zahtijeva samo podešavanje puta i poveznice na poslužitelj

Za početak rada potrebno je još pustiti skripte u AMI pomoću korisničkog imena i lozinke — za to FreePBX također ima _custom datoteku

Datoteka manager_custom.conf

;;  to je korisničko ime
[callmeplus]
;; to je lozinka
secret = trampampamturlala
deny = 0.0.0.0/0.0.0.0

;; radim s lokalnim strojem - ali ako treba, može se navesti i druge
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

Ove obje datoteke treba staviti u /etc/asterisk, zatim ponovo učitati konfiguracije (ili ponovo pokrenuti Asterisk)

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

Sada prelazimo na PHP

Inicijalizacija skripti i kreiranje servisa

Budući da je shema rada s Bitrix 24, servisom za AMI, prilično složena i neprozirna, na njoj se treba posebno zadržati. Asterisk, kada se aktivira AMI, jednostavno otvara port i to je to. Kada se klijent pridruži, traži autorizaciju, zatim se klijent pretplaćuje na potrebne događaje. Događaji dolaze u običnom tekstu, koji PAMI pretvara u strukturirane objekte i omogućava postavljanje funkcije filtriranja samo za interesantne događaje, polja, brojeve itd.

S čim dolazi poziv, nastaje događaj NewExten počevši od roditeljskog konteksta [from-pstn], zatim idu svi događaji po redoslijedu linija u kontekstima. Kada se dobije informacija iz zadanih u dijal planu _custom varijablama CallMeCallerIDName i CallStart, poziva se

  1. Funckcja zapytania UserID, odpowiadająca wewnętrznemu numerowi, do którego dzwoniono. A jeśli to grupa połączeń? To pytanie polityczne – należy utworzyć połączenie do wszystkich jednocześnie (gdy dzwonią wszyscy jednocześnie), czy też tworzyć je w miarę dzwonienia podczas dzwonienia po kolei? U większości klientów stosuje się strategię First Available, więc nie ma z tym problemów, dzwoni tylko jedna osoba. Ale problem należy rozwiązać.

  2. Funkcja rejestracji połączenia w Bitrix24, która zwraca CallID, potrzebny później do zgłaszania parametrów połączenia oraz linku do nagrania. Wymaga wewnętrznego numeru lub UserID.

Let’s explore FreePBX and integrate it with Bitrix24 and beyond

Po zakończeniu połączenia wywoływana jest funkcja ładowania zapisu, która jednocześnie informuje o statusie zakończenia połączenia (Zajęty, Brak odpowiedzi, Sukces), a także ładuje link do pliku mp3 z nagraniem (jeśli jest).

Ponieważ moduł CallMeIn.php musi działać nieprzerwanie, stworzono dla niego plik startowy SystemD. callme.service, który należy umieścić w /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

# tutaj należy sprawdzić, jakie są prawa do folderów
#User=www-data  #Ubuntu - debian
#User=nginx #Centos

[Install]
WantedBy=multi-user.target

Inicjalizacja i uruchomienie skryptu odbywa się za pośrednictwem systemctl lub service.

# systemctl enable callme
# systemctl start callme

Serwis będzie automatycznie uruchamiał się ponownie w razie potrzeby (przy awariach). Serwis monitorujący przychodzące połączenia nie wymaga instalacji serwera WWW, potrzebny jest tylko PHP (który z pewnością jest na serwerze FeePBX). Jednak w przypadku braku dostępu do nagrań połączeń przez serwer WWW (jeszcze z HTTPS) nie będzie możliwości odsłuchiwania nagrań rozmów.

Teraz porozmawiajmy o połączeniach wychodzących. Skrypt CallMeOut.php ma dwie funkcje:

  • Inicjacja połączenia przy otrzymaniu żądania do skryptu PHP (w tym przycisk „Zadzwoń” w samym Bitrixie). Bez serwera WWW nie działa, żądanie przychodzi przez HTTP POST, a w żądaniu zawarty jest token.

  • Informacja o dzwonieniu, jego parametrach i nagraniach w Bitrixie. Ma miejsce z inicjatywy Asterisk w planie dzwanienia [sub-call-internal-ended] po zakończeniu połączenia.

Let’s explore FreePBX and integrate it with Bitrix24 and beyond

Serwer WWW potrzebny jest tylko do dwóch rzeczy – ładowania plików nagrań przez Bitrix (przez HTTPS) oraz wywoływania skryptu CallMeOut.php. Można używać wbudowanego serwera FreePBX, pliki dla którego znajdują się w /var/www/html, można zainstalować inny serwer lub określić inną ścieżkę.

Serwer WWW

Pustimo konfiguracijo spletnega strežnika za samostojno raziskovanje (klikni tukaj, klikni tukaj, klikni tukaj). Če nimate domene, lahko preizkusite FreeDomain ( https://www.freenom.com/ru/index.html), ki vam bodo brezplačno dali ime za vaš javni IP (ne pozabite preusmeriti vrat 80, 443 skozi usmerjevalnik, če je zunanji naslov samo na njem). Če ste pravkar ustvarili DNS domeno, boste morali počakati (od 15 minut do 48 ur), da se vsi strežniki naložijo. Na podlagi izkušenj z domačimi ponudniki – od 1 ure do enega dneva.

Samodejna namestitev

Na githubu se je začela razvijati namestitvena programska oprema, tako da bo namestitev še enostavnejša. Toda gladko je bilo na papirju — zaenkrat vse to nameščamo ročno, a po muckanju z vsemi temi stvarmi je postalo kristalno jasno, kdo je s kom prijatelj, kdo kam hodi in kako to debuggirati. Namestitvene programske opreme zaenkrat ni (

Docker

Če želite hitro preizkusiti rešitev — obstaja možnost z Dockerjem — hitro ustvarite vsebnik, mu omogočite zunanja vrata, dodajte konfiguracijske datoteke in preizkusite (to je možnost z LetsEncrypt vsebnikom, če ima že certifikat, potrebno je le preusmeriti obratni proxy na spletni strežnik FreePBX (dali smo mu drugo vrata — 88), LetsEncrypt v Dockerju po motivih ovog članka

Datoteko je treba zagnati v preneseni mapi projekta (po git clone), a prej je treba spremeniti nastavitve Asteriska (mapa asterisk) in tam vnesti poti do zapisov in URL vašega spletnega mesta.

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

Ta datoteka docker-compose.yaml se zažene prek

docker-compose up -d

Če nginx ni zagnal, potem je nekaj narobe s konfiguracijo v mapi nginx\/ssl_docker.conf.

Druge integracije

Zakaj ne bi dodali več CRM v skripte, smo pomislili. Raziskovali smo več API-jev drugih CRM, še posebej brezplačne, vgrajene v nekatere PBX — ShugarCRM in Vtiger, in ja! lahko, načelo je isto. A to je že druga zgodba, ki jo bomo kasneje nalagali na github ločeno.

Povezave

Disklejmer: vse morebitne podobnosti z resničnostjo so naključne in to nisem bil jaz,

Izvor: habr.com

Kupite zanesljivo gostovanje za spletne strani z zaščito pred DDoS, VPS VDS strežniki 🔥 Kupite zanesljivo gostovanje za spletne strani z zaščito pred DDoS, VPS VDS strežniki | ProHoster