#!/bin/bash ## ## Install i-doit on a GNU/Linux operating system ## ## ## Copyright (C) 2017-22 synetics GmbH, ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU Affero General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU Affero General Public License for more details. ## ## You should have received a copy of the GNU Affero General Public License ## along with this program. If not, see . ## set -euo pipefail IFS=$'\n\t' ## ## Configuration ## ## You **should not** edit these settings. ## You will be asked for your preferred settings. ## To overwrite these settings export them before running this script. ## For example: ## export MARIADB_INNODB_BUFFER_POOL_SIZE=2G ## ./idoit-install ## : "${MARIADB_HOSTNAME:="localhost"}" : "${MARIADB_SUPERUSER_USERNAME:="root"}" : "${MARIADB_SUPERUSER_PASSWORD:="idoit"}" : "${MARIADB_INNODB_BUFFER_POOL_SIZE:="1G"}" : "${IDOIT_ADMIN_CENTER_PASSWORD:="admin"}" : "${MARIADB_IDOIT_USERNAME:="idoit"}" : "${MARIADB_IDOIT_PASSWORD:="idoit"}" : "${IDOIT_DEFAULT_TENANT:="CMDB"}" : "${INSTALL_DIR:="/var/www/html"}" : "${UPDATE_FILE_PRO:="https://i-doit.com/updates.xml"}" : "${UPDATE_FILE_OPEN:="https://i-doit.org/updates.xml"}" : "${UPDATE_FILE_EVAL:="https://eval-downloads.i-doit.com/idoit-eval-automatic.zip"}" : "${SCRIPT_SETTINGS:="/etc/i-doit/i-doit.sh"}" : "${CONSOLE_BIN:="/usr/local/bin/idoit"}" : "${JOBS_BIN:="/usr/local/bin/idoit-jobs"}" : "${CRON_FILE:="/etc/cron.d/i-doit"}" : "${BACKUP_DIR:="/var/backups/i-doit"}" : "${RECOMMENDED_PHP_VERSION:="8.0"}" : "${RECOMMENDED_MARIADB_VERSION:="10.6"}" ## ## Runtime settings ## ## DO NOT EDIT THESE SETTINGS. ## OS="" DATE="$(date +%Y-%m-%d)" TMP_DIR="/tmp/i-doit_${DATE}" APACHE_USER="www-data" APACHE_GROUP="www-data" MIN_CPU_CORES=2 ## Be tolerant, use 1000 instead of 1024: MIN_RAM=$((1000 * 1000 * 1000 * 2)) APACHE_UNIT="" MARIADB_UNIT="" MEMCACHED_UNIT="" PHP_FPM_UNIT="" APACHE_CONFIG_FILE="" MARIADB_CONFIG_FILE="" PHP_CONFIG_FILE="" MARIADB_SOCKET="" PHP_FPM_SOCKET="" APACHE_HTACCESS_SUBSTITUTION="## Insert content from .htaccess file" BASENAME=$(basename "$0") PROJECT_VERSION="0.14-dev" MARIADB_BIN="" SUDO_BIN="" UNZIP_BIN="" WGET_BIN="" PHP_BIN="" ## /etc/os-release comes with these variables: ## NAME, VERSION, VERSION_ID, PRETTY_NAME and some more… NAME="" VERSION="" VERSION_ID="" PRETTY_NAME="" ##-------------------------------------------------------------------------------------------------- function execute { local status=0 local ip_address="" log "Install i-doit on a GNU/Linux operating system" log "" log "Attention:" log "This script alters your OS. It will install new packages and will change configuration settings." log "Only use it on a fresh installation of a GNU/Linux OS." log "It comes with absolutely no warranty." log "Read the documentation carefully before you continue:" log "" log " https://github.com/i-doit/scripts" log "" log "This script will automatically…" log "" log " 1) install additional distribution packages," log " 2) alter configuration of your PHP environment," log " 3) alter configuration of your Apache Web server," log " 4) alter configuration of your MariaDB DBMS, and" log " 5) download and install the latest version of i-doit pro or open" log " 6) deploy cron jobs and an easy-to-use CLI tool for your i-doit instance" log " 7) deploy scripts to backup and restore your i-doit instance" log "" log "You may skip any step if you like." log "" askYesNo "Do you really want to continue?" || cancel log "\\n--------------------------------------------------------------------------------\\n" identifyOS log "\\n--------------------------------------------------------------------------------\\n" checkHardwareRequirements log "\\n--------------------------------------------------------------------------------\\n" log "This script needs Web access (HTTP/HTTPS on ports 80/443)." askNoYes "Do you want to configure a proxy server?" || configureProxy log "\\n--------------------------------------------------------------------------------\\n" askYesNo "Do you want to configure the operating system?" && configureOS log "\\n--------------------------------------------------------------------------------\\n" checkSoftwareRequirements log "\\n--------------------------------------------------------------------------------\\n" askYesNo "Do you want to configure the PHP environment?" && configurePHP && configurePHPFPM log "\\n--------------------------------------------------------------------------------\\n" askYesNo "Do you want to configure the Apache Web server?" && configureApache log "\\n--------------------------------------------------------------------------------\\n" askYesNo "Do you want to configure MariaDB?" && configureMariaDB log "\\n--------------------------------------------------------------------------------\\n" if askYesNo "Do you want to download and install i-doit automatically?"; then prepareIDoit updateApacheConfig installIDoit ip_address=$(ip route get 1 | sed 's/^.*src \([^ ]*\).*$/\1/;q') log "Your setup is ready. Navigate to" log "" log " http://${ip_address}/" log "" log "with your Web browser and login to the Admin Center 'admin' to create Tenants manually" log "\\n--------------------------------------------------------------------------------\\n" askYesNo "Do you want to create the initial i-doit tenant automatically?" && create_tenant status=1 else log "Your operating system is prepared for the installation of i-doit." log "To complete the setup please follow the instructions as described in the i-doit Knowledge Base:" log "" log " https://kb.i-doit.com/display/en/Setup" fi if [[ "$status" = 1 ]]; then log "\\n--------------------------------------------------------------------------------\\n" if askYesNo "Do you want to configure i-doit cron jobs?"; then deployScriptSettings deployConsole deployJobScript deployCronJobs log "Cron jobs are successfully activated. To change e-mail address, execution date and time please edit this file:" log "" log " $CRON_FILE" log "" log "There is also a script available for all system users to execute the i-doit console command line tool:" log "" log " idoit" log "" log "The needed cron jobs are defined here:" log "" log " $JOBS_BIN" log "" log "If needed you can change the settings of both the i-doit console and the cron jobs:" log "" log " $SCRIPT_SETTINGS" status=2 fi fi if [[ "$status" = 2 ]]; then log "\\n--------------------------------------------------------------------------------\\n" if askYesNo "Do you want to backup i-doit automatically?"; then deployBackupAndRestore log "Backups are successfully activated. Each night a backup will be created." log "Backups will be kept for 30 days:" log "" log " $BACKUP_DIR" log "" log "You may create a backup manually:" log "" log " idoit-backup" log "" log "Of course, you are able to restore i-doit from the lastest backup:" log "" log " idoit-restore" log "" log "Settings may be changed here:" log "" log " $SCRIPT_SETTINGS" fi fi log "\\n--------------------------------------------------------------------------------\\n" case "$OS" in "ubuntu1604") log "To garantee that all your changes take effect you should restart your system." ;; esac } function identifyOS { if [[ ! -f "/etc/os-release" ]]; then log "File /etc/os-release is missing" abort "Unable to identify operating system" fi # shellcheck source=/dev/null source "/etc/os-release" log "Operating system identified as ${PRETTY_NAME}" if [[ "$NAME" == "CentOS Linux" && "$VERSION_ID" == "7" ]]; then log "Warning: This OS is not officially supported by i-doit" log "Warning: CentOS 7 is out-dated. Please consider to upgrade your OS." askNoYes "Do you really want to continue?" || cancel OS="centos7" APACHE_USER="apache" APACHE_GROUP="apache" APACHE_CONFIG_FILE="/etc/httpd/conf.d/i-doit.conf" MARIADB_CONFIG_FILE="/etc/my.cnf.d/99-i-doit.cnf" PHP_CONFIG_FILE="/etc/php.d/i-doit.ini" MARIADB_SOCKET="/var/lib/mysql/mysql.sock" PHP_FPM_SOCKET="/var/run/php-fpm/php-fpm.sock" APACHE_UNIT="httpd" MARIADB_UNIT="mariadb" MEMCACHED_UNIT="memcached" PHP_FPM_UNIT="php-fpm" elif [[ "$NAME" == "CentOS Linux" && "$VERSION_ID" == "8" ]]; then log "Warning: This OS is not officially supported by i-doit" askNoYes "Do you really want to continue?" || cancel OS="centos8" APACHE_USER="apache" APACHE_GROUP="apache" APACHE_CONFIG_FILE="/etc/httpd/conf.d/i-doit.conf" MARIADB_CONFIG_FILE="/etc/my.cnf.d/99-i-doit.cnf" PHP_CONFIG_FILE="/etc/php.d/i-doit.ini" MARIADB_SOCKET="/var/lib/mysql/mysql.sock" PHP_FPM_SOCKET="/var/run/php-fpm/php-fpm.sock" APACHE_UNIT="httpd" MARIADB_UNIT="mariadb" MEMCACHED_UNIT="memcached" PHP_FPM_UNIT="php-fpm" elif [[ "$NAME" == "Debian GNU/Linux" && "$VERSION" == "12 (bookworm)" ]]; then export DEBIAN_FRONTEND="noninteractive" OS="debian12" APACHE_USER="www-data" APACHE_GROUP="www-data" APACHE_CONFIG_FILE="/etc/apache2/sites-available/i-doit.conf" MARIADB_CONFIG_FILE="/etc/mysql/mariadb.conf.d/99-i-doit.cnf" PHP_CONFIG_FILE="/etc/php/8.2/mods-available/i-doit.ini" MARIADB_SOCKET="/var/run/mysqld/mysqld.sock" PHP_FPM_SOCKET="/var/run/php/php8.2-fpm.sock" APACHE_UNIT="apache2" MARIADB_UNIT="mysql" MEMCACHED_UNIT="memcached" PHP_FPM_UNIT="php8.2-fpm" elif [[ "$NAME" == "Debian GNU/Linux" && "$VERSION" == "11 (bullseye)" ]]; then export DEBIAN_FRONTEND="noninteractive" OS="debian11" APACHE_USER="www-data" APACHE_GROUP="www-data" APACHE_CONFIG_FILE="/etc/apache2/sites-available/i-doit.conf" MARIADB_CONFIG_FILE="/etc/mysql/mariadb.conf.d/99-i-doit.cnf" PHP_CONFIG_FILE="/etc/php/7.4/mods-available/i-doit.ini" MARIADB_SOCKET="/var/run/mysqld/mysqld.sock" PHP_FPM_SOCKET="/var/run/php/php7.4-fpm.sock" APACHE_UNIT="apache2" MARIADB_UNIT="mysql" MEMCACHED_UNIT="memcached" PHP_FPM_UNIT="php7.4-fpm" elif [[ "$NAME" == "Debian GNU/Linux" && "$VERSION" == "10 (buster)" ]]; then abort "Error: This version of Debian GNU/Linux is not supported anymore. Please upgrade to Debian 12." elif [[ "$NAME" == "Debian GNU/Linux" && "$VERSION" == "9 (stretch)" ]]; then abort "Error: This version of Debian GNU/Linux is not supported anymore. Please upgrade to Debian 12." elif [[ "$NAME" == "Debian GNU/Linux" && "$VERSION" == "8 (jessie)" ]]; then abort "Error: This version of Debian GNU/Linux is not supported anymore. Please upgrade to Debian 12." elif [[ "$NAME" == "Red Hat Enterprise Linux" && "$VERSION_ID" == 8* ]]; then OS="rhel8" APACHE_USER="apache" APACHE_GROUP="apache" APACHE_CONFIG_FILE="/etc/httpd/conf.d/i-doit.conf" MARIADB_CONFIG_FILE="/etc/my.cnf.d/99-i-doit.cnf" PHP_CONFIG_FILE="/etc/php.d/i-doit.ini" MARIADB_SOCKET="/var/lib/mysql/mysql.sock" PHP_FPM_SOCKET="/var/run/php-fpm/php-fpm.sock" APACHE_UNIT="httpd" MARIADB_UNIT="mariadb" MEMCACHED_UNIT="memcached" PHP_FPM_UNIT="php-fpm" elif [[ "$NAME" == "Red Hat Enterprise Linux Server" && "$VERSION_ID" == 7* ]]; then log "Warning: RHEL 7 is out-dated. Please consider to upgrade your OS." askNoYes "Do you really want to continue?" || cancel OS="rhel7" APACHE_USER="apache" APACHE_GROUP="apache" APACHE_CONFIG_FILE="/etc/httpd/conf.d/i-doit.conf" MARIADB_CONFIG_FILE="/etc/my.cnf.d/99-i-doit.cnf" PHP_CONFIG_FILE="/etc/php.d/i-doit.ini" MARIADB_SOCKET="/var/lib/mysql/mysql.sock" PHP_FPM_SOCKET="/var/run/php-fpm/php-fpm.sock" APACHE_UNIT="httpd" MARIADB_UNIT="mariadb" MEMCACHED_UNIT="memcached" PHP_FPM_UNIT="php-fpm" elif [[ "$NAME" == "SLES" && "$VERSION" == 15* ]]; then OS="sles15" INSTALL_DIR="/srv/www/htdocs" APACHE_USER="wwwrun" APACHE_GROUP="www" APACHE_CONFIG_FILE="/etc/apache2/vhosts.d/i-doit.conf" MARIADB_CONFIG_FILE="/etc/my.cnf.d/99-i-doit.cnf" PHP_CONFIG_FILE="/etc/php7/conf.d/i-doit.ini" MARIADB_SOCKET="/var/run/mysql/mysql.sock" PHP_FPM_SOCKET="/var/run/php-fpm.sock" APACHE_UNIT="apache2" MARIADB_UNIT="mariadb" MEMCACHED_UNIT="memcached" PHP_FPM_UNIT="php-fpm" elif [[ "$NAME" = "SLES" && "$VERSION_ID" == 12* ]]; then abort "Error: SLES 12 is out-dated. It's not supported anymore. Please upgrade." elif [[ "$NAME" == "openSUSE Leap" && "$VERSION" == 15* ]]; then OS="opensuse15" INSTALL_DIR="/srv/www/htdocs" APACHE_USER="wwwrun" APACHE_GROUP="www" APACHE_CONFIG_FILE="/etc/apache2/vhosts.d/i-doit.conf" MARIADB_CONFIG_FILE="/etc/my.cnf.d/99-i-doit.cnf" PHP_CONFIG_FILE="/etc/php7/conf.d/i-doit.ini" MARIADB_SOCKET="/var/run/mysql/mysql.sock" PHP_FPM_SOCKET="/var/run/php-fpm.sock" APACHE_UNIT="apache2" MARIADB_UNIT="mariadb" MEMCACHED_UNIT="memcached" PHP_FPM_UNIT="php-fpm" elif [[ "$NAME" = "openSUSE" && "$VERSION_ID" == 12* ]]; then abort "Error: openSUSE 12 is out-dated. It's not supported anymore. Please upgrade." elif [[ "$NAME" == "Ubuntu" && "$VERSION_ID" == "22.04" ]]; then export DEBIAN_FRONTEND="noninteractive" OS="ubuntu2204" APACHE_USER="www-data" APACHE_GROUP="www-data" APACHE_CONFIG_FILE="/etc/apache2/sites-available/i-doit.conf" MARIADB_CONFIG_FILE="/etc/mysql/mariadb.conf.d/99-i-doit.cnf" PHP_CONFIG_FILE="/etc/php/8.1/mods-available/i-doit.ini" MARIADB_SOCKET="/var/run/mysqld/mysqld.sock" PHP_FPM_SOCKET="/var/run/php/php8.1-fpm.sock" APACHE_UNIT="apache2" MARIADB_UNIT="mysql" MEMCACHED_UNIT="memcached" PHP_FPM_UNIT="php8.1-fpm" elif [[ "$NAME" == "Ubuntu" && "$VERSION_ID" == "20.04" ]]; then export DEBIAN_FRONTEND="noninteractive" OS="ubuntu2004" APACHE_USER="www-data" APACHE_GROUP="www-data" APACHE_CONFIG_FILE="/etc/apache2/sites-available/i-doit.conf" MARIADB_CONFIG_FILE="/etc/mysql/mariadb.conf.d/99-i-doit.cnf" PHP_CONFIG_FILE="/etc/php/7.4/mods-available/i-doit.ini" MARIADB_SOCKET="/var/run/mysqld/mysqld.sock" PHP_FPM_SOCKET="/var/run/php/php7.4-fpm.sock" APACHE_UNIT="apache2" MARIADB_UNIT="mysql" MEMCACHED_UNIT="memcached" PHP_FPM_UNIT="php7.4-fpm" elif [[ "$NAME" == "Ubuntu" && "$VERSION_ID" == "18.04" ]]; then abort "Error: Ubuntu 18.04 is out-dated. It's not supported anymore. Please upgrade." elif [[ "$NAME" == "Ubuntu" && "$VERSION_ID" == "16.04" ]]; then abort "Error: Ubuntu 16.04 is out-dated. It's not supported anymore. Please upgrade." else abort "Operating system ${PRETTY_NAME} is not supported" fi } function checkHardwareRequirements { local cores=0 local ram=0 local arch="" log "Check hardware requirements…" arch=$(uname -m) if [[ "$arch" != "x86_64" ]]; then log "Attention! The system architecture is not x86 64 bit, but ${arch}. This could cause unwanted behaviour." askNoYes "Do you really want to continue?" || cancel fi cores=$(nproc) if [[ "$cores" -ge "$MIN_CPU_CORES" ]]; then log "$cores CPU cores detected; $MIN_CPU_CORES is required minimum" else log "Less than $MIN_CPU_CORES CPU cores detected" log "Found only $cores CPU core(s)." log "Your system does not meet the requirements. See:" log "" log " " log "" askNoYes "Do you really want to continue?" || cancel fi ram=$(vmstat --stats --unit b | grep -i "total memory" | awk '{print $1}') if [[ "$ram" -ge "$MIN_RAM" ]]; then log "$ram bytes of total memory detected; $MIN_RAM is required minimum" else log "Less than $MIN_RAM bytes of total memory detected" log "Found only $ram bytes." log "Your system does not meet the requirements. See:" log "" log " " log "" askNoYes "Do you really want to continue?" || cancel fi } function checkSoftwareRequirements { local failed=0 log "Check for installed applications and services…" MARIADB_BIN=$(command -v mysql) SUDO_BIN=$(command -v sudo) UNZIP_BIN=$(command -v unzip) WGET_BIN=$(command -v wget) PHP_BIN=$(command -v php) declare -A binaries binaries["mariabdb"]="$MARIADB_BIN" binaries["sudo"]="$SUDO_BIN" binaries["unzip"]="$UNZIP_BIN" binaries["wget"]="$WGET_BIN" binaries["php"]="$PHP_BIN" binaries["systemctl"]=$(command -v systemctl) binaries["chronic"]=$(command -v chronic) binaries["memcached"]=$(command -v memcached) case "$OS" in "rhel7" | "rhel8" | "centos7" | "centos8") binaries["httpd"]=$(command -v httpd) ;; *) binaries["apachectl"]=$(command -v apachectl) ;; esac for bin in "${!binaries[@]}"; do if [[ -x "${binaries[$bin]}" ]]; then log "$bin: found" else log "$bin: missing" ((failed++)) fi done if [[ -x "$PHP_BIN" ]]; then log "Check for installed PHP extensions…" case "$OS" in ## TODO There is no php-memcached on RHEL 8: "rhel8" | "centos8") local phpExtensions=(bcmath ctype curl fileinfo gd json ldap mbstring mysqli mysqlnd pgsql session soap xml zip) ;; *) local phpExtensions=(bcmath ctype curl fileinfo gd json ldap mbstring memcached mysqli mysqlnd pgsql session soap xml zip) ;; esac for phpExtension in "${phpExtensions[@]}"; do if "$PHP_BIN" -m | grep "$phpExtension" >/dev/null; then log "PHP extension $phpExtension: found" else log "PHP extension $phpExtension: missing" ((failed++)) fi done fi case "$failed" in 0) log "All software requirements met. Excellent." ;; 1) abort "Important software requirement is missing. Please install and configure it." ;; *) abort "Important software requirements are missing. Please install and configure them." ;; esac } function configureOS { case "$OS" in "debian12") configureDebian12 ;; "debian11") configureDebian11 ;; "ubuntu2204") configureUbuntu2204 ;; "ubuntu2004") configureUbuntu2004 ;; "rhel7") configureRHEL7 ;; "rhel8") configureRHEL8 ;; "centos7") configureCentOS7 ;; "centos8") configureCentOS8 ;; "sles15") configureSLES15 ;; "opensuse15") configureOpenSuse15 ;; *) abort "Unkown operating system '${OS}'!?!" ;; esac } function configureDebian12 { log "Keep your Debian packages up-to-date" apt-get -qq --yes update || abort "Unable to update Debian package repositories" apt-get -qq --yes full-upgrade || abort "Unable to perform update of Debian packages" apt-get -qq --yes clean || abort "Unable to cleanup Debian packages" apt-get -qq --yes autoremove || abort "Unable to remove unnecessary Debian packages" log "Install required Debian 12 packages" apt-get -qq --yes install --no-install-recommends \ apache2 libapache2-mod-fcgid \ mariadb-client mariadb-server \ php-bcmath php-cli php-common php-curl php-fpm php-gd \ php-ldap php-mbstring php-mysql php-opcache php-pgsql \ php-soap php-xml php-zip \ php-memcached \ memcached unzip sudo moreutils || abort "Unable to install required Debian packages" } function configureDebian11 { log "Keep your Debian packages up-to-date" apt-get -qq --yes update || abort "Unable to update Debian package repositories" apt-get -qq --yes full-upgrade || abort "Unable to perform update of Debian packages" apt-get -qq --yes clean || abort "Unable to cleanup Debian packages" apt-get -qq --yes autoremove || abort "Unable to remove unnecessary Debian packages" log "Install required Debian packages" apt-get -qq --yes install --no-install-recommends \ apache2 libapache2-mod-fcgid \ mariadb-client mariadb-server \ php7.4-bcmath php7.4-cli php7.4-common php7.4-curl php7.4-fpm php7.4-gd php7.4-json \ php7.4-ldap php7.4-mbstring php7.4-mysql php7.4-opcache php7.4-pgsql \ php7.4-soap php7.4-xml php7.4-zip \ php-memcached \ memcached unzip sudo moreutils || abort "Unable to install required Debian packages" } function configureUbuntu2004 { log "Keep your Ubuntu packages up-to-date" apt-get -qq --yes update || abort "Unable to update Ubuntu package repositories" apt-get -qq --yes full-upgrade || abort "Unable to perform update of Ubuntu packages" apt-get -qq --yes clean || abort "Unable to cleanup Ubuntu packages" apt-get -qq --yes autoremove || abort "Unable to remove unnecessary Ubuntu packages" log "Install required Ubuntu packages" apt-get -qq --yes install --no-install-recommends \ apache2 libapache2-mod-fcgid \ mariadb-client mariadb-server \ php7.4-bcmath php7.4-cli php7.4-common php7.4-curl php7.4-fpm php7.4-gd php7.4-json \ php7.4-ldap php7.4-mbstring php7.4-mysql php7.4-opcache php7.4-pgsql \ php7.4-soap php7.4-xml php7.4-zip \ php-memcached \ memcached unzip moreutils || abort "Unable to install required Ubuntu packages" } function configureUbuntu2204 { log "Keep your Ubuntu packages up-to-date" apt-get -qq --yes update || abort "Unable to update Ubuntu package repositories" apt-get -qq --yes full-upgrade || abort "Unable to perform update of Ubuntu packages" apt-get -qq --yes clean || abort "Unable to cleanup Ubuntu packages" apt-get -qq --yes autoremove || abort "Unable to remove unnecessary Ubuntu packages" log "Install required Ubuntu packages" apt-get -qq --yes install --no-install-recommends \ apache2 libapache2-mod-fcgid \ mariadb-client mariadb-server \ php8.1-bcmath php8.1-cli php8.1-common php8.1-curl php8.1-fpm php8.1-gd \ php8.1-ldap php8.1-mbstring php8.1-mysql php8.1-opcache php8.1-pgsql \ php8.1-soap php8.1-xml php8.1-zip \ php-memcached \ memcached unzip moreutils || abort "Unable to install required Ubuntu packages" } function configureCentOS7 { log "Keep your yum packages up-to-date" yum --assumeyes --quiet update || abort "Unable to update yum packages" yum --assumeyes --quiet autoremove || abort "Unable to remove out-dated yum packages" yum --assumeyes --quiet clean all || abort "Unable to clean yum caches" rm -rf /var/cache/yum || abort "Unable to remove orphaned yum caches" log "Install some important packages, for example Apache Web server" yum --assumeyes --quiet install httpd memcached unzip wget zip || abort "Unable to install packages" log "RHEL 7 has out-dated packages for PHP and MariaDB." log "This script will fix this issue by enabling these 3rd party repositories:" log "" log " Webtatic.com for PHP 7.2" log " Official MariaDB repository for MariaDB 10.3" log "" if askYesNo "Do you agree with it?"; then if ! rpm -qa | grep "epel-release" >/dev/null; then log "Import EPEL public GPG key" rpm --import --quiet https://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-7 || abort "Unable to import public GPG key from EPEL" log "Add EPEL releases" rpm -Uvh --quiet https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm || abort "Unable to install epel-releases via yum" fi if ! rpm -qa | grep "webtatic-release" >/dev/null; then log "Import W ebtatic public GPG key" rpm --import --quiet https://mirror.webtatic.com/yum/RPM-GPG-KEY-webtatic-el7 || abort "Unable to import GPG key from Webtatic" log "Add Webtatic releases" rpm -Uvh --quiet https://mirror.webtatic.com/yum/el7/webtatic-release.rpm || abort "Unable to add Webtatic" fi log "Install PHP packages" yum --assumeyes --quiet install \ php72w-bcmath php72w-cli php72w-common php72w-fpm php72w-gd php72w-ldap \ php72w-mbstring php72w-mysqlnd php72w-opcache php72w-pdo \ php72w-pecl-memcached php72w-pgsql php72w-soap php72w-xml || abort "Unable to install PHP packages" log "Enable MariaDB repository" cat </etc/yum.repos.d/MariaDB.repo || abort "Unable to create and edit file '/etc/yum.repos.d/MariaDB.repo'" # MariaDB 10.3 repository list # http://downloads.mariadb.org/mariadb/repositories/ [mariadb] name = MariaDB baseurl = http://yum.mariadb.org/10.3/centos7-amd64 gpgkey=https://yum.mariadb.org/RPM-GPG-KEY-MariaDB gpgcheck=1 EOF log "Install MariaDB packages" rpm --import --quiet https://yum.mariadb.org/RPM-GPG-KEY-MariaDB || abort "Unable to import GPG key from MariaDB" ## Suppress unnecessary notices which could confuse the user: yum --assumeyes --quiet install MariaDB-server MariaDB-client &>/dev/null || abort "Unable to install MariaDB" fi log "Install 'moreutils'" yum --assumeyes --quiet install moreutils || abort "Unable to install packages" for unit in $APACHE_UNIT $MARIADB_UNIT $MEMCACHED_UNIT $PHP_FPM_UNIT; do unitctl "enable" "$unit" unitctl "start" "$unit" done log "Allow incoming HTTP traffic" systemctl -q is-active firewalld.service || ( log "Firewall is inactive." unitctl "start" "firewalld" ) firewall-cmd --permanent --add-service=http || abort "Unable to configure firewall" unitctl "restart" "firewalld" } function configureCentOS8 { log "Keep your yum packages up-to-date" yum --assumeyes --quiet update || abort "Unable to update yum packages" yum --assumeyes --quiet autoremove || abort "Unable to remove out-dated yum packages" yum --assumeyes --quiet clean all || abort "Unable to clean yum caches" rm -rf /var/cache/yum || abort "Unable to remove orphaned yum caches" for appStream in httpd:2.4 mariadb:10.3 php:7.4; do log "Install AppStream $appStream" yum --assumeyes --quiet module install "$appStream" done log "Install some important packages" yum --assumeyes --quiet install \ memcached unzip wget zip \ php-bcmath php-gd php-ldap php-mysqli php-mysqlnd \ php-pgsql php-soap php-zip || abort "Unable to install packages" if ! rpm -qa | grep "epel-release" >/dev/null; then log "Import EPEL public GPG key" rpm --import --quiet https://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-8 || abort "Unable to import public GPG key from EPEL" log "Add epel releases repository" rpm -Uvh --quiet https://dl.fedoraproject.org/pub/epel/epel-release-latest-8.noarch.rpm || abort "Unable to install epel releases repository" fi log "Enable PowerTools for CentOS 8" dnf --assumeyes --quiet config-manager --set-enabled powertools || abort "Unable to enable PowerTools" log "Install moreutils with all dependencies" dnf --assumeyes --quiet install moreutils || abort "Unable to install moreutils" for unit in $APACHE_UNIT $MARIADB_UNIT $MEMCACHED_UNIT $PHP_FPM_UNIT; do unitctl "enable" "$unit" unitctl "start" "$unit" done log "Allow incoming HTTP traffic" systemctl -q is-active firewalld.service || ( log "Firewall is inactive." unitctl "start" "firewalld" ) firewall-cmd --permanent --add-service=http || abort "Unable to configure firewall" unitctl "restart" "firewalld" } function configureRHEL8 { log "Keep your yum packages up-to-date" yum --assumeyes --quiet update || abort "Unable to update yum packages" yum --assumeyes --quiet autoremove || abort "Unable to remove out-dated yum packages" yum --assumeyes --quiet clean all || abort "Unable to clean yum caches" rm -rf /var/cache/yum || abort "Unable to remove orphaned yum caches" for appStream in httpd:2.4 mariadb:10.3 php:7.4; do log "Install AppStream $appStream" yum --assumeyes --quiet module install "$appStream" done log "Install some important packages" yum --assumeyes --quiet install \ memcached unzip wget zip \ php-bcmath php-gd php-ldap php-mysqli php-mysqlnd \ php-pgsql php-soap php-zip || abort "Unable to install packages" if ! rpm -qa | grep "epel-release" >/dev/null; then log "Import EPEL public GPG key" rpm --import --quiet https://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-8 || abort "Unable to import public GPG key from EPEL" log "Add epel releases repository" rpm -Uvh --quiet https://dl.fedoraproject.org/pub/epel/epel-release-latest-8.noarch.rpm || abort "Unable to install epel releases repository" fi log "Enable codeready-builder for RHEL 8" subscription-manager repos --enable "codeready-builder-for-rhel-8-x86_64-rpms" || abort "Unable to enable Codeready-Builder" log "Install moreutils with all dependencies" dnf --assumeyes --quiet install moreutils || abort "Unable to install moreutils" for unit in $APACHE_UNIT $MARIADB_UNIT $MEMCACHED_UNIT $PHP_FPM_UNIT; do unitctl "enable" "$unit" unitctl "start" "$unit" done log "Allow incoming HTTP traffic" systemctl -q is-active firewalld.service || ( log "Firewall is inactive." unitctl "start" "firewalld" ) firewall-cmd --permanent --add-service=http || abort "Unable to configure firewall" unitctl "restart" "firewalld" } function configureRHEL7 { log "Keep your yum packages up-to-date" yum --assumeyes --quiet update || abort "Unable to update yum packages" yum --assumeyes --quiet autoremove || abort "Unable to remove out-dated yum packages" yum --assumeyes --quiet clean all || abort "Unable to clean yum caches" rm -rf /var/cache/yum || abort "Unable to remove orphaned yum caches" log "Install some important packages, for example Apache Web server" yum --assumeyes --quiet install httpd memcached unzip wget zip || abort "Unable to install packages" log "RHEL 7 has out-dated packages for PHP and MariaDB." log "This script will fix this issue by enabling these 3rd party repositories:" log "" log " Webtatic.com for PHP 7.2" log " Official MariaDB repository for MariaDB 10.3" log "" if askYesNo "Do you agree with it?"; then if ! rpm -qa | grep "epel-release" >/dev/null; then log "Import EPEL public GPG key" rpm --import --quiet https://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-7 || abort "Unable to import public GPG key from EPEL" log "Add EPEL releases" rpm -Uvh --quiet https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm || abort "Unable to install epel-releases via yum" fi if ! rpm -qa | grep "webtatic-release" >/dev/null; then log "Import Webtatic public GPG key" rpm --import --quiet https://mirror.webtatic.com/yum/RPM-GPG-KEY-webtatic-el7 || abort "Unable to import GPG key from Webtatic" log "Add Webtatic releases" rpm -Uvh --quiet https://mirror.webtatic.com/yum/el7/webtatic-release.rpm || abort "Unable to add Webtatic" fi log "Install PHP packages" yum --assumeyes --quiet install \ php72w-bcmath php72w-cli php72w-common php72w-fpm php72w-gd php72w-ldap \ php72w-mbstring php72w-mysqlnd php72w-opcache php72w-pdo \ php72w-pecl-memcached php72w-pgsql php72w-soap php72w-xml || abort "Unable to install PHP packages" log "Enable MariaDB repository" cat </etc/yum.repos.d/MariaDB.repo || abort "Unable to create and edit file '/etc/yum.repos.d/MariaDB.repo'" # MariaDB 10.3 RedHat repository list # http://downloads.mariadb.org/mariadb/repositories/ [mariadb] name = MariaDB baseurl = http://yum.mariadb.org/10.3/rhel7-amd64 gpgkey=https://yum.mariadb.org/RPM-GPG-KEY-MariaDB gpgcheck=1 EOF log "Install MariaDB packages" rpm --import --quiet https://yum.mariadb.org/RPM-GPG-KEY-MariaDB || abort "Unable to import GPG key from MariaDB" ## Suppress unnecessary notices which could confuse the user: yum --assumeyes --quiet install MariaDB-server MariaDB-client &>/dev/null || abort "Unable to install MariaDB" fi log "Enable required repository 'rhel-7-server-eus-optional-rpms'" subscription-manager repos --enable=rhel-7-server-eus-optional-rpms || abort "Repository cannot be enabled" ## Install moreutils *after* EPEL *and* rhel-7-server-eus-optional-rpms have been ## enabled! log "Install 'moreutils'" yum --assumeyes --quiet install moreutils || abort "Unable to install packages" for unit in $APACHE_UNIT $MARIADB_UNIT $MEMCACHED_UNIT $PHP_FPM_UNIT; do unitctl "enable" "$unit" unitctl "start" "$unit" done log "Allow incoming HTTP traffic" systemctl -q is-active firewalld.service || ( log "Firewall is inactive." unitctl "start" "firewalld" ) firewall-cmd --permanent --add-service=http || abort "Unable to configure firewall" unitctl "restart" "firewalld" } function configureSLES15 { local web_repos="" local openSuseRepo="" local webScriptingModuleAlias="Web_and_Scripting_Module_${VERSION_ID}_x86_64" local webScriptingModuleProduct="sle-module-web-scripting/${VERSION_ID}/x86_64" log "Keep your packages up-to-date" zypper --quiet --non-interactive refresh || abort "Unable to refresh software repositories" zypper --quiet --non-interactive update || abort "Unable to update software packages" web_repos=$(zypper repos -E | grep -c "$webScriptingModuleAlias") if [[ "$web_repos" -lt 2 ]]; then log "The following module is required:" log "" log " Web and Scripting" log "" log "This script will activate it." if askYesNo "Do you agree with it?"; then SUSEConnect -p "$webScriptingModuleProduct" || abort "Unable to active module" else abort "Essential software repositories are missing" fi fi log "Install software packages" zypper --quiet --non-interactive install --no-recommends \ apache2 \ mariadb mariadb-client \ memcached \ make sudo unzip \ php7 php7-bcmath php7-bz2 php7-ctype php7-curl php7-fpm php7-gd php7-gettext php7-fileinfo \ php7-json php7-ldap php7-mbstring php7-mysql php7-opcache php7-openssl php7-pdo php7-pgsql \ php7-phar php7-posix php7-soap php7-sockets php7-sqlite php7-xsl php7-zip php7-zlib || abort "Unable to install required software packages" openSuseRepo=$(zypper repos -E | grep -c "server_php_extensions_php7") if [[ "$openSuseRepo" -lt 1 ]]; then log "i-doit requires PHP module for memcached" log "But this PHP module is not available in SLE standard repositories" log "It will be installed from a 3rd-party repository from openSUSE:" log "" log " server:php:extensions:php7" log "" log "Details:" log "" log " https://software.opensuse.org/download.html?project=server%3Aphp%3Aextensions%3Aphp7&package=php7-memcached" if [[ "$VERSION_ID" == 15 ]]; then zypper --quiet --non-interactive addrepo \ --gpgcheck --refresh \ https://download.opensuse.org/repositories/server:php:extensions:php7/SLE_15/server:php:extensions:php7.repo || abort "Unable to add repository" zypper --quiet --non-interactive --gpg-auto-import-keys refresh || abort "Unable to refresh software repositories" elif [[ "$VERSION_ID" == 15.1 ]]; then zypper --quiet --non-interactive addrepo \ --gpgcheck --refresh \ https://download.opensuse.org/repositories/server:/php:/extensions/SLE_15_SP1/server:php:extensions.repo || abort "Unable to add repository" zypper --quiet --non-interactive --gpg-auto-import-keys refresh || abort "Unable to refresh software repositories" elif [[ "$VERSION_ID" == 15.2 ]]; then zypper --quiet --non-interactive addrepo \ --gpgcheck --refresh \ https://download.opensuse.org/repositories/server:/php:/extensions/SLE_15_SP2/server:php:extensions.repo || abort "Unable to add repository" zypper --quiet --non-interactive --gpg-auto-import-keys refresh || abort "Unable to refresh software repositories" fi fi zypper --quiet --non-interactive install --no-recommends php7-memcached || abort "Unable to install required software package" zypper --quiet --non-interactive clean || abort "Unable to clean up cached software packages" for unit in $APACHE_UNIT $MARIADB_UNIT $MEMCACHED_UNIT; do unitctl "enable" "$unit" unitctl "start" "$unit" done log "Allow incoming HTTP traffic" systemctl -q is-active firewalld.service || ( log "Firewall is inactive." unitctl "start" "firewalld" ) firewall-cmd --permanent --add-service=http || abort "Unable to configure firewall" unitctl "restart" "firewalld" if [[ ! -x "$(command -v chronic)" ]]; then log "Install 'chronic'" ## TODO: I know, this seems to be pretty ugly, but: ## Why the hack is moreutils not included in the standard repositories?!? wget --quiet -O "${TMP_DIR}/chronic" \ https://git.joeyh.name/index.cgi/moreutils.git/plain/chronic || abort "Unable to download 'chronic'" chmod +x "${TMP_DIR}/chronic" || abort "Unable to set executable bit" mv "${TMP_DIR}/chronic" /usr/bin || abort "Unable to move 'chronic' to '/usr/bin'" wget --quiet -O - https://cpanmin.us | perl - App::cpanminus || abort "Unable to install cpanminus" cpanm --quiet --notest --install IPC::Run || abort "Unable to install Perl module IPC::Run" fi } function configureOpenSuse15 { local web_repos="" local openSuseRepo="" log "Keep your packages up-to-date" zypper --quiet --non-interactive refresh || abort "Unable to refresh software repositories" zypper --quiet --non-interactive update || abort "Unable to update software packages" log "Install software packages" zypper --quiet --non-interactive install --no-recommends \ apache2 \ mariadb mariadb-client \ memcached \ make sudo unzip \ php7 php7-bcmath php7-bz2 php7-ctype php7-curl php7-fpm php7-gd php7-gettext php7-fileinfo \ php7-json php7-ldap php7-mbstring php7-mysql php7-memcached php7-opcache php7-openssl php7-pdo \ php7-pgsql php7-phar php7-posix php7-soap php7-sockets php7-sqlite php7-xsl php7-zip php7-zlib || abort "Unable to install required software packages" zypper --quiet --non-interactive clean || abort "Unable to clean up cached software packages" for unit in $APACHE_UNIT $MARIADB_UNIT $MEMCACHED_UNIT; do unitctl "enable" "$unit" unitctl "start" "$unit" done log "Allow incoming HTTP traffic" systemctl -q is-active firewalld.service || ( log "Firewall is inactive." unitctl "start" "firewalld" ) firewall-cmd --permanent --add-service=http || abort "Unable to configure firewall" unitctl "restart" "firewalld" if [[ ! -x "$(command -v chronic)" ]]; then log "Install 'chronic'" ## TODO: I know, this seems to be pretty ugly, but: ## Why the hack is moreutils not included in the standard repositories?!? wget --quiet -O "${TMP_DIR}/chronic" \ https://git.joeyh.name/index.cgi/moreutils.git/plain/chronic || abort "Unable to download 'chronic'" chmod +x "${TMP_DIR}/chronic" || abort "Unable to set executable bit" mv "${TMP_DIR}/chronic" /usr/bin || abort "Unable to move 'chronic' to '/usr/bin'" wget --quiet -O - https://cpanmin.us | perl - App::cpanminus || abort "Unable to install cpanminus" cpanm --quiet --notest --install IPC::Run || abort "Unable to install Perl module IPC::Run" fi } function configureProxy { if [[ -n "${https_proxy+x}" ]]; then log "Found proxy settings in environment variable 'https_proxy': $https_proxy" askYesNo "Do you want to use this setting?" && return 0 fi echo -n -e "Provide proxy settings [schema: https://username:password@proxy:port]: " read -r answer if [[ -n "$answer" ]]; then log "Set environment variable 'https_proxy' to '${answer}'" export https_proxy="$answer" else log "No settings found. Skip it." fi } function configurePHP { local php_en_mod="" local php_version="" log "Configure PHP" php_version=$(php --version | head -n1 -c7 | tail -c3) case "$php_version" in "5.4" | "5.5" | "5.6" | "7.0" | "7.1" | "7.2" | "7.3") abort "PHP ${php_version} is way too old. Please upgrade. We recommend version ${RECOMMENDED_PHP_VERSION}." ;; "7.4") log "PHP ${php_version} is installed, but this version is deprecated. Please consider to upgrade. We recommend version ${RECOMMENDED_PHP_VERSION}." php_en_mod=$(command -v phpenmod) ;; "8.0") php_en_mod=$(command -v phpenmod) ;; "8.1") php_en_mod=$(command -v phpenmod) ;; "8.2") php_en_mod=$(command -v phpenmod) ;; *) abort "PHP ${php_version} is not supported. Please follow the system requirements. We recommend version ${RECOMMENDED_PHP_VERSION}." ;; esac log "Write PHP settings to '${PHP_CONFIG_FILE}'" cat <"$PHP_CONFIG_FILE" || abort "Unable to create and edit file '${PHP_CONFIG_FILE}'" allow_url_fopen = Yes file_uploads = On magic_quotes_gpc = Off max_execution_time = 300 max_file_uploads = 42 max_input_time = 60 max_input_vars = 10000 memory_limit = 256M post_max_size = 128M register_argc_argv = On register_globals = Off short_open_tag = On upload_max_filesize = 128M display_errors = Off display_startup_errors = Off error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT log_errors = On default_charset = "UTF-8" default_socket_timeout = 60 date.timezone = Europe/Berlin session.gc_maxlifetime = 604800 session.cookie_lifetime = 0 mysqli.default_socket = ${MARIADB_SOCKET} EOF ## SLES has no phpenmod: if [[ -n "$php_en_mod" ]]; then log "Enable PHP settings" "$php_en_mod" i-doit log "Enable PHP module for memcached" "$php_en_mod" memcached fi } function configurePHPFPM { log "Configure PHP-FPM" case "$OS" in "debian11" | "debian12" | "ubuntu2004" | "ubuntu2204") unitctl "restart" "$PHP_FPM_UNIT" ;; "rhel7" | "rhel8" | "centos7" | "centos8") log "Disable default configuration file" mv /etc/php-fpm.d/www.conf{,.bak} || abort "Unable to disable default configuration file" log "Put new settings into file '/etc/php-fpm.d/i-doit.conf'" cat </etc/php-fpm.d/i-doit.conf || abort "Unable to create and edit file '/etc/php-fpm.d/i-doit.conf'" [i-doit] listen = ${PHP_FPM_SOCKET} user = ${APACHE_USER} group = ${APACHE_GROUP} listen.owner = ${APACHE_USER} listen.group = ${APACHE_GROUP} pm = dynamic pm.max_children = 50 pm.start_servers = 5 pm.min_spare_servers = 5 pm.max_spare_servers = 35 security.limit_extensions = .php EOF unitctl "restart" "$PHP_FPM_UNIT" ;; "sles15" | "opensuse15") log "Enable PHP FPM configuration files" mv /etc/php7/fpm/php-fpm.conf{.default,} || abort "Unable to move file" log "Put new settings into file '/etc/php7/fpm/php-fpm.d/i-doit.conf'" cat </etc/php7/fpm/php-fpm.d/i-doit.conf || abort "Unable to create and edit file '/etc/php7/fpm/php-fpm.d/i-doit.conf'" [i-doit] listen = ${PHP_FPM_SOCKET} user = ${APACHE_USER} group = ${APACHE_GROUP} listen.owner = ${APACHE_USER} listen.group = ${APACHE_GROUP} pm = dynamic pm.max_children = 5 pm.start_servers = 2 pm.min_spare_servers = 1 pm.max_spare_servers = 3 security.limit_extensions = .php EOF unitctl "enable" "$PHP_FPM_UNIT" unitctl "start" "$PHP_FPM_UNIT" ;; *) log "Nope. This OS will stuck on mod_php." ;; esac } function configureApache { local a2_en_mod="" local a2_dis_mod="" local a2_en_site="" local a2_dis_site="" local hostname="" log "Configure Apache Web server" hostname="$(cat /etc/hostname)" case "$OS" in "rhel7" | "rhel8" | "centos7" | "centos8") cat <${APACHE_CONFIG_FILE} || abort "Unable to create and edit file '${APACHE_CONFIG_FILE}'" DirectoryIndex index.php DocumentRoot ${INSTALL_DIR}/ AllowOverride None ${APACHE_HTACCESS_SUBSTITUTION} TimeOut 600 ProxyTimeout 600 SetHandler "proxy:unix:${PHP_FPM_SOCKET}|fcgi://localhost" EOF test ! -d "$INSTALL_DIR" && ( mkdir -p "$INSTALL_DIR" || abort "Unable to create directory '${INSTALL_DIR}'" ) log "Change directory ownership" chown "$APACHE_USER":"$APACHE_GROUP" -R "${INSTALL_DIR}/" || abort "Unable to change ownership" log "SELinux: Allow Apache Web server to read/write files under ${INSTALL_DIR}/" chcon -t httpd_sys_content_t "${INSTALL_DIR}/" -R || abort "Unable to give read permissions recursively" chcon -t httpd_sys_rw_content_t "${INSTALL_DIR}/" -R || abort "Unable to give write permissions recursively" ## mpm_event is already enabled on RHEL 8: if [[ "$OS" != "rhel8" ]]; then log "Disable MPM prefork" sed -i "/.* mpm_prefork_module /s/^#*/#/" /etc/httpd/conf.modules.d/00-mpm.conf || abort "sed exited with error" log "Enable MPM event" sed -i "/^#.* mpm_event_module /s/^#//" /etc/httpd/conf.modules.d/00-mpm.conf || abort "sed exited with error" fi if [[ "$OS" != "centos8" ]]; then log "Disable MPM prefork" sed -i "/.* mpm_prefork_module /s/^#*/#/" /etc/httpd/conf.modules.d/00-mpm.conf || abort "sed exited with error" log "Enable MPM event" sed -i "/^#.* mpm_event_module /s/^#//" /etc/httpd/conf.modules.d/00-mpm.conf || abort "sed exited with error" fi unitctl "restart" "$APACHE_UNIT" ;; "sles15" | "opensuse15") a2_en_mod=$(command -v a2enmod) cat <${APACHE_CONFIG_FILE} || abort "Unable to create and edit file '${APACHE_CONFIG_FILE}'" ServerName ${hostname} ServerAdmin i-doit@example.net DirectoryIndex index.php DocumentRoot ${INSTALL_DIR}/ AllowOverride None ${APACHE_HTACCESS_SUBSTITUTION} TimeOut 600 ProxyTimeout 600 SetHandler "proxy:unix:${PHP_FPM_SOCKET}|fcgi://localhost" LogLevel warn ErrorLog /var/log/apache2/error.log CustomLog /var/log/apache2/access.log combined EOF log "Change directory ownership" chown "$APACHE_USER":"$APACHE_GROUP" -R "${INSTALL_DIR}/" || abort "Unable to change ownership" log "Enable Apache module proxy" "$a2_en_mod" proxy || abort "Unable to enable Apache module proxy" log "Enable Apache module proxy_fcgi" "$a2_en_mod" proxy_fcgi || abort "Unable to enable Apache module proxy_fcgi" log "Enable Apache module rewrite" "$a2_en_mod" rewrite || abort "Unable to enable Apache module rewrite" log "Enable Apache module mod_access_compat" "$a2_en_mod" mod_access_compat || abort "Unable to enable Apache module mod_access_compat" unitctl "restart" "$APACHE_UNIT" ;; "debian11" | "debian12" | "ubuntu2004" | "ubuntu2204") a2_en_site=$(command -v a2ensite) a2_dis_site=$(command -v a2dissite) a2_en_mod=$(command -v a2enmod) a2_dis_mod=$(command -v a2dismod) cat <${APACHE_CONFIG_FILE} || abort "Unable to create and edit file '${APACHE_CONFIG_FILE}'" ServerName ${hostname} ServerAdmin i-doit@example.net DirectoryIndex index.php DocumentRoot ${INSTALL_DIR}/ AllowOverride None ${APACHE_HTACCESS_SUBSTITUTION} TimeOut 600 ProxyTimeout 600 SetHandler "proxy:unix:${PHP_FPM_SOCKET}|fcgi://localhost" LogLevel warn ErrorLog \${APACHE_LOG_DIR}/error.log CustomLog \${APACHE_LOG_DIR}/access.log combined EOF log "Disable default VHost" "$a2_dis_site" 000-default || abort "Unable to disable default VHost" log "Change directory ownership" chown "$APACHE_USER":"$APACHE_GROUP" -R "${INSTALL_DIR}/" || abort "Unable to change ownership" log "Enable new VHost settings" "$a2_en_site" i-doit || abort "Unable to enable VHost settings" log "Enable Apache module rewrite" "$a2_en_mod" rewrite || abort "Unable to enable Apache module rewrite" log "Enable Apache module alias" "$a2_en_mod" alias || abort "Unable to enable Apache module alias" log "Disable Apache module mpm_prefork" "$a2_dis_mod" mpm_prefork || abort "Unable to enable Apache module mpm_prefork" log "Enable Apache module mpm_event" "$a2_en_mod" mpm_event || abort "Unable to enable Apache module mpm_event" log "Enable Apache module proxy" "$a2_en_mod" proxy || abort "Unable to enable Apache module proxy" log "Enable Apache module proxy_fcgi" "$a2_en_mod" proxy_fcgi || abort "Unable to enable Apache module proxy_fcgi" log "Enable Apache module setenvif" "$a2_en_mod" setenvif || abort "Unable to enable Apache module setenvif" log "Let every user read the logs" chmod 755 /var/log/apache2 || abort "Unable to change permissions" chmod 664 /var/log/apache2/* || abort "Unable to change permissions" unitctl "restart" "$APACHE_UNIT" ;; *) a2_en_site=$(command -v a2ensite) a2_dis_site=$(command -v a2dissite) a2_en_mod=$(command -v a2enmod) cat <${APACHE_CONFIG_FILE} || abort "Unable to create and edit file '${APACHE_CONFIG_FILE}'" ServerName ${hostname} ServerAdmin i-doit@example.net DocumentRoot ${INSTALL_DIR}/ # See ${INSTALL_DIR}/.htaccess for details AllowOverride All Require all granted LogLevel warn ErrorLog \${APACHE_LOG_DIR}/error.log CustomLog \${APACHE_LOG_DIR}/access.log combined EOF log "Disable default VHost" "$a2_dis_site" 000-default || abort "Unable to disable default VHost" log "Change directory ownership" chown "$APACHE_USER":"$APACHE_GROUP" -R "${INSTALL_DIR}/" || abort "Unable to change ownership" log "Enable new VHost settings" "$a2_en_site" i-doit || abort "Unable to enable VHost settings" log "Enable Apache module rewrite" "$a2_en_mod" rewrite || abort "Unable to enable Apache module rewrite" log "Let every user read the logs" chmod 755 /var/log/apache2 || abort "Unable to change permissions" chmod 664 /var/log/apache2/* || abort "Unable to change permissions" unitctl "restart" "$APACHE_UNIT" ;; esac } function configureMariaDB { log "Configure MariaDB DBMS" echo -e -n "Please enter the MariaDB hostname [leave empty for '${MARIADB_HOSTNAME}']: " read -r answer if [[ -n "$answer" ]]; then MARIADB_HOSTNAME="$answer" fi secureMariaDB # Check mariadb version local mariadb_version="" mariadb_version=$(mysql --version | head -n1 -c29 | tail -c 5) log "Prepare shutdown of MariaDB" "$MARIADB_BIN" \ -h"$MARIADB_HOSTNAME" \ -u"$MARIADB_SUPERUSER_USERNAME" -p"$MARIADB_SUPERUSER_PASSWORD" \ -e"SET GLOBAL innodb_fast_shutdown = 0" || abort "Unable to prepare shutdown" unitctl "stop" "$MARIADB_UNIT" log "How many bytes of your RAM do you like to spend to MariaDB?" echo -n -e "You SHOULD give MariaDB ~ 50 per cent of your RAM. You can use G for Gigabytes or M for Megabytes, e.g. 1024M or 1G [leave empty for '${MARIADB_INNODB_BUFFER_POOL_SIZE}']: " read -r answer if [[ -n "$answer" ]]; then MARIADB_INNODB_BUFFER_POOL_SIZE="$answer" fi if [[ "$mariadb_version" != "10.11" ]]; then log "Move old MariaDB log files" mv /var/lib/mysql/ib_logfile[01] "$TMP_DIR" || abort "Unable to remove old log files" log "Configure MariaDB settings" cat <"$MARIADB_CONFIG_FILE" || abort "Unable to create and edit file '${MARIADB_CONFIG_FILE}'" [mysqld] # This is the number 1 setting to look at for any performance optimization # It is where the data and indexes are cached: having it as large as possible will # ensure MySQL uses memory and not disks for most read operations. # See https://mariadb.com/kb/en/innodb-buffer-pool/ # Typical values are 1G (1-2GB RAM), 5-6G (8GB RAM), 20-25G (32GB RAM), 100-120G (128GB RAM). innodb_buffer_pool_size = ${MARIADB_INNODB_BUFFER_POOL_SIZE} # Use multiple instances if you have innodb_buffer_pool_size > 10G, 1 every 4GB innodb_buffer_pool_instances = 1 # Redo log file size, the higher the better. # MySQL/MariaDB writes two of these log files in a default installation. innodb_log_file_size = 512M innodb_sort_buffer_size = 64M sort_buffer_size = 262144 # default join_buffer_size = 262144 # default max_allowed_packet = 128M max_heap_table_size = 32M query_cache_min_res_unit = 4096 query_cache_type = 1 query_cache_limit = 5M query_cache_size = 80M tmp_table_size = 32M max_connections = 200 innodb_file_per_table = 1 # Disable this (= 0) if you have only one to two CPU cores, change it to 4 for a quad core. innodb_thread_concurrency = 0 # Disable this (= 0) if you have slow harddisks innodb_flush_log_at_trx_commit = 1 innodb_flush_method = O_DIRECT innodb_lru_scan_depth = 2048 table_definition_cache = 1024 table_open_cache = 2048 innodb_stats_on_metadata = 0 sql-mode = "" EOF else cat <"$MARIADB_CONFIG_FILE" || abort "Unable to create and edit file '${MARIADB_CONFIG_FILE}'" [mysqld] # This is the number 1 setting to look at for any performance optimization # It is where the data and indexes are cached: having it as large as possible will # ensure MySQL uses memory and not disks for most read operations. # See https://mariadb.com/kb/en/innodb-buffer-pool/ # Typical values are 1G (1-2GB RAM), 5-6G (8GB RAM), 20-25G (32GB RAM), 100-120G (128GB RAM). innodb_buffer_pool_size = 1G # Redo log file size, the higher the better. # MySQL/MariaDB writes one of these log files in a default installation. innodb_log_file_size = 512M innodb_sort_buffer_size = 64M sort_buffer_size = 262144 # default join_buffer_size = 262144 # default max_allowed_packet = 128M max_heap_table_size = 32M query_cache_min_res_unit = 4096 query_cache_type = 1 query_cache_limit = 5M query_cache_size = 80M tmp_table_size = 32M max_connections = 200 innodb_file_per_table = 1 # Disable this (= 0) if you have slow hard disks innodb_flush_log_at_trx_commit = 1 innodb_flush_method = O_DIRECT innodb_lru_scan_depth = 2048 table_definition_cache = 1024 table_open_cache = 2048 innodb_stats_on_metadata = 0 sql-mode = "" EOF fi if [[ -d "/var/log/mysql" ]]; then log "Let every user read the logs" chmod 755 /var/log/mysql chmod 664 /var/log/mysql/* fi unitctl "start" "$MARIADB_UNIT" } function secureMariaDB { local mariadb_version="" mariadb_version=$(mysql --version | head -n1 -c29 | tail -c 5) echo -n -e \ "Please enter a new password for MariaDB's super user '${MARIADB_SUPERUSER_USERNAME}' [leave empty for '${MARIADB_SUPERUSER_PASSWORD}']: " read -r answer if [[ -n "$answer" ]]; then MARIADB_SUPERUSER_PASSWORD="$answer" fi log "Set $MARIADB_SUPERUSER_USERNAME password and plugin 'mysql_native_password'" case "$mariadb_version" in "10.11") "$MARIADB_BIN" \ -h"$MARIADB_HOSTNAME" \ -u"$MARIADB_SUPERUSER_USERNAME" \ -p"$MARIADB_SUPERUSER_PASSWORD" \ -e"ALTER USER 'root'@'localhost' IDENTIFIED VIA mysql_native_password USING PASSWORD('${MARIADB_SUPERUSER_PASSWORD}');" || abort "SQL statement failed" ;; "10.4" | "10.5" | "10.6") "$MARIADB_BIN" \ -h"$MARIADB_HOSTNAME" \ -u"$MARIADB_SUPERUSER_USERNAME" \ -p"$MARIADB_SUPERUSER_PASSWORD" \ -e"SET PASSWORD FOR '${MARIADB_SUPERUSER_USERNAME}'@'localhost' = PASSWORD('${MARIADB_SUPERUSER_PASSWORD}');" \ -e"ALTER USER '${MARIADB_SUPERUSER_USERNAME}'@'localhost' IDENTIFIED VIA mysql_native_password USING PASSWORD('${MARIADB_SUPERUSER_PASSWORD}');" || abort "SQL statement failed" ;; "10.1" | "10.2" | "10.3") "$MARIADB_BIN" \ -h"$MARIADB_HOSTNAME" \ -u"$MARIADB_SUPERUSER_USERNAME" \ -p"$MARIADB_SUPERUSER_PASSWORD" \ -e"UPDATE mysql.user SET Password=PASSWORD('${MARIADB_SUPERUSER_PASSWORD}'), plugin='mysql_native_password' WHERE User='${MARIADB_SUPERUSER_USERNAME}';" || abort "SQL statement failed" ;; *) abort "MariaDB ${mariadb_version} is not supported. Please follow the system requirements. We recommend version ${RECOMMENDED_MARIADB_VERSION}." ;; esac case "$OS" in "rhel7" | "rhel8" | "centos7" | "centos8") log "Allow $MARIADB_SUPERUSER_USERNAME login only from localhost" "$MARIADB_BIN" \ -h"$MARIADB_HOSTNAME" \ -u"$MARIADB_SUPERUSER_USERNAME" \ -p"$MARIADB_SUPERUSER_PASSWORD" \ -e"DELETE FROM mysql.user WHERE User='${MARIADB_SUPERUSER_USERNAME}' AND Host NOT IN ('localhost', '127.0.0.1', '::1');" || abort "SQL statement failed" log "Remove anonymous user" "$MARIADB_BIN" \ -h"$MARIADB_HOSTNAME" \ -u"$MARIADB_SUPERUSER_USERNAME" \ -p"$MARIADB_SUPERUSER_PASSWORD" \ -e"DELETE FROM mysql.user WHERE User='';" || abort "SQL statement failed" log "Remove test database" "$MARIADB_BIN" \ -h"$MARIADB_HOSTNAME" \ -u"$MARIADB_SUPERUSER_USERNAME" \ -p"$MARIADB_SUPERUSER_PASSWORD" \ -e"DELETE FROM mysql.db WHERE Db='test' OR Db='test_%';" || abort "SQL statement failed" log "Flush MariaDB user privileges" "$MARIADB_BIN" \ -h"$MARIADB_HOSTNAME" \ -u"$MARIADB_SUPERUSER_USERNAME" \ -p"$MARIADB_SUPERUSER_PASSWORD" \ -e"FLUSH PRIVILEGES;" || abort "SQL statement failed" ;; "sles15" | "opensuse15" | "debian11" | "ubuntu2004" | "ubuntu2204") log "Allow $MARIADB_SUPERUSER_USERNAME login only from localhost" "$MARIADB_BIN" \ -h"$MARIADB_HOSTNAME" \ -u"$MARIADB_SUPERUSER_USERNAME" \ -p"$MARIADB_SUPERUSER_PASSWORD" \ -e"DELETE FROM mysql.user WHERE User='${MARIADB_SUPERUSER_USERNAME}' AND Host NOT IN ('localhost', '127.0.0.1', '::1');" || abort "SQL statement failed" log "Remove anonymous user" "$MARIADB_BIN" \ -h"$MARIADB_HOSTNAME" \ -u"$MARIADB_SUPERUSER_USERNAME" \ -p"$MARIADB_SUPERUSER_PASSWORD" \ -e"DELETE FROM mysql.user WHERE User='';" || abort "SQL statement failed" log "Remove test database" "$MARIADB_BIN" \ -h"$MARIADB_HOSTNAME" \ -u"$MARIADB_SUPERUSER_USERNAME" \ -p"$MARIADB_SUPERUSER_PASSWORD" \ -e"DELETE FROM mysql.db WHERE Db='test' OR Db='test_%';" || abort "SQL statement failed" log "Flush MariaDB user privileges" "$MARIADB_BIN" \ -h"$MARIADB_HOSTNAME" \ -u"$MARIADB_SUPERUSER_USERNAME" \ -p"$MARIADB_SUPERUSER_PASSWORD" \ -e"FLUSH PRIVILEGES;" || abort "SQL statement failed" ;; esac } function prepareIDoit { local file="${TMP_DIR}/i-doit.zip" local update_file_url="" local variant="" local parse_updates_script="" local url="" local version="" local release_date="" log "Cleanup VHost directory" rm -rf "${INSTALL_DIR:?}/"* || abort "Unable to remove files" rm -f "${INSTALL_DIR}"/.htaccess || abort "Unable to remove files" log "" log "For evaluation use \033[32mEVAL\033[0m" log "If you have a license use \033[32mPRO\033[0m" log "If you want the open version use \033[32mOPEN\033[0m" log "" echo -n -e "Which variant of i-doit do you like to install? [EVAL|pro|open]: " read -r wanted_variant case "$wanted_variant" in "" | "EVAL" | "Eval" | "eval") update_file_url="$UPDATE_FILE_EVAL" variant="eval" ;; "PRO" | "Pro" | "pro") update_file_url="$UPDATE_FILE_PRO" variant="pro" ;; "OPEN" | "Open" | "open") update_file_url="$UPDATE_FILE_OPEN" variant="open" ;; *) abort "Unknown variant" ;; esac log "Install i-doit $variant" case "$variant" in "pro" | "open") log "Identify latest version of i-doit $variant" test ! -f "$TMP_DIR/updates.xml" && "$WGET_BIN" --quiet -O "${TMP_DIR}/updates.xml" "$update_file_url" test -f "$TMP_DIR/updates.xml" || abort "Unable to fetch file from '${update_file_url}'" parse_updates_script="${TMP_DIR}/parseupdates.php" cat <"$parse_updates_script" || abort "Unable to create and edit file '${parse_updates_script}'" updates->update[count(\$xml->updates->update) - 1]->\$attribute; EOF url=$($PHP_BIN "$parse_updates_script" "filename" | sed "s/-update.zip/.zip/") test -n "$url" || abort "Missing URL" version=$($PHP_BIN "$parse_updates_script" "version") test -n "$version" || abort "Missing version" release_date=$($PHP_BIN "$parse_updates_script" "release") test -n "$release_date" || abort "Missing release date" log "Download i-doit $variant $version (released on ${release_date})" "$WGET_BIN" --quiet -O "$file" "$url" || abort "Unable to download installation file" ;; "eval") log "Download i-doit EVAL version" "$WGET_BIN" --quiet -O "$file" "$update_file_url" || abort "Unable to download installation file" ;; *) abort "Unknown variant" ;; esac cp "$file" "${INSTALL_DIR}/i-doit.zip" || abort "Unable to copy installation file" log "Unzip package" cd "$INSTALL_DIR" || abort "Unable to change to installation directory '${INSTALL_DIR}'" "$UNZIP_BIN" -q i-doit.zip || abort "Unable to unzip file" log "Prepare files and directories" rm i-doit.zip || abort "Unable to remove downloaded file" chown "$APACHE_USER":"$APACHE_GROUP" -R . || abort "Unable to change ownership" find . -type d -name \* -exec chmod 775 {} \; || abort "Unable to change directory permissions" find . -type f -exec chmod 664 {} \; || abort "Unable to change file permissions" } function updateApacheConfig { local htaccessFile="${INSTALL_DIR}/.htaccess" log "Update Apache's VHost config from i-doit's htaccess file" sed -i \ -e "/${APACHE_HTACCESS_SUBSTITUTION}/ {" \ -e "r ${htaccessFile}" \ -e "d" \ -e "}" \ "$APACHE_CONFIG_FILE" || abort "Unable to change config file" unitctl "restart" "$APACHE_UNIT" } function installIDoit { local prefix="php" local console="${INSTALL_DIR}/console.php" log "Install i-doit via console.php" echo -n -e \ "Please enter a Admin Center password [leave empty for '${IDOIT_ADMIN_CENTER_PASSWORD}']: " read -r adminCenterPass if [[ -n "$adminCenterPass" ]]; then IDOIT_ADMIN_CENTER_PASSWORD="$adminCenterPass" fi echo -n -e \ "Please enter a username for a new MySQL user (This user will be authorized to the i-doit databases only) [leave empty for '${MARIADB_IDOIT_USERNAME}']: " read -r mariaDBidoitUsername if [[ -n "$mariaDBidoitUsername" ]]; then MARIADB_IDOIT_USERNAME="$mariaDBidoitUsername" fi echo -n -e \ "Please enter a password for a the new MySQL user [leave empty for '${MARIADB_IDOIT_PASSWORD}']: " read -r mariaDBidoitPassword if [[ -n "$mariaDBidoitPassword" ]]; then MARIADB_IDOIT_PASSWORD="$mariaDBidoitPassword" fi sudo -u ${APACHE_USER} ${prefix} ${console} install \ -u "$MARIADB_SUPERUSER_USERNAME" \ -p "$MARIADB_SUPERUSER_PASSWORD" \ --host="$MARIADB_HOSTNAME" \ -d idoit_system \ -U "$MARIADB_IDOIT_USERNAME" \ -P "$MARIADB_IDOIT_PASSWORD" \ --admin-password "$IDOIT_ADMIN_CENTER_PASSWORD" \ -n || abort "Installation of i-doit failed" config_file="${INSTALL_DIR}/src/config.inc.php" log "Fix configuration file '${config_file}'" chown "$APACHE_USER":"$APACHE_GROUP" "$config_file" || abort "Unable to change ownership" } function create_tenant { local prefix="php" local console="${INSTALL_DIR}/console.php" local tenant_name="Your company name" log "Install i-doit via console.php" echo -n -e \ "Please enter a tenant name [leave empty for '${tenant_name}']: " read -r tenantName if [[ -n "$tenantName" ]]; then tenant_name="$tenantName" fi sudo -u ${APACHE_USER} ${prefix} ${console} tenant-create \ -u "$MARIADB_SUPERUSER_USERNAME" \ -p "$MARIADB_SUPERUSER_PASSWORD" \ -U "$MARIADB_IDOIT_USERNAME" \ -P "$MARIADB_IDOIT_PASSWORD" \ -d idoit_data \ -t "$tenant_name" \ -n || abort "Creating tenant failed" log "Tenant '$tenant_name' created" } function deployScriptSettings { local settings_dir="" log "Deploy script settings" settings_dir=$(dirname "$SCRIPT_SETTINGS") test -d "$settings_dir" || ( mkdir -p "$settings_dir" || abort "Unable to create directory '$settings_dir'" ) cat <"$SCRIPT_SETTINGS" || abort "Unable to create and edit file '${SCRIPT_SETTINGS}'" #!/bin/bash export CONSOLE_BIN="$CONSOLE_BIN" export APACHE_USER="$APACHE_USER" export SYSTEM_DATABASE="idoit_system" export TENANT_DATABASE="idoit_data" export TENANT_ID="1" export MARIADB_USERNAME="$MARIADB_IDOIT_USERNAME" export MARIADB_PASSWORD="$MARIADB_IDOIT_PASSWORD" export MARIADB_HOSTNAME="$MARIADB_HOSTNAME" export INSTANCE_PATH="$INSTALL_DIR" export IDOIT_USERNAME="admin" export IDOIT_PASSWORD="admin" export BACKUP_DIR="$BACKUP_DIR" # Max. age of backup files (in days): export BACKUP_AGE=30 EOF } function deployConsole { log "Deploy i-doit console" deployScript idoit } function deployJobScript { log "Deploy i-doit jobs" deployScript idoit-jobs } function deployCronJobs { local download_url="https://raw.githubusercontent.com/i-doit/scripts/main/cron" local file="$TMP_DIR/cron" test ! -f "$file" && ( "$WGET_BIN" --quiet -O "$file" "$download_url" || abort "Unable to fetch file from '${download_url}'" ) sed -i -- "s/www-data/${APACHE_USER}/g" "$file" || abort "Unable to set Apache user" chmod 644 "$file" || abort "Unable to set read/write bits" mv "$file" "$CRON_FILE" || abort "Unable to move file to '/etc/cron.d/i-doit'" } function deployBackupAndRestore { log "Deploy backup and restore scripts" deployScript idoit-backup deployScript idoit-restore log "Create the first backup" /usr/local/bin/idoit-backup || abort "Backup script returned with error" } function deployScript { local file="$1" local tmp_file="${TMP_DIR}/$file" local url="https://raw.githubusercontent.com/i-doit/scripts/main/$file" log "Deploy script '$file'" test ! -f "$tmp_file" && ( "$WGET_BIN" --quiet -O "$tmp_file" "$url" || abort "Unable to fetch file from '${url}'" ) chmod 775 "$tmp_file" || abort "Unable to set read/write/executable bits" mv "$tmp_file" "/usr/local/bin/$file" || abort "Unable to move file to '/usr/local/bin/'" } function unitctl { local action="$1" local unit="$2" log "${action^} $unit" systemctl -q "$action" "${unit}.service" || abort "Failed to $action $unit" } function setup { # We need English to check some command outputs: if locale -a | grep "^en_US.utf8" >/dev/null; then export LC_ALL="en_US.utf8" export LANG="en_US.utf8" export LANGUAGE="en_US.utf8" elif locale -a | grep "^en_GB.utf8" >/dev/null; then export LC_ALL="en_GB.utf8" export LANG="en_GB.utf8" export LANGUAGE="en_GB.utf8" elif locale -a | grep "^C.UTF-8" >/dev/null; then export LC_ALL="C.UTF-8" export LANG="C.UTF-8" export LANGUAGE="C.UTF-8" elif locale -a | grep "^C.utf8" >/dev/null; then export LC_ALL="C.utf8" export LANG="C.utf8" export LANGUAGE="C.utf8" else log "This script may fail because it depends on US/GB English locale. We try it anyway…" fi test "$(whoami)" = "root" || abort "Superuser rights required" mkdir -p "$TMP_DIR" || abort "Unable to create temporary directory" } function tearDown { test -d "$TMP_DIR" && (rm -rf "$TMP_DIR" || echo "Failed to cleanup" 1>&2) } function showUsage { log "Usage: $BASENAME [OPTIONS]" log "" log "Options:" log "" log " -h, --help Print usage" log " -v, --version Print version" } function printVersion { log "$PROJECT_VERSION" } function log { echo -e "$1" } function askYesNo { echo -n -e "$1 [Y]es [n]o: " read -r answer case "$answer" in "" | "Y" | "Yes" | "y" | "yes") return 0 ;; "No" | "no" | "n" | "N") return 1 ;; *) log "Sorry, what do you mean?" askYesNo "$1" ;; esac } function askNoYes { echo -n -e "$1 [y]es [N]o: " read -r answer case "$answer" in "" | "No" | "no" | "n" | "N") return 0 ;; "Y" | "Yes" | "y" | "yes") return 1 ;; *) log "Sorry, what do you mean?" askNoYes "$1" ;; esac } function finish { log "Done. Have fun :-)" exit 0 } function abort { echo -e "$1" 1>&2 echo "Operation failed. Please check what is wrong and try again." 1>&2 exit 1 } function cancel { echo "Bye" exit 0 } ##-------------------------------------------------------------------------------------------------- if [[ "${BASH_SOURCE[0]}" = "$0" ]]; then trap tearDown EXIT ARGS=$(getopt \ -o vh \ --long help,version -- "$@" 2>/dev/null) eval set -- "$ARGS" while true; do case "$1" in -h | --help) showUsage exit 0 ;; -v | --version) printVersion exit 0 ;; --) shift break ;; *) log "Unkown option '${1}'." showUsage exit 1 ;; esac done setup && execute && finish fi