Hal De 3 anni fa
commit
cf7a16feef

+ 322 - 0
Dockerfile

@@ -0,0 +1,322 @@
+FROM ubuntu:focal AS build-asterisk
+ENV DEBIAN_FRONTEND=noninteractive
+ARG ASTERISK_VER=18.10.0
+ARG BCG729_VER=1.1.1
+ARG ASTERISK_G72X_VER=master
+
+WORKDIR /usr/src
+RUN apt-get update && \
+    apt-get install --no-install-recommends --yes \
+    git build-essential subversion checkinstall autoconf automake bison flex graphviz cmake curl ca-certificates libresample1-dev libiksemel-dev libopus-dev pkg-config
+
+RUN cd /usr/src && \
+  mkdir asterisk && \
+  curl -fSL --connect-timeout 30 http://downloads.asterisk.org/pub/telephony/asterisk/releases/asterisk-${ASTERISK_VER}.tar.gz | tar xz --strip 1 -C asterisk && \
+  cd asterisk && \
+  ./contrib/scripts/get_mp3_source.sh && \
+  ./contrib/scripts/install_prereq install
+
+RUN cd /usr/src/asterisk && git clone https://github.com/felipem1210/asterisk-res_json.git && ./asterisk-res_json/install.sh
+
+RUN cd /usr/src/asterisk && ./configure --prefix=/usr --libdir=/usr/lib --with-pjproject-bundled --with-jansson-bundled --with-resample --with-ssl=ssl --with-srtp && \
+  make menuselect/menuselect menuselect-tree menuselect.makeopts && \
+  menuselect/menuselect \
+    --enable-category MENUSELECT_ADDONS \
+    --enable-category MENUSELECT_CHANNELS \
+    --enable-category MENUSELECT_APPS \
+    --enable-category MENUSELECT_CDR \
+    --enable-category MENUSELECT_FORMATS \
+    --enable-category MENUSELECT_FUNCS \
+    --enable-category MENUSELECT_PBX \
+    --enable-category MENUSELECT_RES \
+    --enable-category MENUSELECT_CEL \
+  \
+  menuselect/menuselect \
+    --enable BETTER_BACKTRACES \
+    --enable DONT_OPTIMIZE \
+    --enable app_confbridge \
+    --enable app_macro \
+    --enable app_meetme \
+    --enable app_mysql \
+    --enable app_page \
+    --enable binaural_rendering_in_bridge_softmix \
+    --enable chan_motif \
+    --enable codec_silk \
+    --enable codec_opus \
+    --enable format_mp3 \
+    --enable res_ari \
+    --enable res_chan_stats \
+    --enable res_calendar \
+    --enable res_calendar_caldav \
+    --enable res_calendar_icalendar \
+    --enable res_endpoint_stats \
+    --enable res_pktccops \
+    --enable res_snmp \
+    --enable res_srtp \
+    --enable res_xmpp \
+    --disable-category MENUSELECT_CORE_SOUNDS \
+    --disable-category MENUSELECT_EXTRA_SOUNDS \
+    --disable-category MENUSELECT_MOH \
+    --disable BUILD_NATIVE \
+    --disable app_ivrdemo \
+    --disable app_meetme \
+    --disable app_saycounted \
+    --disable app_skel \
+    --disable cdr_pgsql \
+    --disable cel_pgsql \
+    --disable cdr_sqlite3_custom \
+    --disable cel_sqlite3_custom \
+    --disable cdr_mysql \
+    --disable cdr_tds \
+    --disable cel_tds \
+    --disable cdr_radius \
+    --disable cel_radius \
+    --disable cdr_syslog \
+    --disable chan_alsa \
+    --disable chan_console \
+    --disable chan_oss \
+    --disable chan_mgcp \
+    --disable chan_skinny \
+    --disable chan_ooh323 \
+    --disable chan_mobile \
+    --disable chan_unistim \
+    --disable res_digium_phone \
+    --disable res_calendar_ews \
+    --disable res_calendar_exchange \
+    --disable res_stasis_mailbox \
+    --disable res_mwi_external \
+    --disable res_mwi_external_ami \
+    --disable res_config_pgsql \
+    --disable res_config_mysql \
+    --disable res_config_ldap \
+    --disable res_config_sqlite3 \
+    --disable res_phoneprov \
+    --disable res_pjsip_phoneprov_provider \
+  && \
+  make && \
+  checkinstall --install=yes --default --pakdir=/usr/src/packages --pkgname=asterisk-iczr  --pkgversion=${ASTERISK_VER} && \
+  checkinstall --install=yes --default --pakdir=/usr/src/packages --pkgname=asterisk-iczr-dev --pkgversion=${ASTERISK_VER} make install-headers && \
+  checkinstall --install=yes --default --pakdir=/usr/src/packages --pkgname=asterisk-iczr-config --pkgversion=${ASTERISK_VER} make config && \
+  checkinstall --install=yes --default --pakdir=/usr/src/packages --pkgname=asterisk-iczr-samples --pkgversion=${ASTERISK_VER} make samples && \
+  ldconfig && \
+  cd /usr/src && \
+  mkdir bcg729 && \
+  curl -fSL --connect-timeout 30 https://github.com/BelledonneCommunications/bcg729/archive/${BCG729_VER}.tar.gz | tar xz --strip 1 -C bcg729 && \
+  cd bcg729 && \
+  cmake . -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_PREFIX_PATH=/usr && \
+  make && \
+  checkinstall --install=yes --default --pakdir=/usr/src/packages --pkgname=bcg729-iczr --pkgversion=${BCG729_VER} --spec=none && \
+  ldconfig && \
+  cd /usr/src && \
+  mkdir asterisk-g72x && \
+  curl -fSL --connect-timeout 30 https://bitbucket.org/arkadi/asterisk-g72x/get/${ASTERISK_G72X_VER}.tar.gz | tar xz --strip 1 -C asterisk-g72x && \
+  cd asterisk-g72x && \
+  ./autogen.sh && \
+  ./configure --prefix=/usr --with-bcg729 --enable-penryn && \
+  make && \
+  checkinstall --install=yes --default --pakdir=/usr/src/packages --pkgname=asterisk-g72x-iczr --pkgversion=0.${ASTERISK_G72X_VER} && \
+  ldconfig
+
+FROM ubuntu:focal AS iczr-freepbx
+ENV DEBIAN_FRONTEND=noninteractive
+ARG ASTERISK_VER=18.10.0
+ARG BCG729_VER=1.1.1
+ARG ASTERISK_G72X_VER=master
+ARG FREEPBX_VER=15.0
+ENV APP_PORT_HTTP         80
+ENV APP_PORT_HTTPS        443
+ENV APP_PORT_PJSIP        5160
+ENV APP_PORT_SIP          5060
+ENV APP_PORT_IAX          4569
+ENV APP_PORT_RTP_START    10000
+ENV APP_PORT_RTP_END      10200
+ENV APP_PORT_MYSQL        3306
+ENV APP_UID=1000
+ENV APP_GID=1000
+ENV APP_USR="asterisk"
+ENV APP_GRP="asterisk"
+
+COPY --from=build-asterisk /usr/src/packages /usr/src/packages
+
+RUN apt-get update && \
+    apt-get install --no-install-recommends --yes gpg gpg-agent dirmngr && \
+    apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 4F4EA0AAE5267A6C && \
+    echo "deb http://ppa.launchpad.net/ondrej/php/ubuntu focal main" >> /etc/apt/sources.list.d/ondrej-php.list && \
+    echo "deb http://ppa.launchpad.net/ondrej/apache2/ubuntu focal main" >> /etc/apt/sources.list.d/ondrej-apache2.list && \
+    apt-get update && \
+    apt-get upgrade --yes && \
+    dpkg -i /usr/src/packages/*.deb && \
+    apt-get install --no-install-recommends --yes \
+    apache2 \
+    binutils \
+    certbot \
+    codec2 \
+    cron \
+    curl \
+    fail2ban \
+    ffmpeg \
+    file \
+    freetds-bin \
+    freetds-common \
+    iptables \
+    jq \
+    lame \
+    libaudiofile1 \
+    libc-client2007e \
+    libcap2 \
+    libcfg7 \
+    libcpg4 \
+    libdbd-mysql \
+    libdbi-perl\
+    libeditline0 \
+    libevent-2.1-7 \
+    libfftw3-3 \
+    libfftw3-bin \
+    libgmime-3.0-0 \
+    libical3 \
+    libicu66 \
+    libiksemel3 \
+    libjansson4 \
+    libjpeg-turbo8 \
+    libltdl7 \
+    libncurses5 \
+    libneon27 \
+    libnewt0.52 \
+    libopus0 \
+    libosptk4 \
+    libportaudio2 \
+    libproxy1v5 \
+    libresample1 \
+    libsensors5 \
+    libsndfile1 \
+    libsnmp35 \
+    libsnmp-base \
+    libspandsp2 \
+    libspeexdsp1 \
+    libsrtp2-1 \
+    libtiff5 \
+    libtiff-tools \
+    libunbound8 \
+    liburiparser1 \
+    libvpb1 \
+    libxml2 \
+    lm-sensors \
+    logrotate \
+    lsof \
+    mariadb-client \
+    mpg123 \
+    netcat \
+    net-tools \
+    nodejs \
+    npm \
+    odbc-mariadb \
+    openssl \
+    php7.3 \
+    php7.3-mysql \
+    php7.3-curl \
+    php7.3-gd \
+    php7.3-json \
+    php7.3-mbstring \
+    php7.3-xml \
+    postfix \
+    rsync \
+    sox \
+    speex \
+    sqlite3 \
+    strace \
+    sudo \
+    supervisor \
+    unixodbc \
+    unzip \
+    uuid \
+    wget \
+    whois \
+    zip
+
+RUN groupadd -g ${APP_GID} ${APP_GRP} && \
+  useradd -u ${APP_UID} -c "Asterisk User" -g ${APP_GRP} -s /sbin/nologin ${APP_USR} && \
+  usermod -aG sudo,www-data ${APP_USR} && \
+  mkdir -p \
+    /etc/pki/pbx \
+    /home/asterisk \
+    /var/lib/asterisk/moh \
+    /var/lib/asterisk/sounds \
+    /var/spool/asterisk \
+    /var/run/fail2ban && \
+  chown -R ${APP_USR}:${APP_GRP} \
+    /etc/asterisk \
+    /home/asterisk \
+    /var/lib/asterisk \
+    /var/spool/asterisk && \
+  openssl req -subj '/CN=pbx/O=ICZR/C=RU' -new -newkey rsa:2048 -sha256 -days 36500 -nodes -x509 -keyout /etc/pki/pbx/iczrpbx.key -out /etc/pki/pbx/iczrpbx.crt
+
+RUN cd /usr/src && \
+  mkdir freepbx && \
+  curl -fSL --connect-timeout 30 http://mirror.freepbx.org/modules/packages/freepbx/freepbx-${FREEPBX_VER}-latest.tgz | tar xz --strip 1 -C freepbx && \
+  cd freepbx && \
+  curl -fSL --connect-timeout 30 http://mirror1.freepbx.org/modules-${FREEPBX_VER}.xml -o modules-${FREEPBX_VER}.xml && \
+  mkdir -p amp_conf/htdocs/admin/modules/_cache && \
+  for MODULE in \
+      announcement \
+      arimanager \
+      asteriskinfo \
+      backup \
+      calendar \
+      callforward \
+      callwaiting \
+      cel \
+      certman \
+      cidlookup \
+      contactmanager \
+      daynight \
+      donotdisturb \
+      filestore \
+      findmefollow \
+      iaxsettings \
+      ivr \
+      manager \
+      miscapps \
+      miscdests \
+      parking \
+      phonebook \
+      presencestate \
+      printextensions \
+      queues \
+      soundlang \
+      timeconditions \
+      userman \
+      ucp \
+      bulkhandler \
+      speeddial \
+      weakpasswords \
+      asterisk-cli \
+      blacklist \
+      configedit \
+      pm2 \
+      ; do \
+  mkdir -p amp_conf/htdocs/admin/modules/$MODULE && \
+  MODULE_VER=$(php -r "echo json_encode(simplexml_load_file('modules-${FREEPBX_VER}.xml'));" | jq -r ".module[] | select(.rawname == \"${MODULE}\") | {version}".version) && \
+  curl -sfSL --connect-timeout 30 http://mirror.freepbx.org/modules/packages/$MODULE/$MODULE-${MODULE_VER}.tgz | tar xz --strip 1 -C amp_conf/htdocs/admin/modules/$MODULE/ && \
+  curl -sfSL --connect-timeout 30 http://mirror.freepbx.org/modules/packages/$MODULE/$MODULE-${MODULE_VER}.tgz.gpg -o amp_conf/htdocs/admin/modules/_cache/$MODULE-${MODULE_VER}.tgz.gpg \
+  ; done && \
+  su - ${APP_USR} -s /bin/bash -c "gpg --refresh-keys --keyserver hkp://keyserver.ubuntu.com:80" && \
+  su - ${APP_USR} -s /bin/bash -c "gpg --import /usr/src/freepbx/amp_conf/htdocs/admin/libraries/BMO/1588A7366BD35B34.key" && \
+  su - ${APP_USR} -s /bin/bash -c "gpg --import /usr/src/freepbx/amp_conf/htdocs/admin/libraries/BMO/3DDB2122FE6D84F7.key" && \
+  su - ${APP_USR} -s /bin/bash -c "gpg --import /usr/src/freepbx/amp_conf/htdocs/admin/libraries/BMO/86CE877469D2EAD9.key" && \
+  su - ${APP_USR} -s /bin/bash -c "gpg --import /usr/src/freepbx/amp_conf/htdocs/admin/libraries/BMO/9F9169F4B33B4659.key"
+
+EXPOSE ${APP_PORT_HTTP}/tcp \
+       ${APP_PORT_HTTPS}/tcp \
+       ${APP_PORT_PJSIP}/tcp \
+       ${APP_PORT_PJSIP}/udp \
+       ${APP_PORT_IAX}/tcp \
+       ${APP_PORT_IAX}/udp \
+       ${APP_PORT_SIP}/tcp \
+       ${APP_PORT_SIP}/udp \
+       ${APP_PORT_RTP_START}-${APP_PORT_RTP_END}/udp \
+       ${APP_PORT_MYSQL}/tcp
+
+ADD filesystem /
+
+ENTRYPOINT ["/entrypoint.sh"]
+CMD ["supervisord", "-n", "-c", "/etc/supervisor/supervisord.conf"]

+ 0 - 0
README.md


+ 73 - 0
env.dist

@@ -0,0 +1,73 @@
+MYSQL_ROOT_PASSWORD=secret
+MYSQL_PASSWORD=secret
+MYSQL_SERVER=127.0.0.1
+MYSQL_DATABASE=asterisk
+MYSQL_USER=asterisk
+APP_DATA=/data
+ROOT_MAILTO=admin@example.com
+SENDMAIL_TG=false
+TG_BOT_APIKEY=secret
+TG_BOT_CHATID=
+APP_FQDN=pbx.example.com
+FREEPBX_AMPMGRPASS=secret
+FREEPBX_CDRDBHOST=127.0.0.1
+FREEPBX_CDRDBNAME=asteriskcdrdb
+FREEPBX_CDRDBPASS=secret
+FREEPBX_CDRDBTABLENAME=cdr
+FREEPBX_CDRDBTYPE=mysql
+FREEPBX_CDRDBUSER=asterisk
+FREEPBX_AMPEXTENSIONS=deviceanduser
+FREEPBX_DYNAMICHINTS=1
+FREEPBX_ASTSIPDRIVER=chan_pjsip
+FREEPBX_USEGOOGLEDNSFORENUM=1
+SMTP_MAIL_FROM=pbx@pbx.example.com
+HTTPD_HTTPS_ENABLED=false
+HTTPD_REDIRECT_HTTP_TO_HTTPS=false
+LETSENCRYPT_ENABLED=false
+#HTTPD_ALLOW_FROM=127.0.0.0/8 10.0.0.0/8 172.16.0.0/12 192.168.0.0/16
+## fail2ban (format: FAIL2BAN_SECTION_KEY=VALUE)
+FAIL2BAN_ENABLED=true
+FAIL2BAN_ASTERISK_ENABLED=true
+#FAIL2BAN_ASTERISK_LOGPATH=/var/log/asterisk/security
+#FAIL2BAN_DEFAULT_SENDER=fail2ban@example.com
+#FAIL2BAN_DEFAULT_DESTEMAIL=security@example.com
+FAIL2BAN_DEFAULT_IGNOREIP=127.0.0.0/8 10.0.0.0/8 172.16.0.0/12 192.168.0.0/16
+FAIL2BAN_DEFAULT_BANTIME=300
+FAIL2BAN_DEFAULT_FINDTIME=3600
+FAIL2BAN_DEFAULT_MAXRETRY=10
+FAIL2BAN_RECIDIVE_ENABLED=true
+FAIL2BAN_RECIDIVE_BANTIME=1814400
+FAIL2BAN_RECIDIVE_FINDTIME=15552000
+FAIL2BAN_RECIDIVE_MAXRETRY=10
+#FREEPBX_MODULES_EXTRA=soundlang callrecording cdr conferences customappsreg featurecodeadmin infoservices logfiles music manager arimanager filestore recordings announcement asteriskinfo backup callforward callwaiting daynight calendar certman cidlookup contactmanager donotdisturb fax findmefollow iaxsettings miscapps miscdests ivr parking phonebook presencestate printextensions queues cel timeconditions pm2
+FREEPBX_FREEPBX_SYSTEM_IDENT=ICZR_PBX
+FREEPBX_AS_DISPLAY_READONLY_SETTINGS=1
+FREEPBX_AS_OVERRIDE_READONLY=1
+FREEPBX_ENABLECW=0
+FREEPBX_TONEZONE=ru
+FREEPBX_PHPTIMEZONE=Europe/Moscow
+#FREEPBX_BRAND_IMAGE_TANGO_LEFT=images/tango.png
+#FREEPBX_BRAND_IMAGE_FREEPBX_FOOT=images/freepbx_small.png
+#FREEPBX_BRAND_IMAGE_SPONSOR_FOOT=images/sangoma-horizontal_thumb.png
+#FREEPBX_BRAND_FREEPBX_ALT_LEFT=FreePBX
+#FREEPBX_BRAND_FREEPBX_ALT_FOOT=FreePBX®
+#FREEPBX_BRAND_SPONSOR_ALT_FOOT=www.sangoma.com
+#FREEPBX_BRAND_IMAGE_FREEPBX_LINK_LEFT=http://www.freepbx.org
+#FREEPBX_BRAND_IMAGE_FREEPBX_LINK_FOOT=http://www.freepbx.org
+#FREEPBX_BRAND_IMAGE_SPONSOR_LINK_FOOT=http://www.sangoma.com
+#FREEPBX_RSSFEEDS=
+FREEPBX_SIGNATURECHECK=0
+APP_PORT_HTTP=80
+APP_PORT_HTTPS=443
+APP_PORT_PJSIP=5160
+APP_PORT_SIP=5060
+APP_PORT_IAX=4569
+APP_PORT_AMI=8088
+APP_PORT_RTP_START=10000
+APP_PORT_RTP_END=20000
+APP_PORT_MYSQL=3306
+POSTFIX_ENABLED=true
+CRON_ENABLED=true
+HTTPD_ENABLED=true
+ICZRPBX_ENABLED=true
+FAIL2BAN_ENABLED=true

+ 718 - 0
filesystem/entrypoint-hooks.sh

@@ -0,0 +1,718 @@
+#!/bin/bash
+
+: ${ROOT_MAILTO:="root@localhost"}
+: ${ASTERISK_VER:=""}
+: ${FREEPBX_VER:=""}
+: ${APP_DATA:=""}
+
+declare -A appDataDirs=(
+  [CRONDIR]=/var/spool/cron
+  [ASTHOME]=/home/asterisk
+  [ASTETCDIR]=/etc/asterisk
+  [ASTVARLIBDIR]=/var/lib/asterisk
+  [ASTSPOOLDIR]=/var/spool/asterisk
+  [ASTRUNDIR]=/var/run/asterisk
+  [HTTPDHOME]=/var/www
+  [HTTPDLOGDIR]=/var/log/apache2
+  [CERTBOTETCDIR]=/etc/letsencrypt
+  [ASTLOGDIR]=/var/log/asterisk
+  [F2BLOGDIR]=/var/log/fail2ban
+  [F2BLIBDIR]=/var/lib/fail2ban
+  [SSLCRTDIR]=/etc/pki/pbx
+  [ROOTHOME]=/root
+)
+
+declare -A appFilesConf=(
+  [FPBXCFGFILE]=/etc/freepbx.conf
+  [AMPCFGFILE]=/etc/amportal.conf
+)
+
+declare -A appCacheDirs=(
+  [ASTRUNDIR]=/var/run/asterisk
+  [PHPOPCACHEDIR]=/var/lib/php/opcache
+  [PHPSESSDIR]=/var/lib/php/session
+  [PHPWSDLDIR]=/var/lib/php/wsdlcache
+)
+
+declare -A fpbxDirs=(
+  [AMPWEBROOT]=/var/www/html
+  [ASTETCDIR]=/etc/asterisk
+  [ASTVARLIBDIR]=/var/lib/asterisk
+  [ASTAGIDIR]=/var/lib/asterisk/agi-bin
+  [ASTSPOOLDIR]=/var/spool/asterisk
+  [ASTRUNDIR]=/var/run/asterisk
+  [ASTLOGDIR]=/var/log/asterisk
+  [AMPBIN]=/var/lib/asterisk/bin
+  [AMPSBIN]=/var/lib/asterisk/sbin
+  [AMPCGIBIN]=/var/www/cgi-bin
+  [AMPPLAYBACK]=/var/lib/asterisk/playback
+  [CERTKEYLOC]=/etc/asterisk/keys
+)
+
+declare -A fpbxDirsExtra=(
+  [ASTMODDIR]=/usr/lib/asterisk/modules
+)
+
+declare -A fpbxFilesLog=(
+  [FPBXDBUGFILE]=/var/log/asterisk/freepbx-debug.log
+  [FPBXLOGFILE]=/var/log/asterisk/freepbx.log
+  [FPBXSECLOGFILE]=/var/log/asterisk/freepbx_security.log
+)
+
+declare -A fpbxSipSettings=(
+  [rtpstart]=${APP_PORT_RTP_START}
+  [rtpend]=${APP_PORT_RTP_END}
+  [udpport-0.0.0.0]=${APP_PORT_PJSIP}
+  [tcpport-0.0.0.0]=${APP_PORT_PJSIP}
+  [bindport]=${APP_PORT_SIP}
+)
+
+[ ! -z ${APP_FQDN} ] && HOSTNAME="${APP_FQDN}"
+: ${SERVERNAME:=$HOSTNAME}
+: ${MYSQL_SERVER:="db"}
+: ${MYSQL_ROOT_PASSWORD:=""}
+: ${MYSQL_DATABASE:="asterisk"}
+: ${MYSQL_USER:="asterisk"}
+: ${MYSQL_PASSWORD:=""}
+: ${APP_PORT_MYSQL:="3306"}
+: ${HTTPD_HTTPS_ENABLED:="true"}
+: ${HTTPD_REDIRECT_HTTP_TO_HTTPS:="false"}
+: ${HTTPD_ALLOW_FROM:=""}
+: ${CRON_ENABLED:="true"}
+: ${HTTPD_ENABLED:="true"}
+: ${ASTERISK_ENABLED:="false"}
+: ${ICZRPBX_ENABLED:="true"}
+: ${FAIL2BAN_ENABLED:="true"}
+: ${POSTFIX_ENABLED:="true"}
+: ${SMTP_RELAYHOST:=""}
+: ${SMTP_RELAYHOST_USERNAME:=""}
+: ${SMTP_RELAYHOST_PASSWORD:=""}
+: ${SMTP_ALLOWED_SENDER_DOMAINS:=""}
+: ${SMTP_MESSAGE_SIZE_LIMIT:="0"}
+: ${SMTP_MAIL_FROM:=""}
+: ${RELAYHOST:="$SMTP_RELAYHOST"}
+: ${RELAYHOST_USERNAME:="$SMTP_RELAYHOST_USERNAME"}
+: ${RELAYHOST_PASSWORD:="$SMTP_RELAYHOST_PASSWORD"}
+: ${ALLOWED_SENDER_DOMAINS:="$SMTP_ALLOWED_SENDER_DOMAINS"}
+: ${MESSAGE_SIZE_LIMIT:="$SMTP_MESSAGE_SIZE_LIMIT"}
+: ${SUPERVISOR_DIR:="/etc/supervisor/conf.d"}
+: ${HTTPD_CONF_DIR:="/etc/apache2"}
+: ${PHP_CONF:="/etc/php/7.4/apache2/php.ini"}
+
+dirEmpty() {
+    [ -z "$(ls -A "$1/")" ]
+}
+
+symlinkDir() {
+  local dirOriginal="$1"
+  local dirCustom="$2"
+  echo "---> directory data override detected: original:[$dirOriginal] custom:[$dirCustom]"
+  if [ -e "$dirOriginal" ] && dirEmpty "$dirCustom"; then
+    echo "---> empty dir '$dirCustom' detected copying '$dirOriginal' contents to '$dirCustom'..."
+    rsync -a -q "$dirOriginal/" "$dirCustom/"
+  fi
+  if [ ! -e "$dirOriginal" ]; then
+      echo "---> WARNING: original data directory doesn't exist... creating empty directory: '$dirOriginal'"
+      mkdir -p "$dirOriginal"
+  fi
+  if [ -e "$dirOriginal" ]; then
+      echo -e "---> renaming '${dirOriginal}' to '${dirOriginal}.dist'"
+      mv "$dirOriginal" "$dirOriginal".dist
+  fi
+  echo "---> symlinking '$dirCustom' to '$dirOriginal'"
+  ln -s "$dirCustom" "$dirOriginal"
+}
+
+symlinkFile() {
+  local fileOriginal="$1"
+  local fileCustom="$2"
+  echo "--> file data override detected: original:[$fileOriginal] custom:[$fileCustom]"
+  if [ -e "$fileOriginal" ]; then
+      if [ ! -e "$fileCustom" ]; then
+        echo "---> INFO: detected not existing file '$fileCustom'. copying '$fileOriginal' to '$fileCustom'..."
+        rsync -a -q "$fileOriginal" "$fileCustom"
+      fi
+      echo -e "---> renaming '${fileOriginal}' to '${fileOriginal}.dist'... "
+      mv "$fileOriginal" "$fileOriginal".dist
+    else
+      echo "---> WARNING: original data file doesn't exist... creating symlink from a not existing source: '$fileOriginal'"
+  fi
+  echo "---> symlinking '$fileCustom' to '$fileOriginal'"
+  [ ! -e "$(dirname "$fileCustom")" ] && mkdir -p "$(dirname "$fileCustom")"
+  ln -s "$fileCustom" "$fileOriginal"
+}
+
+chkService() {
+  local SERVICE_VAR="$1"
+  eval local SERVICE_ENABLED="\$$(echo $SERVICE_VAR)"
+  eval local SERVICE_DAEMON="\$$(echo $SERVICE_VAR | sed 's/_.*//')_DAEMON"
+  local SERVICE="$(echo $SERVICE_VAR | sed 's/_.*//' | sed -e 's/\(.*\)/\L\1/')"
+  [ -z "$SERVICE_DAEMON" ] && local SERVICE_DAEMON="$SERVICE"
+  if [ "$SERVICE_ENABLED" = "true" ]; then
+    autostart=true
+    echo "=> Enabling $SERVICE_DAEMON service... because $SERVICE_VAR=$SERVICE_ENABLED"
+    echo "--> configuring $SERVICE_DAEMON service..."
+    cfgService_$SERVICE
+   else
+    autostart=false
+    echo "=> Disabling $SERVICE_DAEMON service... because $SERVICE_VAR=$SERVICE_ENABLED"
+  fi
+  sed "s/autostart=.*/autostart=$autostart/" -i ${SUPERVISOR_DIR}/$SERVICE_DAEMON.conf
+}
+
+cfgService_postfix() {
+postconf -e inet_protocols=ipv4
+
+if [ ! -z "$HOSTNAME" ]; then
+  postconf -e myhostname="$HOSTNAME"
+else
+  postconf -# myhostname
+fi
+
+postconf -# relayhost
+postconf -# smtp_sasl_auth_enable
+postconf -# smtp_sasl_password_maps
+postconf -# smtp_sasl_security_options
+if [ ! -z "$MYNETWORKS" ]; then
+  postconf -e mynetworks=$MYNETWORKS
+else
+  postconf -e "mynetworks=127.0.0.0/8,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16"
+fi
+[ ! -f /etc/aliases ] && echo "postmaster: root" > /etc/aliases
+[ ${ROOT_MAILTO} ] && echo "root: ${ROOT_MAILTO}" >> /etc/aliases && newaliases
+postconf -e "maillog_file = /dev/stdout"
+postconf -e "inet_protocols = ipv4"
+postconf -e "mailbox_size_limit = 0"
+postconf -e "message_size_limit = ${MESSAGE_SIZE_LIMIT}"
+if [ ! -z "$SMTP_MAIL_FROM" ]; then
+  echo "/.+/ $SMTP_MAIL_FROM" > /etc/postfix/sender_canonical_maps
+  echo "/From:.*/ REPLACE From: $SMTP_MAIL_FROM" > /etc/postfix/header_checks
+  postconf -e "sender_canonical_maps = regexp:/etc/postfix/sender_canonical_maps"
+  postconf -e "smtp_header_checks = regexp:/etc/postfix/header_checks"
+fi
+postconf -M telegram-mailgate/unix="telegram-mailgate unix   -   n   n   -   -   pipe flags= user=list argv=/usr/local/bin/telegram-mailgate.py --key ${TG_BOT_APIKEY} --chatid ${TG_BOT_CHATID} --queue-id \${queue_id} \${recipient}"
+postconf -e "content_filter = telegram-mailgate"
+}
+
+cfgService_cron() {
+  ls -la /var/spool/cron/crontabs
+}
+
+cfgService_letsencrypt() {
+  if [ -e "/etc/letsencrypt/live/${APP_FQDN}/privkey.pem" ] ; then
+    echo "--> Let's Encrypt certificate already exist... trying to renew"
+    certbot renew --standalone
+  else
+    echo "--> generating HTTPS Let's Encrypt certificate"
+    certbot certonly --standalone --expand -n --agree-tos --email ${ROOT_MAILTO} -d ${APP_FQDN}
+  fi
+  echo '#!/bin/bash
+/usr/bin/certbot renew --noninteractive --no-random-sleep-on-renew --deploy-hook "/usr/bin/supervisorctl restart httpd"
+exit $?' > /etc/cron.daily/certbot && chmod 755 /etc/cron.daily/certbot
+}
+
+iniParser() {
+  ini="$@"
+  while read setting ; do
+    section="$(echo $setting | awk -F" " '{print $1}')"
+    k=$(echo $setting | sed -e "s/^${section} //" | awk -F"=" '{print $1}' | tr '[:upper:]' '[:lower:]')
+    v=$(echo $setting | sed -e "s/'//g" | awk -F"=" '{print $2}')
+    sed -e "/^\[${section}\]$/I,/^\(\|;\|#\)\[/ s/^\(;\|#\)${k}/${k}/" -e "/^\[${section}\]$/I,/^\[/ s|^${k}.*=.*|${k}=${v}|I" -i "${ini}"
+  done
+}
+
+cfgService_fail2ban() {
+  echo "--> reconfiguring Fail2ban settings..."
+  echo "DEFAULT LOGTARGET=/var/log/fail2ban/fail2ban.log" | iniParser /etc/fail2ban/fail2ban.conf
+  sed "s/%(mta)s-whois\[/%(mta)s\[/g" -i /etc/fail2ban/jail.conf
+  touch /var/log/fail2ban/fail2ban.log
+  set | grep ^"FAIL2BAN_" | sed -e 's/^FAIL2BAN_//' | sed -e 's/_/ /' | iniParser "/etc/fail2ban/jail.d/99-local.conf"
+}
+
+cfgService_httpd() {
+  if [ "${HTTPD_HTTPS_ENABLED}" = "true" ]; then
+    echo "--> enabling Apache ssl module"
+    a2enmod ssl
+  else
+    echo "--> disabling Apache ssl module"
+    a2dismod ssl
+  fi
+  a2enmod rewrite
+  rm -f /var/www/html/index.html
+  echo "--> setting Apache ServerName to ${SERVERNAME}"
+  sed "s/#ServerName .*/ServerName ${SERVERNAME}/" -i "${HTTPD_CONF_DIR}/sites-enabled/000-default.conf"
+  echo "ServerName ${SERVERNAME}" >> "${HTTPD_CONF_DIR}/apache2.conf"
+  echo "--> setting Apache user and group"
+  sed -i "s/^User.*/User ${APP_USR}/" /etc/apache2/apache2.conf
+  sed -i "s/^Group.*/Group ${APP_GRP}/" /etc/apache2/apache2.conf
+  sed -i "s/AllowOverride None/AllowOverride All/" /etc/apache2/apache2.conf
+
+print_AllowFrom() {
+  if [ ! -z "${HTTPD_ALLOW_FROM}" ]; then
+      for IP in $(echo ${HTTPD_ALLOW_FROM} | sed -e "s/'//g") ; do
+        echo "    Require ip ${IP}"
+      done
+  else
+      echo "    Require all granted"
+  fi
+}
+
+echo "# default HTTP virtualhost
+<VirtualHost *:${APP_PORT_HTTP}>
+  DocumentRoot /var/www/html
+$(if [ "${HTTPD_REDIRECT_HTTP_TO_HTTPS}" = "true" ]; then
+echo "  <IfModule mod_rewrite.c>
+    RewriteEngine on
+    RewriteCond %{REQUEST_URI} !\.well-known/acme-challenge
+    RewriteCond %{HTTPS} off
+    #RewriteCond %{HTTP_HOST} ^www\.(.*)$ [NC]
+    RewriteRule .? https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
+  </IfModule>"
+fi)
+  <Directory /var/www/html>
+    Options Includes FollowSymLinks MultiViews
+    AllowOverride All
+$(print_AllowFrom)
+  </Directory>
+</VirtualHost>
+
+$(if [ ! -z "${APP_FQDN}" ]; then
+echo "# HTTP virtualhost
+<VirtualHost *:${APP_PORT_HTTP}>
+  ServerName ${APP_FQDN}
+$(if [ "${HTTPD_REDIRECT_HTTP_TO_HTTPS}" = "true" ]; then
+echo "# enable http to https automatic rewrite
+<IfModule mod_rewrite.c>
+  RewriteEngine on
+  RewriteCond %{REQUEST_URI} !\.well-known/acme-challenge
+  RewriteCond %{HTTPS} off
+  #RewriteCond %{HTTP_HOST} ^www\.(.*)$ [NC]
+  RewriteRule .? https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
+</IfModule>"
+fi)
+  <Directory /var/www/html>
+    Options Includes FollowSymLinks MultiViews
+    DirectoryIndex index.php
+    AllowOverride All
+$(print_AllowFrom)
+  </Directory>
+</VirtualHost>"
+fi)
+
+$(if [ "${HTTPD_HTTPS_ENABLED}" = "true" ]; then
+echo "SSLPassPhraseDialog    builtin
+SSLSessionCache        shmcb:/run/apache2/sslcache(512000)
+SSLSessionCacheTimeout 300
+SSLCryptoDevice        builtin"
+fi)
+
+$(if [[ "${HTTPD_HTTPS_ENABLED}" = "true" && "${LETSENCRYPT_ENABLED}" != "true" ]]; then
+echo "# enable default ssl virtualhost with self signed certificate
+<VirtualHost _default_:${APP_PORT_HTTPS}>
+  ErrorLog                 ${appDataDirs[HTTPDLOGDIR]}/ssl_error.log
+  TransferLog              ${appDataDirs[HTTPDLOGDIR]}/ssl_access.log
+  LogLevel                 warn
+  SSLProtocol              all -SSLv3 -TLSv1 -TLSv1.1
+  SSLCipherSuite           ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384
+  SSLHonorCipherOrder      off
+  SSLSessionTickets        off
+  SSLCertificateFile       ${appDataDirs[SSLCRTDIR]}/iczrpbx.crt
+  SSLCertificateKeyFile    ${appDataDirs[SSLCRTDIR]}/iczrpbx.key
+  #SSLCertificateChainFile ${appDataDirs[SSLCRTDIR]}/chain.crt
+
+  <Directory /var/www/html>
+    Options Includes FollowSymLinks MultiViews
+    AllowOverride All
+$(print_AllowFrom)
+  </Directory>
+</VirtualHost>"
+fi)
+
+$(if [[ ! -z "${APP_FQDN}" && "${LETSENCRYPT_ENABLED}" = "true" && -e "/etc/letsencrypt/live/${APP_FQDN}/cert.pem" ]]; then
+echo "# HTTPS virtualhost
+<VirtualHost *:${APP_PORT_HTTPS}>
+  ServerName ${APP_FQDN}
+
+  SSLProtocol              all -SSLv3 -TLSv1 -TLSv1.1
+  SSLCipherSuite           ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384
+  SSLHonorCipherOrder      off
+  SSLSessionTickets        off
+  SSLCertificateChainFile /etc/letsencrypt/live/${APP_FQDN}/chain.pem
+  SSLCertificateFile      /etc/letsencrypt/live/${APP_FQDN}/cert.pem
+  SSLCertificateKeyFile   /etc/letsencrypt/live/${APP_FQDN}/privkey.pem
+
+  <Directory /var/www/html>
+    Options Includes FollowSymLinks MultiViews
+    AllowOverride All
+$(print_AllowFrom)
+  </Directory>
+</VirtualHost>"
+fi)
+
+" > "${HTTPD_CONF_DIR}/conf-enabled/virtual.conf"
+
+}
+
+cfgService_asterisk() {
+  echo "=> Starting Asterisk"
+}
+
+cfgService_iczrpbx() {
+  freepbx_reload() {
+    echo "---> reloading FreePBX..."
+    su - ${APP_USR} -s /bin/bash -c "fwconsole reload"
+  }
+  echo "---> verifing FreePBX configurations"
+  if [ ! -z "${APP_DATA}" ]; then
+    echo "---> using '${APP_DATA}' as basedir for FreePBX install"
+    for k in ${!fpbxDirs[@]}; do
+      v="${fpbxDirs[$k]}"
+      eval fpbxDirs[$k]=${APP_DATA}$v
+      [ ! -e "$v" ] && mkdir -p "$v"
+      if [ "$(stat -c "%U %G" "$v" 2>/dev/null)" != "${APP_USR} ${APP_GRP}" ];then
+      echo "---> fixing permissions for: $k=$v"
+      chown ${APP_USR}:${APP_GRP} "$v"
+      fi
+    done
+
+    for k in ${!fpbxFilesLog[@]}; do
+      v="${fpbxFilesLog[$k]}"
+      eval fpbxFilesLog[$k]=${APP_DATA}$v
+      [ ! -e "$v" ] && touch "$v"
+      if [ "$(stat -c "%U %G" "$v" 2>/dev/null)" != "${APP_USR} ${APP_GRP}" ];then
+      echo "---> fixing permissions for: $k=$v"
+      chown ${APP_USR}:${APP_GRP} "$v"
+      fi
+    done
+  fi
+  echo "[MySQL-asteriskcdrdb]
+Description = MariaDB connection to 'asteriskcdrdb' database
+driver = MySQL
+server = ${MYSQL_SERVER}
+database = asteriskcdrdb
+Port = ${APP_PORT_MYSQL}
+option = 3
+Charset=utf8" > /etc/odbc.ini
+
+  if [[ -e "${appFilesConf[FPBXCFGFILE]}" && ! -e ${APP_DATA}/.initialized ]]; then
+    echo "--> INFO: found '${appFilesConf[FPBXCFGFILE]}' configuration file but missing '${APP_DATA}/.initialized'... creating it right now"
+    echo "--> NOTE: if you want make an initial install, remove '${appFilesConf[FPBXCFGFILE]}' and '${APP_DATA}/.initialized' file"
+    touch "${APP_DATA}/.initialized"
+  fi
+  if [ ! -e ${APP_DATA}/.initialized ]; then
+      cfgService_freepbx_install
+    else
+      echo "--> INFO: FreePBX installation DETECTED! found '${APP_DATA}/.initialized' file"
+      [ ! -e "${appFilesConf[FPBXCFGFILE]}" ] && echo "---> WARNING: missing configuration file: ${appFilesConf[FPBXCFGFILE]}"
+      echo "---> reconfiguring '${appFilesConf[FPBXCFGFILE]}'..."
+      [[ ! -z "${APP_PORT_MYSQL}" && ${APP_PORT_MYSQL} -ne 3306 ]] && export MYSQL_SERVER="${MYSQL_SERVER}:${APP_PORT_MYSQL}"
+      sed "s/^\$amp_conf\['AMPDBUSER'\] =.*/\$amp_conf\['AMPDBUSER'\] = '${MYSQL_USER}';/"     -i "${appFilesConf[FPBXCFGFILE]}"
+      sed "s/^\$amp_conf\['AMPDBPASS'\] =.*/\$amp_conf\['AMPDBPASS'\] = '${MYSQL_PASSWORD}';/" -i "${appFilesConf[FPBXCFGFILE]}"
+      sed "s/^\$amp_conf\['AMPDBHOST'\] =.*/\$amp_conf\['AMPDBHOST'\] = '${MYSQL_SERVER}';/"   -i "${appFilesConf[FPBXCFGFILE]}"
+      sed "s/^\$amp_conf\['AMPDBNAME'\] =.*/\$amp_conf\['AMPDBNAME'\] = '${MYSQL_DATABASE}';/" -i "${appFilesConf[FPBXCFGFILE]}"
+  fi
+  echo "---> applying workarounds for FreePBX and Asterisk..."
+  [ ! -e "${fpbxDirs[ASTLOGDIR]}/full" ] && touch "${fpbxDirs[ASTLOGDIR]}/full" && chown ${APP_USR}:${APP_GRP} "${file}" "${fpbxDirs[ASTLOGDIR]}/full"
+  [ ! -e "/usr/sbin/fwconsole" ] && ln -s ${fpbxDirs[AMPBIN]}/fwconsole /usr/sbin/fwconsole
+  [ ! -e "/usr/sbin/amportal" ]  && ln -s ${fpbxDirs[AMPBIN]}/amportal  /usr/sbin/amportal
+  echo "---> reconfiguring FreePBX Advanced Settings if needed..."
+  set | grep ^"FREEPBX_" | grep -v -e ^"FREEPBX_MODULES_" -e ^"FREEPBX_VER=" | sed -e 's/^FREEPBX_//' -e 's/=/ /' | while read setting ; do
+    k="$(echo $setting | awk '{print $1}')"
+    v="$(echo $setting | awk '{print $2}')"
+    currentVal=$(fwconsole setting $k | awk -F"[][{}]" '{print $2}')
+    [ "$currentVal" = "true" ] && currentVal="1"
+    [ "$currentVal" = "false" ] && currentVal="0"
+    if [ "$currentVal" != "$v" ]; then
+      echo "---> reconfiguring advanced setting: ${k}=${v}"
+      fwconsole setting $k $v
+    fi
+  done
+
+  if [[ ! -z "${APP_AMI_USERNAME}" && ! -z "${APP_AMI_SECRET}" ]]; then
+    echo "---> adding asterisk manager user ${APP_AMI_USERNAME}..."
+    set +H
+    echo "[${APP_AMI_USERNAME}]
+secret = ${APP_AMI_SECRET}
+deny=0.0.0.0/0.0.0.0
+permit=127.0.0.1/255.255.255.0
+permit=172.16.0.0/255.240.0.0
+read = all
+write = all
+writetimeout = 100
+eventfilter=!Event: SuccessfulAuth
+eventfilter=!Event: ChallengeSent
+eventfilter=!Event: Registry
+eventfilter=!Event: InvalidPassword" > /etc/asterisk/manager_custom.conf
+    set -H
+  fi
+  echo "---> reconfiguring FreePBX SIP Settings if needed..."
+  for k in ${!fpbxSipSettings[@]}; do
+    v="${fpbxSipSettings[$k]}"
+    cVal=$(echo "<?php include '/etc/freepbx.conf'; \$FreePBX = FreePBX::Create(); echo \$FreePBX->sipsettings->getConfig('${k}');?>" | php)
+    if [ "$cVal" != "${v}" ];then
+      echo "---> reconfiguring sip setting: ${k}=${v}"
+      echo "<?php include '/etc/freepbx.conf'; \$FreePBX = FreePBX::Create(); \$FreePBX->sipsettings->setConfig('${k}',${v}); needreload();?>" | php
+    fi
+  done
+
+  echo "---> FIXME: temporary workarounds for FreePBX broken modules and configs..."
+  sed 's/^preload = chan_local.so/;preload = chan_local.so/' -i ${fpbxDirs[ASTETCDIR]}/modules.conf
+  sed 's/^enabled =.*/enabled = yes/' -i ${fpbxDirs[ASTETCDIR]}/hep.conf
+  sed 's/!count(\$dsn)/!@count(\$dsn)/' -i ${fpbxDirs[AMPWEBROOT]}/admin/libraries/DB.class.php
+}
+
+cfgService_freepbx_install() {
+  n=1 ; t=5
+
+  until [ $n -eq $t ]; do
+  echo "=> !!! FreePBX IS NOT INITIALIZED :: NEW INSTALLATION DETECTED !!!"
+  echo "--> missing '${APP_DATA}/.initialized' file... initializing FreePBX right now... try:[$n/$t]"
+  cd /usr/src/freepbx
+  if ! asterisk -r -x "core show version" 2>/dev/null ; then ./start_asterisk start ; fi
+  myn=1 ; myt=10
+  until [ $myn -eq $myt ]; do
+    mysql -h ${MYSQL_SERVER} -P ${APP_PORT_MYSQL} -u root --password=${MYSQL_ROOT_PASSWORD} -B -e "SELECT 1;" >/dev/null
+    RETVAL=$?
+    if [ $RETVAL = 0 ]; then
+        myn=$myt
+      else
+        let myn+=1
+        echo "--> WARNING: cannot connect to MySQL database '${MYSQL_SERVER}'... waiting database to become ready... retrying in 10 seconds... try:[$myn/$myt]"
+        sleep 10
+    fi
+  done
+
+  mysql -h ${MYSQL_SERVER} -P ${APP_PORT_MYSQL} -u root --password=${MYSQL_ROOT_PASSWORD} -B -e "CREATE DATABASE IF NOT EXISTS asteriskcdrdb;"
+  mysql -h ${MYSQL_SERVER} -P ${APP_PORT_MYSQL} -u root --password=${MYSQL_ROOT_PASSWORD} -B -e "GRANT ALL PRIVILEGES ON asteriskcdrdb.* TO 'asterisk'@'%' WITH GRANT OPTION;"
+  mysql -h ${MYSQL_SERVER} -P ${APP_PORT_MYSQL} -u root --password=${MYSQL_ROOT_PASSWORD} -B -e \
+    "CREATE TABLE IF NOT EXISTS asteriskcdrdb.voicemessages \
+    (msgnum INT(11) NULL DEFAULT NULL, \
+     dir VARCHAR(80) NOT NULL, \
+     context VARCHAR(80) NULL DEFAULT NULL, \
+     macrocontext VARCHAR(80) NULL DEFAULT NULL, \
+     callerid VARCHAR(40) NULL DEFAULT NULL, \
+     origtime VARCHAR(40) NULL DEFAULT NULL, \
+     duration VARCHAR(20) NULL DEFAULT NULL, \
+     flag VARCHAR(8) NULL DEFAULT NULL, \
+     mailboxuser VARCHAR(80) NULL DEFAULT NULL, \
+     mailboxcontext VARCHAR(80) NULL DEFAULT NULL, \
+     recording LONGBLOB NULL DEFAULT NULL, \
+     msg_id VARCHAR(40) NULL DEFAULT NULL) ENGINE = InnoDB;"
+  mysql -h ${MYSQL_SERVER} -P ${APP_PORT_MYSQL} -u root --password=${MYSQL_ROOT_PASSWORD} -B -e \
+    "CREATE TABLE IF NOT EXISTS asteriskcdrdb.cdr \
+    (calldate datetime NOT NULL DEFAULT '1000-01-01 00:00:00', \
+     clid varchar(80) NOT NULL DEFAULT '', \
+     src varchar(80) NOT NULL DEFAULT '', \
+     dst varchar(80) NOT NULL DEFAULT '', \
+     dcontext varchar(80) NOT NULL DEFAULT '', \
+     channel varchar(80) NOT NULL DEFAULT '', \
+     dstchannel varchar(80) NOT NULL DEFAULT '', \
+     lastapp varchar(80) NOT NULL DEFAULT '', \
+     lastdata varchar(80) NOT NULL DEFAULT '', \
+     duration int(11) NOT NULL DEFAULT 0, \
+     billsec int(11) NOT NULL DEFAULT 0, \
+     disposition varchar(45) NOT NULL DEFAULT '', \
+     amaflags int(11) NOT NULL DEFAULT 0, \
+     accountcode varchar(20) NOT NULL DEFAULT '', \
+     uniqueid varchar(32) NOT NULL DEFAULT '', \
+     userfield varchar(255) NOT NULL DEFAULT '', \
+     did varchar(50) NOT NULL DEFAULT '', \
+     recordingfile varchar(255) NOT NULL DEFAULT '', \
+     cnum varchar(80) NOT NULL DEFAULT '', \
+     cnam varchar(80) NOT NULL DEFAULT '', \
+     outbound_cnum varchar(80) NOT NULL DEFAULT '', \
+     outbound_cnam varchar(80) NOT NULL DEFAULT '', \
+     dst_cnam varchar(80) NOT NULL DEFAULT '', \
+     linkedid varchar(32) NOT NULL DEFAULT '', \
+     peeraccount varchar(80) NOT NULL DEFAULT '', \
+     sequence int(11) NOT NULL DEFAULT 0, \
+     KEY calldate (calldate), \
+     KEY dst (dst), \
+     KEY accountcode (accountcode), \
+     KEY uniqueid (uniqueid), \
+     KEY did (did), \
+     KEY recordingfile (recordingfile)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;"
+
+  FPBX_OPTS+=" --webroot=${fpbxDirs[AMPWEBROOT]}"
+  FPBX_OPTS+=" --astetcdir=${fpbxDirs[ASTETCDIR]}"
+  FPBX_OPTS+=" --astmoddir=${fpbxDirs[ASTMODDIR]}"
+  FPBX_OPTS+=" --astvarlibdir=${fpbxDirs[ASTVARLIBDIR]}"
+  FPBX_OPTS+=" --astagidir=${fpbxDirs[ASTAGIDIR]}"
+  FPBX_OPTS+=" --astspooldir=${fpbxDirs[ASTSPOOLDIR]}"
+  FPBX_OPTS+=" --astrundir=${fpbxDirs[ASTRUNDIR]}"
+  FPBX_OPTS+=" --astlogdir=${fpbxDirs[ASTLOGDIR]}"
+  FPBX_OPTS+=" --ampbin=${fpbxDirs[AMPBIN]}"
+  FPBX_OPTS+=" --ampsbin=${fpbxDirs[AMPSBIN]}"
+  FPBX_OPTS+=" --ampcgibin=${fpbxDirs[AMPCGIBIN]}"
+  FPBX_OPTS+=" --ampplayback=${fpbxDirs[AMPPLAYBACK]}"
+
+  echo "--> installing FreePBX in '${fpbxDirs[AMPWEBROOT]}'"
+  echo "---> START install FreePBX @ $(date)"
+  [[ ! -z "${APP_PORT_MYSQL}" && ${APP_PORT_MYSQL} -ne 3306 ]] && export MYSQL_SERVER="${MYSQL_SERVER}:${APP_PORT_MYSQL}"
+  set -x
+  ./install -n --skip-install --no-ansi --dbhost=${MYSQL_SERVER} --dbuser=${MYSQL_USER} --dbpass=${MYSQL_PASSWORD} ${FPBX_OPTS}
+  RETVAL=$?
+  set +x
+  echo "---> END install FreePBX @ $(date)"
+  unset FPBX_OPTS
+
+  if [ $RETVAL = 0 ]; then
+    [ ! -e "/usr/sbin/fwconsole" ] && ln -s ${fpbxDirs[ASTVARLIBDIR]}/bin/fwconsole /usr/sbin/fwconsole
+    [ ! -e "/usr/sbin/amportal" ]  && ln -s ${fpbxDirs[ASTVARLIBDIR]}/bin/amportal  /usr/sbin/amportal
+
+    if [ ! -z "${APP_DATA}" ]; then
+      for file in ${appFilesConf[@]}; do
+        chown ${APP_USR}:${APP_GRP} "${file}"
+      done
+      echo "--> fixing directory system paths in db configuration..."
+      for k in ${!fpbxDirs[@]} ${!fpbxFilesLog[@]}; do
+        fwconsole setting ${k} ${fpbxDirs[$k]}
+      done
+    fi
+
+    : ${FREEPBX_MODULES_CORE="
+      framework
+      core
+      dashboard
+      sipsettings
+      voicemail
+    "}
+
+    : ${FREEPBX_MODULES_PRE:="
+      pm2
+      userman
+    "}
+
+    : ${FREEPBX_MODULES_EXTRA:="
+      soundlang
+      callrecording
+      cdr
+      conferences
+      customappsreg
+      featurecodeadmin
+      infoservices
+      logfiles
+      music
+      manager
+      arimanager
+      filestore
+      recordings
+      announcement
+      asteriskinfo
+      backup
+      callforward
+      callwaiting
+      daynight
+      calendar
+      certman
+      cidlookup
+      contactmanager
+      donotdisturb
+      fax
+      findmefollow
+      iaxsettings
+      miscapps
+      miscdests
+      ivr
+      parking
+      phonebook
+      presencestate
+      printextensions
+      queues
+      cel
+      timeconditions
+      asterisk-cli
+      blacklist
+      configedit
+    "}
+
+    : ${FREEPBX_MODULES_DISABLED="
+      bulkhandler
+      speeddial
+      weakpasswords
+      ucp
+    "}
+    echo "--> enabling EXTENDED FreePBX repo..."
+    su - ${APP_USR} -s /bin/bash -c "fwconsole ma enablerepo extended"
+    su - ${APP_USR} -s /bin/bash -c "fwconsole ma enablerepo unsupported"
+    echo "--> starting cron to avoid crontab checks error..."
+    cron
+    echo "--> installing prerequisite FreePBX modules from local install into '${fpbxDirs[AMPWEBROOT]}/admin/modules'"
+    for module in ${FREEPBX_MODULES_PRE}; do
+      su - ${APP_USR} -s /bin/bash -c "echo \"---> installing module: ${module}\" && fwconsole ma install ${module}"
+    done
+    echo "--> fixing FreePBX permissions..."
+    fwconsole chown
+    echo "--> enabling pm2 module..."
+    fwconsole ma enable pm2
+    freepbx_reload
+    echo "--> installing Extra FreePBX modules from local install into '${fpbxDirs[AMPWEBROOT]}/admin/modules'"
+    for module in ${FREEPBX_MODULES_EXTRA}; do
+      su - ${APP_USR} -s /bin/bash -c "echo \"---> installing module: ${module}\" && fwconsole ma install ${module}"
+    done
+    echo "--> fixing FreePBX permissions..."
+    fwconsole chown
+    freepbx_reload
+    echo "--> upgrading modules..."
+    fwconsole ma upgradeall
+    echo "--> fixing FreePBX permissions..."
+    fwconsole chown
+    freepbx_reload
+    echo "--> stopping cron..."
+    killall -9 cron
+    touch "${APP_DATA}/.initialized"
+  fi
+
+  if [ $RETVAL = 0 ]; then
+      n=$t
+    else
+      let n+=1
+      echo "--> problem detected... restarting in 10 seconds... try:[$n/$t]"
+      sleep 10
+  fi
+  done
+
+  if asterisk -r -x "core show version" 2>/dev/null ; then
+    echo "--> stopping Asterisk"
+    asterisk -r -x "core stop now"
+    echo "=> Finished installing FreePBX"
+  fi
+}
+
+runHooks() {
+  mkdir -p /var/log/supervisor /var/log/dbconfig-common /var/log/apt /var/log/apache2 /var/log/asterisk/cdr-csv
+  touch /var/log/wtmp /var/log/lastlog
+  [ ! -e /sbin/nologin ] && ln -s /usr/sbin/nologin /sbin/nologin
+
+  if [ ! -z "${APP_DATA}" ]; then
+    echo "=> Persistent storage path detected... relocating and reconfiguring system data and configuration files using base: ${APP_DATA}"
+    for dir in ${appDataDirs[@]}
+      do
+        dir="${APP_DATA}${dir}"
+        if [ ! -e "${dir}" ];then
+          echo "--> creating missing dir: '$dir'"
+          mkdir -p "${dir}"
+        fi
+      done
+
+    for dir in ${appDataDirs[@]}; do
+      symlinkDir "${dir}" "${APP_DATA}${dir}"
+    done
+
+    for file in ${appFilesConf[@]}; do
+      symlinkFile "${file}" "${APP_DATA}${file}"
+    done
+   else
+    echo "=> WARNING: No Persistent storage path detected... the configurations will be lost on container restart"
+  fi
+
+  chkService POSTFIX_ENABLED
+  chkService CRON_ENABLED
+  chkService FAIL2BAN_ENABLED
+  chkService HTTPD_ENABLED
+  chkService ASTERISK_ENABLED
+  chkService ICZRPBX_ENABLED
+  [[ ! -z "${APP_FQDN}" && "${LETSENCRYPT_ENABLED}" = "true" ]] && cfgService_letsencrypt
+}
+
+runHooks

+ 62 - 0
filesystem/entrypoint.sh

@@ -0,0 +1,62 @@
+#!/bin/bash
+
+appHooks() {
+  : ${APP_RELINK:=false}
+
+  if [ "$APP_RELINK" = "true" ]; then
+  [ ! -z "${APP_CONF}" ] && relink_dir "${APP_CONF_DEFAULT}" "${APP_CONF}"
+  [ ! -z "${APP_DATA}" ] && relink_dir "${APP_DATA_DEFAULT}" "${APP_DATA}"
+  [ ! -z "${APP_LOGS}" ] && relink_dir "${APP_LOGS_DEFAULT}" "${APP_LOGS}"
+  [ ! -z "${APP_TEMP}" ] && relink_dir "${APP_TEMP_DEFAULT}" "${APP_TEMP}"
+  [ ! -z "${APP_WORK}" ] && relink_dir "${APP_WORK_DEFAULT}" "${APP_WORK}"
+  [ ! -z "${APP_SHARED}" ] && relink_dir "${APP_SHARED_DEFAULT}" "${APP_SHARED}"
+  else
+    echo "=> Skipping APP directories relinking: APP_RELINK=$APP_RELINK"
+  fi
+
+  echo "=> Executing hooks:"
+  . /entrypoint-hooks.sh
+  echo "-------------------------------------------------------------------------------"
+}
+
+relink_dir() {
+	local dir_default="$1"
+	local dir_custom="$2"
+	[ ! -e "$dir_default" ] && mkdir -p "$dir_default"
+	[ ! -e "$(dirname "$dir_custom")" ] && mkdir -p "$(dirname "$dir_custom")"
+	echo "Directory container override detected! default: $dir_default custom: $dir_custom"
+	if [ ! -e "$dir_custom" ]; then
+		echo -e -n "=> moving the $dir_default directory to $dir_custom ..."
+		mv "$dir_default" "$dir_custom"
+	else
+		echo -e -n "=> directory $dir_custom already exist... "
+		mv "$dir_default" "$dir_default".dist
+	fi
+	echo "linking $dir_custom into $dir_default"
+	ln -s "$dir_custom" "$dir_default"
+}
+
+appHooks
+
+: ${APP_RUNAS:=false}
+: ${ENTRYPOINT_TINI:=false}
+: ${MULTISERVICE:=false}
+
+if [ "$MULTISERVICE" = "true" ]; then
+    CMD="runsvdir -P /etc/service"
+elif [ "$APP_RUNAS" = "true" ]; then
+    CMD="runuser -p -u $APP_USR -- $@"
+  else
+    CMD="$@"
+fi
+
+[ "$ENTRYPOINT_TINI" = "true" ] && CMD="tini -g -- $CMD"
+
+echo "=> Executing entrypoint command: $CMD"
+echo "==============================================================================="
+[ ! -z "$UMASK" ] && umask $UMASK
+set -x
+
+exec $CMD
+
+exit $?

+ 9 - 0
filesystem/etc/fail2ban/filter.d/freepbx.conf

@@ -0,0 +1,9 @@
+[INCLUDES]
+
+[Definition]
+
+failregex = .* Authentication failure for .* from <HOST>\.
+
+ignoreregex =
+
+

+ 55 - 0
filesystem/etc/fail2ban/jail.d/99-local.conf

@@ -0,0 +1,55 @@
+[DEFAULT]
+ignoreip = 127.0.0.0/8 10.0.0.0/8 172.16.0.0/12 192.168.0.0/16
+bantime  = 300
+findtime  = 3600
+maxretry = 10
+banaction = iptables-allports
+destemail = root@localhost
+sender = fail2ban@localhost.localdomain
+
+action = %(action_)s
+
+logtarget = /var/log/fail2ban/fail2ban.log
+apache_error_log = /var/log/apache2/*error*log
+apache_access_log = /var/log/apache2/*access*log
+
+[recidive]
+enabled  = true
+logpath  = /var/log/fail2ban/fail2ban.log
+action   = %(action_mwl)s
+protocol = all
+bantime  = 1814400 ; 3 weeks (ipset support max of 2147483 secs)
+findtime = 15552000 ;6 months
+maxretry = 30
+
+[asterisk]
+enabled = true
+logpath = /var/log/asterisk/full
+
+[freepbx]
+enabled = true
+logpath = /var/log/asterisk/freepbx_security.log
+
+[apache-auth]
+enabled = true
+
+[apache-badbots]
+enabled = true
+
+[apache-noscript]
+enabled = true
+
+[apache-overflows]
+enabled = true
+
+[apache-nohome]
+enabled = true
+
+[apache-botsearch]
+enabled = true
+
+[apache-fakegooglebot]
+enabled = true
+
+[apache-shellshock]
+enabled = true

+ 2 - 0
filesystem/etc/fail2ban/jail.d/defaults-debian.conf

@@ -0,0 +1,2 @@
+[sshd]
+enabled = false

+ 15 - 0
filesystem/etc/logrotate.d/apache2

@@ -0,0 +1,15 @@
+/var/log/httpd/*log {
+  daily
+  ifempty
+  rotate 7
+  missingok
+  compress
+  dateext
+  copytruncate
+  sharedscripts
+  postrotate
+    if /usr/bin/supervisorctl status httpd > /dev/null 2>/dev/null ; then \
+      /usr/bin/supervisorctl restart httpd > /dev/null 2>/dev/null; \
+    fi;
+  endscript
+} 

+ 15 - 0
filesystem/etc/logrotate.d/asterisk

@@ -0,0 +1,15 @@
+/var/log/asterisk/full
+/var/log/asterisk/messages
+/var/log/asterisk/security
+/var/log/asterisk/freepbx_dbug
+/var/log/asterisk/*_log
+/var/log/asterisk/*.log {
+    daily
+    rotate 7
+    compress
+    dateext
+    ifempty
+    missingok
+    su asterisk asterisk
+    copytruncate
+}

+ 14 - 0
filesystem/etc/logrotate.d/fail2ban

@@ -0,0 +1,14 @@
+/var/log/fail2ban/fail2ban.log {
+    monthly
+    ifempty
+    rotate 12
+    missingok
+    compress
+    dateext
+    missingok
+    notifempty
+    postrotate
+      /usr/bin/fail2ban-client flushlogs >/dev/null || true
+    endscript
+}
+ 

+ 17 - 0
filesystem/etc/odbcinst.ini

@@ -0,0 +1,17 @@
+# Driver from the mysql-connector-odbc package
+# Setup from the unixODBC package
+[MySQL]
+Description	= ODBC for MySQL
+Driver		= /usr/lib/x86_64-linux-gnu/odbc/libmaodbc.so
+Setup		= /usr/lib/x86_64-linux-gnu/odbc/libodbcmyS.so
+Driver64	= /usr/lib/x86_64-linux-gnu/odbc/libmaodbc.so
+Setup64		= /usr/lib/x86_64-linux-gnu/odbc/libodbcmyS.so
+FileUsage	= 1
+
+# Driver from the mariadb-connector-odbc package
+# Setup from the unixODBC package
+[MariaDB]
+Description     = ODBC for MariaDB
+Driver          = /usr/lib/x86_64-linux-gnu/odbc/libmaodbc.so
+Driver64        = /usr/lib/x86_64-linux-gnu/odbc/libmaodbc.so
+FileUsage       = 1

+ 24 - 0
filesystem/etc/php/7.3/apache2/conf.d/99-local.ini

@@ -0,0 +1,24 @@
+short_open_tag = On
+max_execution_time = 600
+memory_limit = 512M
+error_reporting = E_ALL & ~E_NOTICE & ~E_STRICT & ~E_DEPRECATED
+display_startup_errors = On
+display_errors = On
+log_errors = On
+post_max_size = 128M
+upload_max_filesize = 128M
+allow_url_include = On
+magic_quotes_gpc = off
+date.timezone = Europe/Moscow
+
+zlib.output_compression = Off
+
+opcache.enable=1
+opcache.enable_cli=0
+opcache.memory_consumption=128
+opcache.interned_strings_buffer=8
+opcache.max_accelerated_files=50000
+opcache.file_update_protection=5
+opcache.validate_timestamps=1
+opcache.revalidate_freq=5
+opcache.fast_shutdown=1

+ 24 - 0
filesystem/etc/php/7.4/apache2/conf.d/99-local.ini

@@ -0,0 +1,24 @@
+short_open_tag = On
+max_execution_time = 600
+memory_limit = 512M
+error_reporting = E_ALL & ~E_NOTICE & ~E_STRICT & ~E_DEPRECATED
+display_startup_errors = On
+display_errors = On
+log_errors = On
+post_max_size = 128M
+upload_max_filesize = 128M
+allow_url_include = On
+magic_quotes_gpc = off
+date.timezone = Europe/Moscow
+
+zlib.output_compression = Off
+
+opcache.enable=1
+opcache.enable_cli=0
+opcache.memory_consumption=128
+opcache.interned_strings_buffer=8
+opcache.max_accelerated_files=50000
+opcache.file_update_protection=5
+opcache.validate_timestamps=1
+opcache.revalidate_freq=5
+opcache.fast_shutdown=1

+ 15 - 0
filesystem/etc/supervisor/conf.d/asterisk.conf

@@ -0,0 +1,15 @@
+[program:asterisk]
+command=asterisk -f -U asterisk -G asterisk -vvvg -c
+autostart=false
+autorestart=true
+startretries=3
+startsecs=5
+user=asterisk
+killasgroup=true
+stopasgroup=true
+stdout_logfile=/dev/stdout
+stderr_logfile=/dev/stderr
+stdout_logfile_maxbytes=0
+stderr_logfile_maxbytes=0
+stdout_events_enabled = true
+stderr_events_enabled = true

+ 15 - 0
filesystem/etc/supervisor/conf.d/cron.conf

@@ -0,0 +1,15 @@
+[program:cron]
+command=cron -f
+autostart=false
+autorestart=true
+startretries=3
+startsecs=1
+user=root
+killasgroup=true
+stopasgroup=true
+stdout_logfile=/dev/stdout
+stderr_logfile=/dev/stderr
+stdout_logfile_maxbytes=0
+stderr_logfile_maxbytes=0
+stdout_events_enabled = true
+stderr_events_enabled = true

+ 15 - 0
filesystem/etc/supervisor/conf.d/fail2ban.conf

@@ -0,0 +1,15 @@
+[program:fail2ban]
+command=fail2ban-server -xf start
+autostart=false
+autorestart=true
+startretries=3
+startsecs=5
+user=root
+killasgroup=true
+stopasgroup=true
+stdout_logfile=/dev/stdout
+stderr_logfile=/dev/stderr
+stdout_logfile_maxbytes=0
+stderr_logfile_maxbytes=0
+stdout_events_enabled = true
+stderr_events_enabled = true

+ 15 - 0
filesystem/etc/supervisor/conf.d/httpd.conf

@@ -0,0 +1,15 @@
+[program:httpd]
+command=/usr/bin/pidproxy /var/run/apache2/apache2.pid /bin/bash -c "/usr/sbin/apache2ctl -D FOREGROUND"
+autostart=false
+autorestart=true
+startretries=3
+startsecs=1
+user=root
+killasgroup=true
+stopasgroup=true
+stdout_logfile=/dev/stdout
+stderr_logfile=/dev/stderr
+stdout_logfile_maxbytes=0
+stderr_logfile_maxbytes=0
+stdout_events_enabled = true
+stderr_events_enabled = true

+ 15 - 0
filesystem/etc/supervisor/conf.d/iczrpbx.conf

@@ -0,0 +1,15 @@
+[program:iczrpbx]
+command=starticzrpbx
+autostart=false
+autorestart=true
+startretries=3
+startsecs=1
+user=root
+killasgroup=true
+stopasgroup=true
+stdout_logfile=/dev/stdout
+stderr_logfile=/dev/stderr
+stdout_logfile_maxbytes=0
+stderr_logfile_maxbytes=0
+stdout_events_enabled = true
+stderr_events_enabled = true

+ 15 - 0
filesystem/etc/supervisor/conf.d/postfix.conf

@@ -0,0 +1,15 @@
+[program:postfix]
+command=sh -c "postfix start-fg || postfix stop"
+autostart=false
+autorestart=true
+startretries=3
+startsecs=1
+user=root
+killasgroup=true
+stopasgroup=true
+stdout_logfile=/dev/stdout
+stderr_logfile=/dev/stderr
+stdout_logfile_maxbytes=0
+stderr_logfile_maxbytes=0
+stdout_events_enabled = true
+stderr_events_enabled = true

+ 28 - 0
filesystem/usr/local/bin/telegram-mailgate.py

@@ -0,0 +1,28 @@
+#!/usr/bin/env python3
+import sys
+import argparse
+import email
+import requests
+
+if __name__ == '__main__':
+  arg_parser = argparse.ArgumentParser()
+  arg_parser.add_argument('--from')
+  arg_parser.add_argument('--key')
+  arg_parser.add_argument('--chatid')
+  arg_parser.add_argument('--queue-id', default=0)
+  arg_parser.add_argument('to', nargs='+')
+  group = arg_parser.add_mutually_exclusive_group()
+  group.add_argument('--raw', action='store_true')
+  args = arg_parser.parse_args()
+  raw_content = sys.stdin.read()
+  if args.raw:
+    content = raw_content
+  else:
+    mail = email.message_from_string(raw_content)
+    content = mail.get_payload()
+  if ((args.key is not None) and
+      (args.chatid is not None)):
+    content = content.replace("\n\n","\n")
+    params = {'chat_id':args.chatid, 'text':content}
+    requests.post('https://api.telegram.org/bot' + args.key + '/sendMessage', data=params)
+  exit(0)

+ 16 - 0
filesystem/usr/local/sbin/starticzrpbx

@@ -0,0 +1,16 @@
+#! /usr/bin/env bash
+set -eu
+pidfile=/var/run/asterisk/asterisk.pid
+command=/usr/sbin/fwconsole
+function kill_app(){
+    $command stop
+    exit $?
+}
+trap "kill_app" SIGINT SIGTERM
+$command chown
+$command start -q
+sleep 2
+while [ -f $pidfile ] && kill -0 $(cat $pidfile) ; do
+    sleep 5
+done
+exit 1000