#!/usr/bin/env bash cript_name="$(basename $(realpath $0))" working_dir="$(dirname $(realpath $0))" #conf_file="${working_dir}/conf/${script_name%%.*}.conf" conf_file="${working_dir}/conf/bbb.conf" LOCK_DIR="/tmp/$(basename $0).$$.LOCK" log_file="${LOCK_DIR}/${script_name%%.*}.log" # ---------- # Base Function(s) # ---------- clean_up() { # Perform program exit housekeeping rm -rf "$LOCK_DIR" blank_line exit $1 } echononl(){ if $terminal ; then echo X\\c > /tmp/shprompt$$ if [ `wc -c /tmp/shprompt$$ | awk '{print $1}'` -eq 1 ]; then echo -e -n " $*\\c" 1>&2 else echo -e -n " $*" 1>&2 fi rm /tmp/shprompt$$ fi } fatal(){ echo "" if $terminal ; then echo -e " [ \033[31m\033[1mFatal\033[m ] $*" else echo -e " [ Fatal ] $*" fi echo "" if $terminal ; then echo -e " \033[1mScript terminated\033[m.." else echo -e " Script terminated.." fi echo "" rm -rf $LOCK_DIR exit 1 } error (){ echo "" if $terminal ; then echo -e " [ \033[31m\033[1mError\033[m ] $*" else echo " [ Error ] $*" fi echo "" } info () { if $terminal ; then echo "" echo -e " [ \033[32m\033[1mInfo\033[m ] $*" echo "" fi } note () { if $terminal ; then echo "" echo -e " [ \033[33m\033[1mNote\033[m ] $*" echo "" fi } echo_ok() { if $terminal ; then echo -e "\033[85G[ \033[32mok\033[m ]" fi } echo_failed(){ if $terminal ; then echo -e "\033[85G[ \033[1;31mfailed\033[m ]" fi } echo_skipped() { if $terminal ; then echo -e "\033[85G[ \033[37m\033[1mskipped\033[m ]" fi } echo_wait(){ if $terminal ; then echo -en "\033[85G[ \033[5m\033[1m..\033[m ]" fi } trim() { local var="$*" var="${var#"${var%%[![:space:]]*}"}" # remove leading whitespace characters var="${var%"${var##*[![:space:]]}"}" # remove trailing whitespace characters echo -n "$var" } blank_line() { if $terminal ; then echo "" fi } detect_os () { if $(which lsb_release > /dev/null 2>&1) ; then DIST="$(lsb_release -i | awk '{print tolower($3)}')" DIST_VERSION="$(lsb_release -r | awk '{print tolower($2)}')" DIST_CODENAME="$(lsb_release -c | awk '{print tolower($2)}')" if [[ "$DIST" = "debian" ]]; then if $(echo "$DIST_VERSION" | grep -q '\.') ; then DIST_VERSION=$(echo "$DIST_VERSION" | cut --delimiter='.' -f1) fi fi elif [[ -e "/etc/os-release" ]]; then . /etc/os-release DIST=$ID DIST_VERSION=${VERSION_ID} fi # remove whitespace from DIST and DIST_VERSION DIST="${DIST// /}" DIST_VERSION="${DIST_VERSION// /}" } # ---------- # - Jobhandling # ---------- # - Run 'clean_up' for signals SIGHUP SIGINT SIGTERM # - trap clean_up SIGHUP SIGINT SIGTERM # - Create lock directory '$LOCK_DIR" # mkdir "$LOCK_DIR" # ---------- # - Some checks .. # ---------- # - Running in a terminal? # - if [[ -t 1 ]] ; then terminal=true else fatal "Script must run in a terminal." fi # ========== # - Begin Main Script # ========== # ---------- # - Headline # ---------- if $terminal ; then echo "" echo -e "\033[1m----------\033[m" echo -e "\033[32m\033[1mRunning script \033[m\033[1m$script_name\033[32m .. \033[m" echo -e "\033[1m----------\033[m" fi # ---------- # Read Configurations from $conf_file # ---------- # - Give your default values here # - DEFAULT_FQDN_HOSTNAME="$(hostname -f)" DEFAULT_GREENLIGTH_DIR="/usr/local/greenlight" if [[ -f "$conf_file" ]]; then source "$conf_file" else warn "No configuration file '$conf_file' present.\n Loading default values.." fi [[ -n "$FQDN_HOSTNAME" ]] && DEFAULT_FQDN_HOSTNAME="$FQDN_HOSTNAME" [[ -n "$GREENLIGTH_DIR" ]] && DEFAULT_GREENLIGTH_DIR="$GREENLIGTH_DIR" blank_line echononl "Detect distribution/release of running OS.." detect_os > "$log_file" 2>&1 if [[ $? -ne 0 ]]; then echo_failed error "$(cat "$log_file")" else echo_ok fi FQDN_HOSTNAME= echo "" echo -e "\033[32m--\033[m" echo "" echo "Insert full qualified hostname for BigBlueButton Service" echo "" if [[ -n "$DEFAULT_FQDN_HOSTNAME" ]]; then while [[ "X${FQDN_HOSTNAME}" = "X" ]]; do echononl "Full qualified hostname [${DEFAULT_FQDN_HOSTNAME}]: " read FQDN_HOSTNAME if [[ "X${FQDN_HOSTNAME}" = "X" ]]; then FQDN_HOSTNAME=$DEFAULT_FQDN_HOSTNAME fi if [[ ! $FQDN_HOSTNAME =~ \. ]]; then echo -e "\n\tGiven Host \033[33m\033[1m$FQDN_HOSTNAME\033[m seems not to be a full qualified hostname.\n" FQDN_HOSTNAME="" fi done else while [[ "X${FQDN_HOSTNAME}" = "X" ]]; do echononl "Full qualified hostname: " read FQDN_HOSTNAME if [[ "X${FQDN_HOSTNAME}" = "X" ]]; then echo -e "\n\t\033[33m\033[1mFull qualified hostname is reqired\033[m\n" fi if [[ ! $FQDN_HOSTNAME =~ \. ]]; then echo -e "\n\tGiven Host \033[33m\033[1m$FQDN_HOSTNAME\033[m seems not to be a full qualified hostname.\n" FQDN_HOSTNAME="" fi done fi HOSTNAME="${FQDN_HOSTNAME%%.*}" GREENLIGTH_DIR= echo "" echo -e "\033[32m--\033[m" echo "" echo "Give the path into install 'greelight':" echo "" if [[ -n "$DEFAULT_GREENLIGTH_DIR" ]]; then while [[ "X${GREENLIGTH_DIR}" = "X" ]]; do echononl "Full qualified hostname [${DEFAULT_GREENLIGTH_DIR}]: " read GREENLIGTH_DIR if [[ "X${GREENLIGTH_DIR}" = "X" ]]; then GREENLIGTH_DIR=$DEFAULT_GREENLIGTH_DIR fi if [[ ! -d "$(dirname "$GREENLIGTH_DIR")" ]]; then echo -e "\n\tBase directory \033[33m\033[1m$(dirname "$GREENLIGTH_DIR")\033[m not found.\n" GREENLIGTH_DIR="" fi done else while [[ "X${GREENLIGTH_DIR}" = "X" ]]; do echononl "Full qualified hostname: " read GREENLIGTH_DIR if [[ "X${GREENLIGTH_DIR}" = "X" ]]; then echo -e "\n\t\033[33m\033[1mInstall directory is reqired\033[m\n" fi if [[ ! -d "$(dirname "$GREENLIGTH_DIR")" ]]; then echo -e "\n\tBase directory \033[33m\033[1m$(dirname "$GREENLIGTH_DIR")\033[m not found.\n" GREENLIGTH_DIR="" fi done fi echo "" echo "" echo -e "\t\033[32mStart pre-install script for BigBlueButton Service with the following parameters\033[m" echo "" echo -e "\tFull qualified Hostname............: $FQDN_HOSTNAME" echo -e "\tHostname...........................: $HOSTNAME" echo "" echo -e "\tOS Distribution....................: $DIST" echo -e "\tDistribution's codename............: $DIST_CODENAME" echo "" echo -e "\tInstallation directory greenlight..: $GREENLIGTH_DIR" echo "" echononl "einverstanden (yes/no): " read OK OK=${OK,,} while [ "X$OK" != "Xyes" -a "X$OK" != "Xno" ]; do echononl "Wrong entry! [yes/no]: " read OK OK=${OK,,} done [ $OK = "yes" ] || fatal Repeat with other settings.. echo "" blank_line # Stop Service if started # echononl "Stop Greenlight Service.." if $(ps ax | grep -v grep | grep -q /usr/bin/docker-proxy ) ; then cd $GREENLIGTH_DIR && docker-compose down > "$log_file" 2>&1 if [[ $? -ne 0 ]]; then echo_failed error "$(cat "$log_file")" else echo_ok fi else echo_skipped fi # Remove old versions of Docker # echononl "Remove old versions of Docker .." apt-get remove -y docker docker-engine docker.io containerd runc > "$log_file" 2>&1 if [[ $? -ne 0 ]]; then echo_failed error "$(cat "$log_file")" else echo_ok fi # Install packages to allow apt to use a repository over HTTPS # echononl "Install packages to allow apt to use a repository over HTTPS .." apt-get install \ apt-transport-https \ ca-certificates \ curl \ gnupg-agent \ software-properties-common -y > "$log_file" 2>&1 if [[ $? -ne 0 ]]; then echo_failed error "$(cat "$log_file")" else echo_ok fi blank_line # Add Docker’s official GPG key # echononl "Add Docker's official GPG key .." curl -fsSL https://download.docker.com/linux/ubuntu/gpg 2> "$log_file" | gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg >> "$log_file" 2>&1 if [[ $? -ne 0 ]]; then echo_failed error "$(cat "$log_file")" else echo_ok fi # Add Dockers stable repository # echononl "Add Dockers stable repositor .." cat < /etc/apt/sources.list.d/docker.list 2> "$log_file" deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable EOF if [[ $? -ne 0 ]]; then echo_failed error "$(cat "$log_file")" else echo_ok fi # Update the apt package index. # echononl "Update the apt package index. .." apt-get update > "$log_file" 2>&1 if [[ $? -ne 0 ]]; then echo_failed error "$(cat "$log_file")" else echo_ok fi # Install the latest version of Docker Engine - Community and containerd # echononl "Install the latest version of Docker Engine - Community and containerd .." DEBIAN_FRONTEND=noninteractive apt-get -y install docker-ce docker-ce-cli containerd.io > "$log_file" 2>&1 if [[ $? -ne 0 ]]; then echo_failed error "$(cat "$log_file")" else echo_ok fi blank_line ## Deinstall apparmor ## ## Needed if docker is running in a LX Conatiner ## #echononl "Deinstall apparmor - Needed because docker is running in a LX-Container .." #DEBIAN_FRONTEND=noninteractive apt-get -y remove apparmor > "$log_file" 2>&1 #if [[ $? -ne 0 ]]; then # echo_failed # error "$(cat "$log_file")" #else # echo_ok #fi # # #blank_line # Create the Greenlight directory for its configuration to live in. # echononl "Create the Greenlight directory for its configuration to live in. .." if [[ -d "$GREENLIGTH_DIR" ]] ; then echo_skipped else mkdir "$GREENLIGTH_DIR" > "$log_file" 2>&1 if [[ $? -ne 0 ]]; then echo_failed error "$(cat "$log_file")" else echo_ok fi fi echononl "Enter Greenlight directory .." cd "$GREENLIGTH_DIR" > "$log_file" 2>&1 if [[ $? -ne 0 ]]; then echo_failed error "$(cat "$log_file")" else echo_ok fi # Greenlight will read its environment configuration from the .env file. To generate this # file and install the Greenlight Docker image, run (inside greenlight directory): # # docker run --rm bigbluebutton/greenlight:v2 cat ./sample.env > .env # _new_env=false echononl "Generate environment configuration and install Greenlight Docker image .." if [[ -s ${GREENLIGTH_DIR}/.env ]]; then echo_skipped else docker run --rm bigbluebutton/greenlight:v2 cat ./sample.env > .env 2> "$log_file" if [[ $? -ne 0 ]]; then echo_failed error "$(cat "$log_file")" else echo_ok _new_env=true fi fi # Greenlight needs a secret key in order to run in production. To generate this, run: # # docker run --rm bigbluebutton/greenlight:v2 bundle exec rake secret # _secret_key_found=false echononl "Generating a Secret Key (in order to run in production).." if [[ -z "$(grep -E "^\s*SECRET_KEY_BASE\s*=" ${GREENLIGTH_DIR}/.env 2> /dev/null | cut -d '=' -f2)" ]] ; then _greenlight_secret="$(docker run --rm bigbluebutton/greenlight:v2 bundle exec rake secret 2> "$log_file")" if [[ -s "$log_file" ]] ; then echo_failed error "$(cat "$log_file")" else echo_ok fi else echo_skipped _secret_key_found=true fi # Set 'SECRET_KEY_BASE' with generated Secret Key # _key="SECRET_KEY_BASE" _val="$_greenlight_secret" echononl "Set 'SECRET_KEY_BASE' env with generated Secret Key at file '.env'.." if $_secret_key_found ; then echo_skipped else perl -i -n -p -e "s/^(\s*${_key}\s*=.*)/##! \1\n${_key}=${_val}/" \ ${GREENLIGTH_DIR}/.env > "$log_file" 2>&1 if [[ $? -ne 0 ]]; then echo_failed error "$(cat "$log_file")" else echo_ok fi fi # Get BigBlueButtons secret .. # echononl "Get BigBlueButtons secret .." _bbb_secret="$(bbb-conf --secret 2> $log_file | grep -i -E "^\s*Secret" 2> $log_file | awk '{print$2}' 2> $log_file)" if [[ -s "$log_file" ]] ; then echo_failed error "$(cat "$log_file")" else echo_ok fi # Set 'BIGBLUEBUTTON_SECRET' with generated Secret Key # _key="BIGBLUEBUTTON_SECRET" _val="$_bbb_secret" echononl "Set 'BIGBLUEBUTTON_SECRET' env with BBB's Secret Key at file '.env'.." if $(grep -E -q "^\s*${_key}\s*=\s*${_val}" ${GREENLIGTH_DIR}/.env 2> /dev/null) ; then echo_skipped else perl -i -n -p -e "s/^(\s*${_key}\s*=.*)/##! \1\n${_key}=${_val}/" \ ${GREENLIGTH_DIR}/.env > "$log_file" 2>&1 if [[ $? -ne 0 ]]; then echo_failed error "$(cat "$log_file")" else echo_ok fi fi # Get BigBlueButtons url .. # echononl "Get BigBlueButtons URL .." _bbb_url="$(bbb-conf --secret 2> $log_file | grep -i -E "^\s*URL" 2> $log_file | awk '{print$2}' 2> $log_file)" if [[ -s "$log_file" ]] ; then echo_failed error "$(cat "$log_file")" else echo_ok fi # Set 'BIGBLUEBUTTON_ENDPOINT' with generated Secret Key # _key="BIGBLUEBUTTON_ENDPOINT" _val="$_bbb_url" echononl "Set 'BIGBLUEBUTTON_ENDPOINT' env with BBB's Secret Key at file '.env'.." if $(grep -E -q "^\s*${_key}\s*=\s*${_val}" ${GREENLIGTH_DIR}/.env 2> /dev/null) ; then echo_skipped else perl -i -n -p -e "s#^(\s*${_key}\s*=.*)#\#\#! \1\n${_key}=${_val}#" \ ${GREENLIGTH_DIR}/.env > "$log_file" 2>&1 if [[ $? -ne 0 ]]; then echo_failed error "$(cat "$log_file")" else echo_ok fi fi # Set SAFE_HOSTSA (Setting Allowed Hosts) # # For reasons related to security, you'll also need to specify the domain from # which the application will be accessible from. # _key="SAFE_HOSTS" _val="${FQDN_HOSTNAME}" echononl "Set '${_key}' to '${_val}' (file .env).." if $(grep -E -q "^\s*${_key}\s*=\s*${_val}" ${GREENLIGTH_DIR}/.env 2> /dev/null) ; then echo_skipped else perl -i -n -p -e "s#^(\s*${_key}\s*=.*)#\#\#! \1\n${_key}=${_val}#" \ ${GREENLIGTH_DIR}/.env > "$log_file" 2>&1 if [[ $? -ne 0 ]]; then echo_failed error "$(cat "$log_file")" else echo_ok fi fi # Set ALLOW_GREENLIGHT_ACCOUNTS # _key="ALLOW_GREENLIGHT_ACCOUNTS" _val="false" echononl "Set 'ALLOW_GREENLIGHT_ACCOUNTS' to false (file .env).." if $(grep -E -q "^\s*${_key}\s*=\s*${_val}" ${GREENLIGTH_DIR}/.env 2> /dev/null) ; then echo_skipped else perl -i -n -p -e "s#^(\s*${_key}\s*=.*)#\#\#! \1\n${_key}=${_val}#" \ ${GREENLIGTH_DIR}/.env > "$log_file" 2>&1 if [[ $? -ne 0 ]]; then echo_failed error "$(cat "$log_file")" else echo_ok fi fi blank_line echononl "Verify the configuration settings (.env file).." cd "${GREENLIGTH_DIR}" \ && docker run --rm --env-file .env bigbluebutton/greenlight:v2 bundle exec rake conf:check > "$log_file" 2>&1 if [[ $? -ne 0 ]]; then echo_failed error "$(cat "$log_file")" else echo_ok fi blank_line # Greenlight will be configured to deploy at the /b subdirectory. This is necessary so # it doesn’t conflict with the other BigBlueButton components. The Nginx configuration # for this subdirectory is stored in the Greenlight image. To add this configuration file # to your BigBlueButton server, run: # # docker run --rm bigbluebutton/greenlight:v2 cat ./greenlight.nginx | sudo tee /etc/bigbluebutton/nginx/greenlight.nginx # echononl "Add nginx configuration to BigBlueButton's service .." if [[ -f "/etc/bigbluebutton/nginx/greenlight.nginx" ]] ; then echo_skipped else docker run --rm bigbluebutton/greenlight:v2 cat ./greenlight.nginx \ > /etc/bigbluebutton/nginx/greenlight.nginx 2> $log_file if [[ $? -ne 0 ]]; then echo_failed error "$(cat "$log_file")" else echo_ok fi fi echononl "Restart nginx service.." systemctl restart nginx > "$log_file" 2>&1 if [[ $? -ne 0 ]]; then echo_failed error "$(cat "$log_file")" else echo_ok fi blank_line # Download the current stable release of Docker Compose: # echononl "Download the current stable release (v 1.29.2) of Docker Compose .." curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" \ -o /usr/local/bin/docker-compose > "$log_file" 2>&1 if [[ $? -ne 0 ]]; then echo_failed error "$(cat "$log_file")" else echo_ok fi echononl "Set executable bit to 'docker-compose'.." chmod +x /usr/local/bin/docker-compose > "$log_file" 2>&1 if [[ $? -ne 0 ]]; then echo_failed error "$(cat "$log_file")" else echo_ok fi info "To install a different version of Compose, substitute 1.29.2 with the version of Compose you want to use." blank_line echononl "Copy the docker-compose.yml file from the Greenlight image in to greenlight directory.." cd ${GREENLIGTH_DIR} \ && docker run --rm bigbluebutton/greenlight:v2 cat ./docker-compose.yml > docker-compose.yml 2> $log_file if [[ $? -ne 0 ]]; then echo_failed error "$(cat "$log_file")" else echo_ok fi blank_line # randomly generate a password for the PostgreSQL database and replace the entries # in the .env and docker-compose.yml # # export pass=$(openssl rand -hex 8) # sed -i 's/POSTGRES_PASSWORD=password/POSTGRES_PASSWORD='$_postgresql_pass'/g' docker-compose.yml # sed -i 's/DB_PASSWORD=password/DB_PASSWORD='$_postgresql_pass'/g' .env # _postgresql_pass="" _pass_generated=false echononl "Generate password for the PostgreSQL database.." if $_new_env ; then _postgresql_pass="$(openssl rand -base64 24 2> $log_file)" if [[ -s "$log_file" ]] ; then echo_failed error "$(cat "$log_file")" else echo_ok _pass_generated=true fi else echo_skipped fi echononl "Set 'POSTGRES_PASSWORD' (file docker-compose.yml).." if $_pass_generated ; then sed -i 's/POSTGRES_PASSWORD=password/POSTGRES_PASSWORD='$_postgresql_pass'/g' \ ${GREENLIGTH_DIR}/docker-compose.yml > "$log_file" 2>&1 if [[ $? -ne 0 ]]; then echo_failed error "$(cat "$log_file")" else echo_ok fi else echo_skipped fi # Set DB_PASSWORD' # _key="DB_PASSWORD" _val="$_postgresql_pass" echononl "Set DB_PASSWORD (file .env).." if $_pass_generated ; then perl -i -n -p -e "s#^(\s*${_key}\s*=.*)#\#\#! \1\n${_key}=${_val}#" \ ${GREENLIGTH_DIR}/.env > "$log_file" 2>&1 if [[ $? -ne 0 ]]; then echo_failed error "$(cat "$log_file")" else echo_ok fi else echo_skipped fi blank_line echononl "Create cronjob to start Greenlight service after booting the system.." if $(crontab -l 2>/dev/null | grep -q -E "^@reboot\s+.*\s+docker-compose up -d" 2> /dev/null) ; then echo_skipped else _crontab_tmp_file="${LOCK_DIR}/crontab_root.$$" crontab -l > $_crontab_tmp_file 2> /dev/null if [[ $? -ne 0 ]]; then echo_failed error "$(cat "$log_file")" else echo "" >> $_crontab_tmp_file echo "# Start greenlight service (docker)" >> $_crontab_tmp_file echo "#" >> $_crontab_tmp_file echo "@reboot cd \"$GREENLIGTH_DIR\" && docker-compose up -d" >> $_crontab_tmp_file crontab $_crontab_tmp_file > "$log_file" 2>&1 if [[ $? -ne 0 ]]; then echo_failed error "$(cat "$log_file")" else echo_ok fi fi fi blank_line echononl "Start Greenlight service (vi docker).." cd ${GREENLIGTH_DIR} && docker-compose up -d > $log_file 2>&1 if [[ $? -ne 0 ]]; then echo_failed error "$(cat "$log_file")" else echo_ok fi blank_line note "To create an Administrator account with the default values, in the Greenlight directory, run the following command: # cd $GREENLIGTH_DIR # \033[1mdocker exec greenlight-v2 bundle exec rake admin:create\033[m If you would like to configure the name, email, or password of the Administrator account, replace the previous command with this: # cd $GREENLIGTH_DIR # \033[1mdocker exec greenlight-v2 bundle exec rake user:create[\"name\",\"email\",\"password\",\"admin\"]\033[m Once the command has finished it will print the account's email and password." note "Optionally, if you wish to have the default landing page at the root of your BigBlueButton server redirect to Greenlight, add the following entry to the bottom of /etc/nginx/sites-available/bigbluebutton just before the last } character. \033[33mlocation = / { return 307 /b; }\033[m To have this change take effect, you must once again restart Nginx." clean_up 0