#!/bin/bash # The most recent program version. _VERSION="2.0.4" _V="2.0" # The program full name PROGRAM_NAME="Docker Deployment" # make sure whiptail is installed command -v whiptail >/dev/null 2>&1 || { echo >&2 "ERROR: ${PROGRAM_NAME} v${_VERSION} script require whiptail." exit 1 } # make sure docker is installed command -v docker >/dev/null 2>&1 || { echo >&2 "ERROR: ${PROGRAM_NAME} v${_VERSION} script require docker." exit 1 } # make sure docker-compose is installed command -v docker-compose >/dev/null 2>&1 || { echo >&2 "ERROR: ${PROGRAM_NAME} v${_VERSION} script require docker-compose." exit 1 } # just clear the screen clear #####################################################################################################################VDM ######################################## The main method function main() { # we check if we have a type and a task # we use the __TRuST__ convention AS "PUBLIC METHODS" to avoid wrong calls, and hide other functions if [ ${#VDM_CONTAINER_TYPE} -ge 1 ] && [ ${#VDM_TASK} -ge 1 ] && isFunc "${VDM_CONTAINER_TYPE}__TRuST__${VDM_TASK}"; then "${VDM_CONTAINER_TYPE}__TRuST__${VDM_TASK}" else mainMenu fi } #####################################################################################################################VDM ######################################## SETUP TRAEFIK function traefik__TRuST__setup() { # load this container type globals # shellcheck disable=SC1090 [ -f "${VDM_REPO_PATH}/${VDM_CONTAINER_TYPE}/.env" ] && source "${VDM_REPO_PATH}/${VDM_CONTAINER_TYPE}/.env" # check if we have secure switch set if [ "${VDM_SECURE:-not}" = 'not' ]; then # check the security switch if (whiptail --yesno "Would you like to use Letsencrypt auto setup for your containers [only for server with public static IP]" --defaultno --title "Letsencrypt" 8 112); then # we set the secure switch VDM_SECURE=true else VDM_SECURE=false fi fi # setup letsencrypt stuff if $VDM_SECURE; then VDM_REMOVE_SECURE='' VDM_HTTP_SCHEME="https" # get the email if not set [ ${#VDM_SECURE_EMAIL} -ge 1 ] || { echo -n "[enter] Email: " read -r VDM_SECURE_EMAIL # make sure value was entered [ ${#VDM_SECURE_EMAIL} -ge 1 ] || exit } else VDM_REMOVE_SECURE="#" VDM_HTTP_SCHEME="http" fi # set the main domain if not set while [ ${#VDM_DOMAIN} -le 1 ]; do # get the value VDM_DOMAIN=$(getInput "Enter main domain of all your containers.\n[only one main domain allowed for now, must have at least one dot]" \ "${USER}.vdm" 'Enter Main Domain') # keep asking if empty or does exist [ ${#VDM_DOMAIN} -ge 1 ] || { showError "You must enter a domain name!" } done # add this value if not set variable setEnvVariable "VDM_DOMAIN=\"${VDM_DOMAIN}\"" # add this value if not set variable setEnvVariable "VDM_SECURE=${VDM_SECURE}" ########################## ### export all we need # global export VDM_CONTAINER_TYPE export VDM_REPO_PATH export VDM_PROJECT_PATH export VDM_DOMAIN export VDM_SECURE # container export VDM_REMOVE_SECURE export VDM_HTTP_SCHEME export VDM_SECURE_EMAIL ## create the directory if it does not yet already exist # shellcheck disable=SC2174 mkdir -p -m 700 "${VDM_REPO_PATH}/${VDM_CONTAINER_TYPE}" ## place this docker composer file in its place traefikContainer >"${VDM_REPO_PATH}/${VDM_CONTAINER_TYPE}/docker-compose.yml" ## set permissions chmod 600 "${VDM_REPO_PATH}/${VDM_CONTAINER_TYPE}/docker-compose.yml" # saved the file showNotice "Saved ${VDM_CONTAINER_TYPE}:docker-compose.yml file.\nSetup of this container is complete!" # ask if we should continue to enable if (whiptail --yesno "Would you also like to enable this ${VDM_CONTAINER_TYPE^} container" --defaultno --title "Enable Container" 8 112); then enableContainer "${VDM_CONTAINER_TYPE}" fi ########################## ### unset all no longer needed # container unset VDM_REMOVE_SECURE unset VDM_HTTP_SCHEME unset VDM_SECURE_EMAIL # return a success return 0 } # return the Traefik Container setup yml function traefikContainer() { # we build the yml file cat <"${VDM_REPO_PATH}/${VDM_CONTAINER_TYPE}/docker-compose.yml" ## set permissions chmod 600 "${VDM_REPO_PATH}/${VDM_CONTAINER_TYPE}/docker-compose.yml" # saved the file showNotice "Saved ${VDM_CONTAINER_TYPE}:docker-compose.yml file.\nSetup of this container is complete!" # ask if we should continue to enable if (whiptail --yesno "Would you also like to enable this ${VDM_CONTAINER_TYPE^} container" --defaultno --title "Enable Container" 8 112); then enableContainer "${VDM_CONTAINER_TYPE}" fi ########################## ### unset all no longer needed # container unset VDM_REMOVE_SECURE unset VDM_ENTRY_POINT # return a success return 0 } # return the Portainer Container setup yml function portainerContainer() { # we build the yml file cat <>"${VDM_REPO_PATH}/${VDM_CONTAINER_TYPE}/.env" # get the database name needed while [ ${#vdm_database_name} -le 1 ]; do # get the value vdm_database_name=$(getInput "Enter Database Name\n[Text with no spaces that is only underscore and alphabetical]" \ "vdm_io" 'Enter Database Name') # keep asking if empty or does exist [ ${#vdm_database_name} -ge 1 ] || { showError "You must enter a database name!" } done # get the database user name needed while [ ${#vdm_database_user} -le 1 ]; do # get the value vdm_database_user=$(getInput "Enter Database Username\n[Text with no spaces that is only underscore and alphabetical]" \ "vdm_user" 'Enter Database Username') # keep asking if empty or does exist [ ${#vdm_database_user} -ge 1 ] || { showError "You must enter a database username!" } done # get the database user password needed while [ ${#vdm_database_pass} -le 1 ]; do # get the value vdm_database_pass=$(getPassword "Enter Database User Password" \ "$(getRandomPass 20)" 'Enter Database User Password') # keep asking if empty or does exist [ ${#vdm_database_pass} -ge 1 ] || { showError "You must enter a database user password!" } done # get the database root password while [ ${#vdm_database_rootpass} -le 1 ]; do # get the value vdm_database_rootpass=$(getPassword "Enter Database Root Password" \ "$(getRandomPass 40)" 'Enter Database Root Password') # keep asking if empty or does exist [ ${#vdm_database_rootpass} -ge 1 ] || { showError "You must enter a database root password!" } done } # add this value if not set variable setEnvVariable "VDM_DOMAIN=\"${VDM_DOMAIN}\"" # add this value if not set variable setEnvVariable "VDM_SECURE=${VDM_SECURE}" # add this value if not set variable [ ${#vdm_database_name} -ge 1 ] && setContainerEnvVariable "VDM_${VDM_ENV_KEY}_DB=\"${vdm_database_name}\"" # add this value if not set variable [ ${#vdm_database_user} -ge 1 ] && setContainerEnvVariable "VDM_${VDM_ENV_KEY}_DB_USER=\"${vdm_database_user}\"" # add this value if not set variable [ ${#vdm_database_pass} -ge 1 ] && setContainerEnvVariable "VDM_${VDM_ENV_KEY}_DB_PASS=\"${vdm_database_pass}\"" # add this value if not set variable [ ${#vdm_database_rootpass} -ge 1 ] && setContainerEnvVariable "VDM_${VDM_ENV_KEY}_DB_ROOT=\"${vdm_database_rootpass}\"" # add the projects path setContainerEnvVariable "VDM_PROJECT_PATH=\"${VDM_PROJECT_PATH}\"" ########################## ### export all we need # global export VDM_CONTAINER_TYPE export VDM_REPO_PATH export VDM_PROJECT_PATH export VDM_DOMAIN export VDM_SECURE export VDM_UPDATE_HOST # container export VDM_SUBDOMAIN export VDM_JV export VDM_KEY export VDM_ENV_KEY export VDM_REMOVE_SECURE export VDM_ENTRY_POINT export VDM_HTTP_SCHEME # container lower export vdm_database_name export vdm_database_user export vdm_database_pass export vdm_database_rootpass # set host file if needed updateHostFile # also set the database domain updateHostFile "${VDM_SUBDOMAIN}db" # create the directory if it does not yet already exist # shellcheck disable=SC2174 mkdir -p -m 700 "${VDM_REPO_PATH}/${VDM_CONTAINER_TYPE}/available/${VDM_SUBDOMAIN}.${VDM_DOMAIN}" # place this docker composer file in its place joomlaContainer >"${VDM_REPO_PATH}/${VDM_CONTAINER_TYPE}/available/${VDM_SUBDOMAIN}.${VDM_DOMAIN}/docker-compose.yml" # set permissions chmod 600 "${VDM_REPO_PATH}/${VDM_CONTAINER_TYPE}/available/${VDM_SUBDOMAIN}.${VDM_DOMAIN}/docker-compose.yml" # saved the file showNotice "Saved ${VDM_CONTAINER_TYPE}:docker-compose.yml file.\nSetup of this container is complete!" # ask if we should continue to enable if (whiptail --yesno "Would you also like to enable this ${VDM_CONTAINER_TYPE^} container" --defaultno --title "Enable Container" 8 112); then # we set the container details export VDM_CONTAINER="${VDM_SUBDOMAIN}.${VDM_DOMAIN}" # then we enable it enableContainer "${VDM_CONTAINER_TYPE}" fi # display the configurations showJoomlaConfigDetails ########################## ### unset all no longer needed # container unset VDM_SUBDOMAIN unset VDM_JV unset VDM_KEY unset VDM_ENV_KEY unset VDM_REMOVE_SECURE unset VDM_ENTRY_POINT unset VDM_HTTP_SCHEME # container lower unset vdm_database_name unset vdm_database_user unset vdm_database_pass unset vdm_database_rootpass # return a success return 0 } # return the Joomla Container setup yml function joomlaContainer() { # we build the yml file cat <"${VDM_REPO_PATH}/${VDM_CONTAINER_TYPE}/available/${VDM_USER_NAME}.${VDM_DOMAIN}/docker-compose.yml" # set permissions chmod 600 "${VDM_REPO_PATH}/${VDM_CONTAINER_TYPE}/available/${VDM_USER_NAME}.${VDM_DOMAIN}/docker-compose.yml" # saved the file showNotice "Saved ${VDM_CONTAINER_TYPE}:docker-compose.yml file.\nSetup of this container is complete!" # ask if we should continue to enable if (whiptail --yesno "Would you also like to enable this ${VDM_CONTAINER_TYPE^} container" --defaultno --title "Enable Container" 8 112); then # we set the container details export VDM_CONTAINER="${VDM_USER_NAME}.${VDM_DOMAIN}" # then we enable it enableContainer "${VDM_CONTAINER_TYPE}" fi ########################## ### unset all no longer needed # container unset VDM_PORT unset VDM_USER_NAME unset VDM_KEY unset VDM_ENV_KEY unset VDM_PUBLIC_KEY_GLOBAL_DIR unset VDM_PUBLIC_KEY_U_DIR unset VDM_PROJECT_U_DIR # return a success return 0 } # return the Openssh Container setup yml function opensshContainer() { # get the projects to mount local mount_projects="$1" # we build the yml file # we use 33 as this is the www-data ID cat </dev/null 2>&1; then ### Fix the folder permissions so the active user (1000) can access the files echo "Fixing the folder permissions of ${persistent} joomla so user:$USER can access them" sudo setfacl -R -m u:"$USER":rwx "${VDM_PROJECT_PATH}/${persistent}/joomla" else echo "[ERROR] Could not fix the permissions of the ${persistent} joomla so user:$USER can access them." echo "[ERROR] You will need to install: setfacl for this option to work, then run this fix again." fi ### Fix the folder ownership of database folders # echo "Fixing the folder ownership of ${persistent} database folders" # sudo chown -R systemd-coredump:systemd-coredump "${VDM_PROJECT_PATH}/${persistent}/db" ### Fix the folder permissions for the database files # echo "Fixing the file and folder permissions for the ${persistent} database files" # # Change the file permissions sudo find "${VDM_PROJECT_PATH}/${persistent}/db" -type f -exec chmod 660 {} \; sudo find "${VDM_PROJECT_PATH}/${persistent}/db" -type d -exec chmod 700 {} \; # show the completion of this permission fix showNotice "Permissions fix completed on (${persistent})." else showError "${VDM_PROJECT_PATH}/${persistent} is not a joomla persistent volume and was skipped." fi done fi fi } # delete persistent volumes function deletePersistentVolumes() { # we first check if we have some volumes if hasDirectories '' "${VDM_PROJECT_PATH}"; then # set some local variables local vdm_delete_volumes local persistent # saved the file showNotice "Only delete persistent volumes of which you have made absolutely sure its no longer in use!" # get containers to enable vdm_delete_volumes=$(getSelectedDirectories "Select persistent volume\s to delete." \ "${VDM_PROJECT_PATH}" "Select Persistent Volume\s to Delete") # check that we have something, else return to main menu if [ ${#vdm_delete_volumes} -ge 1 ]; then # convert the string to and array IFS=' ' read -r -a vdm_delete_volumes_array <<<"${vdm_delete_volumes[@]}" # loop over the directories to build the for volumes in "${vdm_delete_volumes_array[@]}"; do # remove the " from the string persistent="${volumes//\"/}" # last serious check and then its gone if [ -d "${VDM_PROJECT_PATH}/${persistent}" ] && (whiptail --yesno "Are you absolutely sure you would like to delete this (${persistent}) persistent volume. THIS CAN'T BE UNDONE!" --title "Delete Persistent Volume" 15 112); then # then remove soft link sudo rm -rf "${VDM_PROJECT_PATH}/${persistent}" fi done fi else showError "There are no persistent volumes found in ${VDM_PROJECT_PATH}." fi } # make an update function runUpdate() { # check that we have an access token getAccessToken || return 1 # remove the current version if [ -f /usr/local/bin/docker-deploy ]; then # just backup in case of failure sudo mv /usr/local/bin/docker-deploy /usr/local/bin/docker-deploy.bak fi # some local values local branch # get the target branch to use in our update branch=$(getTargetBranch) # pull the latest version. Master is always the latest if sudo curl --fail -L "https://git.vdm.dev/api/v1/repos/octoleo/docker-deploy/raw/src/docker-deploy?ref=${branch:-master}&access_token=${VDM_ACCESS_TOKEN}" -o /usr/local/bin/docker-deploy 2>/dev/null; then # give success message echo "SUCCESS: Update was successful." # do we have a backup if [ -f /usr/local/bin/docker-deploy.bak ]; then # lets remove it now sudo rm -f /usr/local/bin/docker-deploy.bak fi else # show the error echo >&2 "ERROR: Update failed please try again later." # do we have a backup if [ -f /usr/local/bin/docker-deploy.bak ]; then # move backup back sudo mv /usr/local/bin/docker-deploy.bak /usr/local/bin/docker-deploy fi fi # always set the permission again if we have a file if [ -f /usr/local/bin/docker-deploy ]; then # the we make sure its executable sudo chmod +x /usr/local/bin/docker-deploy fi # always exit so the new script can load exit 0 } # make an uninstall function runUninstall() { # little notice showNotice "We have three uninstall options: 1) Complete. 2) Just Script. 3) Make your selection." # first safety check if (whiptail --yesno "We are just trying to be careful here, therefore we have a few questions. Please remember there is an auto update option!\n\ Are you absolutely sure you want to continue with the uninstalling process?" --defaultno --title "Uninstalling ${PROGRAM_NAME} v${_VERSION} " 12 112); then # we have four main options if (whiptail --yesno "Okay, So do you want to completely remove everything? This is the most dangerous option! IT CAN'T BE UNDONE!\ We will remove literally everything like this script was never here." --defaultno --title "Complete Uninstall of ${PROGRAM_NAME} v${_VERSION} " 12 112); then if [ -d "${VDM_REPO_PATH}/joomla" ]; then # take down all joomla containers downContainers 'joomla' # now completely remove Joomla configurations sudo rm -fr "${VDM_REPO_PATH}/joomla" fi # Remove all of Openssh Docker stuff if [ -d "${VDM_REPO_PATH}/openssh" ]; then # take down all joomla containers downContainers 'openssh' # now completely remove Joomla configurations sudo rm -fr "${VDM_REPO_PATH}/openssh" fi # Remove all of Portainer Docker stuff if [ -d "${VDM_REPO_PATH}/portainer" ]; then # take down all portainer containers disableContainer 'portainer' # now completely remove Portainer configurations sudo rm -fr "${VDM_REPO_PATH}/portainer" fi # Remove all of Traefik Docker stuff if [ -d "${VDM_REPO_PATH}/traefik" ]; then # take down all traefik containers disableContainer 'traefik' # now completely remove Traefik configurations sudo rm -fr "${VDM_REPO_PATH}/traefik" fi # remove config if found if [ -d "${VDM_SRC_PATH}" ]; then sudo rm -fr "${VDM_SRC_PATH}" fi # remove config if found if [ -d "${VDM_REPO_PATH}" ]; then sudo rm -fr "${VDM_REPO_PATH}" fi elif (whiptail --yesno "Would you like to only remove the actual ${PROGRAM_NAME} v${_V} script but keep all the Docker stuff?" --title "Keep Docker Stuff" 8 112); then # now remove the docker-deploy script if [ -f /usr/local/bin/docker-deploy ]; then sudo rm -f /usr/local/bin/docker-deploy fi # give the final message whiptail --title "${PROGRAM_NAME} v${_VERSION} is UNINSTALLED" --msgbox "\n\ ${PROGRAM_NAME} v${_V} has been uninstalled.\n\n\ We have not touched any of the Docker stuff.\n\ To also remove these you will have to manually pull down the Docker containers (if their are any running) and then remove the following directories.\n\n\ DOCKER: ${VDM_REPO_PATH} \n\ VOLUMES: ${VDM_PROJECT_PATH} \n\ CONFIG: ${VDM_SRC_PATH}" 20 112 # we exit here... where done! exit 0 else # little notice showNotice "This option lets you choose what you keep, so read the questions carefully! IT CAN'T BE UNDONE!" # shellcheck disable=SC1090 # ----------------------------------------------------- MULTI CONTAINERS # Remove all of Joomla Docker stuff if [ -d "${VDM_REPO_PATH}/joomla" ] && (whiptail --yesno "Would you like to completely remove the Joomla Docker yml configurations in (${VDM_REPO_PATH}/joomla)?" --defaultno --title "Remove Docker Config" 12 112); then # take down all joomla containers downContainers 'joomla' # now completely remove Joomla configurations sudo rm -fr "${VDM_REPO_PATH}/joomla" fi # check if we have possible joomla containers (this will only run if they did not remove it above) if [ -e "${VDM_REPO_PATH}/joomla/enabled" ] && (whiptail --yesno "Would you like to take down Joomla containers?" --defaultno --title "Take Down Containers" 8 112); then # take down all joomla containers downContainers 'joomla' # remove all enabled rm -fr "${VDM_REPO_PATH}/joomla/enabled" fi # Remove all of Openssh Docker stuff if [ -d "${VDM_REPO_PATH}/openssh" ] && (whiptail --yesno "Would you like to completely remove the Openssh Docker yml configurations in (${VDM_REPO_PATH}/openssh)?" --defaultno --title "Remove Docker Config" 12 112); then # take down all joomla containers downContainers 'openssh' # now completely remove Joomla configurations sudo rm -fr "${VDM_REPO_PATH}/openssh" fi # check if we have possible openssh containers (this will only run if they did not remove it above) if [ -e "${VDM_REPO_PATH}/openssh/enabled" ] && (whiptail --yesno "Would you like to take down Openssh containers?" --defaultno --title "Take Down Containers" 8 112); then # take down all joomla containers downContainers 'openssh' # remove all enabled rm -fr "${VDM_REPO_PATH}/openssh/enabled" fi # ----------------------------------------------------- SINGLE CONTAINER # Remove all of Portainer Docker stuff if [ -d "${VDM_REPO_PATH}/portainer" ] && (whiptail --yesno "Would you like to completely remove the Portainer Docker yml configurations in (${VDM_REPO_PATH}/portainer)?" --defaultno --title "Remove Docker Config" 12 112); then # take down all portainer containers disableContainer 'portainer' # now completely remove Portainer configurations sudo rm -fr "${VDM_REPO_PATH}/portainer" fi # check if we have possible portainer container (this will only run if they did not remove it above) if [ -f "${VDM_REPO_PATH}/portainer/docker-compose.yml" ] && (whiptail --yesno "Would you like to take down Portainer container?" --defaultno --title "Take Down Container" 8 112); then # take down the container disableContainer 'portainer' fi # Remove all of Traefik Docker stuff if [ -d "${VDM_REPO_PATH}/traefik" ] && (whiptail --yesno "Would you like to completely remove the Traefik Docker yml configurations in (${VDM_REPO_PATH}/traefik)?" --defaultno --title "Remove Docker Config" 12 112); then # take down all traefik containers disableContainer 'traefik' # now completely remove Traefik configurations sudo rm -fr "${VDM_REPO_PATH}/traefik" fi # check if we have possible traefik container (this will only run if they did not remove it above) if [ -f "${VDM_REPO_PATH}/traefik/docker-compose.yml" ] && (whiptail --yesno "Would you like to take down Traefik container?" --defaultno --title "Take Down Container" 8 112); then # take down the container disableContainer 'traefik' fi # remove config if found if [ -d "${VDM_SRC_PATH}" ] && (whiptail --yesno "Would you like to remove the global docker configurations?" --defaultno --title "Remove Docker Config" 8 112); then sudo rm -fr "${VDM_SRC_PATH}" fi fi # now remove the docker-deploy script if [ -f /usr/local/bin/docker-deploy ]; then sudo rm -f /usr/local/bin/docker-deploy fi # last and final question as this is most dangerous and serious issue. if [ -d "${VDM_PROJECT_PATH}" ] && (whiptail --yesno "Last question, would you like to remove all persistent volumes of your containers in (${VDM_PROJECT_PATH})?" --defaultno --title "Completely DELETE persistent volumes" 12 112); then sudo rm -rf "${VDM_PROJECT_PATH}" fi # give the final message whiptail --title "${PROGRAM_NAME} v${_VERSION} is UNINSTALLED" --msgbox "\n\n\ ${PROGRAM_NAME} v${_V} has been uninstalled." 10 112 # exit the program right now exit 0 fi } # we show the octoleo info quietly octoleoQuietly() { local message # now set the message message=" https://git.vdm.dev/octoleo/docker-deploy Welcome to an Octoleo Program (${PROGRAM_NAME} v$_VERSION) Description With this script we can easily deploy docker containers of Joomla and Openssh. This combination of these tools give rise to a powerful and very secure shared development environment. This program has **command input** options as seen in the menus item called **Show command help**, but these command are _not the only way_ to set these values. When the values are **omitted** you will be _asked in the terminal_ to manually enter the required values as needed. Furthermore, the use of **env variables** are also heavily used across the script. There are more than one .env file and the script will set those up for you whenever you run a task that make use of env variables the script will check if those values exist, and if they don't it will ask for them, and store them automatically for future use. That same time the output message to the terminal will show you where the specific .env file can be found. Author Licence Llewellyn van der Merwe GNU GENERAL PUBLIC LICENSE Version 2 --quiet" whiptail --msgbox "${message}" --fb --backtitle " Octoleo" 32 112 } # show the commands help menu function showCommandsHelpMenu() { help=$(showHelp) whiptail --msgbox --scrolltext "${help}" --fb --backtitle " Octoleo" 30 90 } #####################################################################################################################VDM ######################################## MENUS # show Joomla menu function showJoomla() { # menu for dynamic addition local menu_options=() # our counter local i=2 # load the back menu menu_options+=("back" "<-- Return to the main menu.") # setup new container menu_options+=("setup" "Setup new container") # enable existing container hasDirectories 'joomla/available' && menu_options+=("enable" "Enable existing container") && i=$((i + 1)) # disable enabled container hasDirectories 'joomla/enabled' && menu_options+=("disable" "Disable enabled container") && i=$((i + 1)) # delete a container hasDirectories 'joomla/available' && menu_options+=("delete" "Delete a container") && i=$((i + 1)) # take all enabled containers down hasDirectories 'joomla/enabled' && menu_options+=("down" "Take all enabled containers down") && i=$((i + 1)) # pull up all enabled containers hasDirectories 'joomla/enabled' && menu_options+=("up" "Pull up all enabled containers") && i=$((i + 1)) # fix permissions hasDirectories '' "${VDM_PROJECT_PATH}" && menu_options+=("fix" "Fix permissions of folders and files of a container") && i=$((i + 1)) # get the selection CHOICE=$( whiptail --menu "Make your selection" 20 112 $i \ --title "Joomla | ${PROGRAM_NAME} v${_V}" --fb \ --backtitle " Octoleo" --nocancel --notags \ "${menu_options[@]}" 3>&2 2>&1 1>&3 ) case $CHOICE in "setup") setupContainer 'joomla' ;; "enable") enableContainer 'joomla' ;; "disable") disableContainer 'joomla' ;; "delete") deleteContainer 'joomla' ;; "down") downContainers 'joomla' ;; "up") upContainers 'joomla' ;; "fix") fixContainerPermissions ;; esac } # show Openssh menu function showOpenssh() { # menu for dynamic addition local menu_options=() # our counter local i=2 # load the back menu menu_options+=("back" "<-- Return to the main menu.") # setup new container menu_options+=("setup" "Setup new container") # enable existing container hasDirectories 'openssh/available' && menu_options+=("enable" "Enable existing container") && i=$((i + 1)) # disable enabled container hasDirectories 'openssh/enabled' && menu_options+=("disable" "Disable enabled container") && i=$((i + 1)) # delete a container hasDirectories 'openssh/available' && menu_options+=("delete" "Delete a container") && i=$((i + 1)) # take all enabled containers down hasDirectories 'openssh/enabled' && menu_options+=("down" "Take all enabled containers down") && i=$((i + 1)) # pull up all enabled containers hasDirectories 'openssh/enabled' && menu_options+=("up" "Pull up all enabled containers") && i=$((i + 1)) # get the selection CHOICE=$( whiptail --menu "Make your selection" 20 112 $i \ --title "Openssh | ${PROGRAM_NAME} v${_V}" --fb \ --backtitle " Octoleo" --nocancel --notags \ "${menu_options[@]}" 3>&2 2>&1 1>&3 ) case $CHOICE in "setup") setupContainer 'openssh' ;; "enable") enableContainer 'openssh' ;; "disable") disableContainer 'openssh' ;; "delete") deleteContainer 'openssh' ;; "down") downContainers 'openssh' ;; "up") upContainers 'openssh' ;; esac } # show Traefik menu function showTraefik() { # menu for dynamic addition local menu_options=() # our counter local i=2 # load the back menu menu_options+=("back" "<-- Return to the main menu.") # setup new container menu_options+=("setup" "Setup/Rebuild Traefik") # enable existing container [ -f "${VDM_REPO_PATH}/traefik/docker-compose.yml" ] && menu_options+=("enable" "Enable Traefik") && i=$((i + 1)) # disable enabled container [ -f "${VDM_REPO_PATH}/traefik/docker-compose.yml" ] && menu_options+=("disable" "Disable Traefik") && i=$((i + 1)) # get the selection CHOICE=$( whiptail --menu "Make your selection" 16 112 $i \ --title "Traefik | ${PROGRAM_NAME} v${_V}" --fb \ --backtitle " Octoleo" --nocancel --notags \ "${menu_options[@]}" 3>&2 2>&1 1>&3 ) case $CHOICE in "setup") setupContainer 'traefik' ;; "enable") enableContainer 'traefik' ;; "disable") disableContainer 'traefik' ;; esac } # show Portainer menu function showPortainer() { # menu for dynamic addition local menu_options=() # our counter local i=2 # load the back menu menu_options+=("back" "<-- Return to the main menu.") # setup new container menu_options+=("setup" "Setup/Rebuild Portainer") # enable existing container [ -f "${VDM_REPO_PATH}/portainer/docker-compose.yml" ] && menu_options+=("enable" "Enable Portainer") && i=$((i + 1)) # disable enabled container [ -f "${VDM_REPO_PATH}/portainer/docker-compose.yml" ] && menu_options+=("disable" "Disable Portainer") && i=$((i + 1)) # get the selection CHOICE=$( whiptail --menu "Make your selection" 16 112 $i \ --title "Portainer | ${PROGRAM_NAME} v${_V}" --fb \ --backtitle " Octoleo" --nocancel --notags \ "${menu_options[@]}" 3>&2 2>&1 1>&3 ) case $CHOICE in "setup") setupContainer 'portainer' ;; "enable") enableContainer 'portainer' ;; "disable") disableContainer 'portainer' ;; esac } # show systems help menu function showHelpMenu() { # menu for dynamic addition local menu_options=() # our counter local i=7 # load the back menu menu_options+=("back" "<-- Return to the main menu.") # Show command help menu_options+=("command-help" "Help with commands") # Show folder paths menu_options+=("important-paths" "Important Paths") # Report an Issue menu_options+=("report-issue" "Report an Issue") # Update the whole script menu_options+=("update" "Update ${PROGRAM_NAME,,}") # Uninstall the whole script menu_options+=("uninstall" "Uninstall ${PROGRAM_NAME,,}") # Octoleo details menu_options+=("octoleo" "Octoleo") # get the selection CHOICE=$( whiptail --menu "Make your selection" 16 112 $i \ --title "Portainer | ${PROGRAM_NAME} v${_V}" --fb \ --backtitle " Octoleo" --nocancel --notags \ "${menu_options[@]}" 3>&2 2>&1 1>&3 ) case $CHOICE in "command-help") showCommandsHelpMenu ;; "important-paths") showImportantPaths ;; "report-issue") showLink "https://git.vdm.dev/octoleo/docker-deploy/issues" "To report an issue go to:" "Report an Issue" ;; "update") runUpdate ;; "uninstall") runUninstall ;; "octoleo") octoleoQuietly ;; esac } # MAIN MENU function mainMenu() { # menu for dynamic addition local menu_options=() # our counter local i=9 # Joomla containers menu_options+=("joomla" "Joomla Containers") # Openssh containers menu_options+=("openssh" "Openssh Containers") # Traefik container menu_options+=("traefik" "Traefik Container") # Portainer container menu_options+=("portainer" "Portainer Container") # Delete Persistent Volumes hasDirectories '' "${VDM_PROJECT_PATH}" && menu_options+=("delete" "Delete Persistent Volumes") && i=$((i + 1)) # Show help menu_options+=("help" "Main Help Menu") # Octoleo details menu_options+=("quit" "Quit Program") # get the selection while true; do CHOICE=$( whiptail --menu "Make your selection" 20 112 $i \ --title "${PROGRAM_NAME} v${_V}" --fb \ --backtitle " Octoleo" --nocancel --notags \ "${menu_options[@]}" 3>&2 2>&1 1>&3 ) case $CHOICE in "joomla") showJoomla ;; "openssh") showOpenssh ;; "traefik") showTraefik ;; "portainer") showPortainer ;; "delete") deletePersistentVolumes ;; "help") showHelpMenu ;; "quit") exit ;; esac done } #####################################################################################################################VDM ######################################## GENERAL SHARED FUNCTIONS # show error function showError() { whiptail --title "ERROR | ${PROGRAM_NAME} v${_V}" --msgbox "${1}" 12 112 } # show info function showInfo() { whiptail --title "INFO | ${PROGRAM_NAME} v${_V}" --infobox "${1}" 12 112 } # show notice function showNotice() { whiptail --title "NOTICE | ${PROGRAM_NAME} v${_V}" --msgbox "${1}" 12 112 } # show link function showLink() { whiptail --title "${3:-Open Link} | ${PROGRAM_NAME} v${_V}" --msgbox "${2:-To open the link click here:} ${1}" 8 112 } # show important paths function showImportantPaths() { local message # now set the message message=" ${PROGRAM_NAME} v$_VERSION We have a few important paths that you should know, and use to manually manage your setup. DOCKER: ${VDM_REPO_PATH} SSH: ${VDM_REPO_PATH}/openssh/.ssh VOLUMES: ${VDM_PROJECT_PATH} CONFIG: ${VDM_SRC_PATH} Then we have some key environment variable files that hold very useful and important information. Since we do not store any passwords or other important details in the docker-deploy.yml files. They are stored in these environment variable files and its permissions are (600) for security. JOOMLA: ${VDM_REPO_PATH}/joomla/.env OPENSSH: ${VDM_REPO_PATH}/openssh/.env TRAEFIK: ${VDM_REPO_PATH}/traefik/.env PORTAINER: ${VDM_REPO_PATH}/portainer/.env Not all these files or folders may exist, they are created only when needed. " whiptail --msgbox "${message}" --fb --backtitle " Octoleo" 32 112 } # show show the Joomla config details function showJoomlaConfigDetails() { # load the env back to show if set previously # shellcheck disable=SC1090 # [ -f "${VDM_REPO_PATH}/${VDM_CONTAINER_TYPE}/.env" ] && source "${VDM_REPO_PATH}/${VDM_CONTAINER_TYPE}/.env" # set some locals local message # now set the message message=" ${PROGRAM_NAME} v$_VERSION Running the Joomla container for the first time you will need these details: -------------------------------------------------------------------- URL: ${VDM_HTTP_SCHEME}${VDM_SUBDOMAIN}.${VDM_DOMAIN} DATABASE_HOST: mariadb_${VDM_KEY}:3306 -------------------------------------------------------------------- VDM_${VDM_ENV_KEY^^}_DB: ${vdm_database_name} VDM_${VDM_ENV_KEY^^}_DB_USER: ${vdm_database_user} VDM_${VDM_ENV_KEY^^}_DB_PASS: ${vdm_database_pass} VDM_${VDM_ENV_KEY^^}_DB_ROOT: ${vdm_database_rootpass} -------------------------------------------------------------------- These details are securely stored in this environment variable file ${VDM_REPO_PATH}/joomla/.env -------------------------------------------------------------------- Do not remove these details from the file, as its used to deploy the container. " whiptail --msgbox "${message}" --fb --backtitle " Octoleo" 30 112 } # we must get a random key function getRandomPass() { # simple basic random # shellcheck disable=SC2046 echo $(tr -dc 'A-HJ-NP-Za-km-z2-9' &1 1>&2 2>&3) # return the answer echo "${answer}" } # get a selected directory function getSelectedDirectory() { # the selected folder local answer # set the local path local path="${2:-}" # set local var local folder="${3:-}" # we start the selection array local selected=() # our counter local i=0 # now check if this dir has sub dirs if hasDirectories '' "$path"; then # loop over the directory for dir_ in "${path%/}/"*; do # remove the full path dir_="${dir_/$path/}" # load the selection [ "$folder" = "${dir_#/}" ] && selected+=("${dir_#/}" "${dir_#/}" "ON") || selected+=("${dir_#/}" "${dir_#/}" "OFF") # increment our pointer i=$((i + 1)) done # now make the selection answer=$(whiptail --title "${4:-Make a Selection}" --radiolist \ "${1}" 20 112 $i \ "${selected[@]}" --nocancel --notags 3>&1 1>&2 2>&3) fi # return the answer echo "${answer:-$folder}" } # select multiple directories from one directory function getSelectedDirectories() { # the selected folder local answer # set the local path local path="${2:-}" # we start the selection array local selected=() # our counter local i=0 # now check if this dir has sub dirs if hasDirectories '' "$path"; then # loop over the directory for dir_ in "${path%/}/"*; do # remove the full path dir_="${dir_/$path/}" # load the selection selected+=("${dir_#/}" "${dir_#/}" "OFF") # increment our pointer i=$((i + 1)) done # now make the selection answer=$(whiptail --title "${3:-Make a Selection}" --checklist \ "${1}" 20 112 $i \ "${selected[@]}" --nocancel --notags 3>&1 1>&2 2>&3) # return the answer echo "${answer[@]}" else echo '' fi } # create a yml dashed line function getYMLDashLine() { # get the projects to mount local line="$1" # return line cat <&1 1>&2 2>&3) # return the password echo "${PASSWORD}" } # get and set the access token function getAccessToken() { # we try getting the token twice local t=0 local new_token=false # check that we have an access token, els ask for it while [ ${#VDM_ACCESS_TOKEN} -le 30 ]; do # this is a new token new_token=true # get the value VDM_ACCESS_TOKEN=$(getInput "Enter access token for updates.\n[You can get an access token from https://git.vdm.dev/user/settings/applications]" \ '' 'Access Token') # keep asking if empty if [ ${#VDM_ACCESS_TOKEN} -le 30 ]; then showError "Updates can only be done if you have an access token." # increment our try t=$((t + 1)) # when the user for the second time does not supply the correct value we return if [ $t -eq 2 ]; then return 12 fi fi done # make the token available export VDM_ACCESS_TOKEN # store the token for next time $new_token && setEnvVariable "VDM_ACCESS_TOKEN=\"${VDM_ACCESS_TOKEN}\"" && showNotice "The token has been stored in the environment variable file (${VDM_SRC_PATH}/.env)." # we have success return 0 } # get the target branch to use in update function getTargetBranch() { # now make the selection answer=$(whiptail --title "Select Update Channel" --radiolist --nocancel --notags \ "You can select the update channel you would like to use." 10 80 2 \ "master" "Stable Version" "ON" \ "staging" "Developer Version" "OFF" \ 3>&1 1>&2 2>&3) # return the answer (default master) echo "${answer:-master}" } # set the networks in place function setNetworks() { # we create the networks docker network inspect traefik_webgateway >/dev/null 2>&1 || docker network create traefik_webgateway docker network inspect openssh_gateway >/dev/null 2>&1 || docker network create openssh_gateway } # to set a global Env Variable function setEnvVariable() { # check if the env file exist if [ -f "${VDM_SRC_PATH}/.env" ]; then grep -q "${1}" "${VDM_SRC_PATH}/.env" || echo "${1}" >>"${VDM_SRC_PATH}/.env" elif (whiptail --yesno "Can we create the ${VDM_SRC_PATH}/.env file" --title "Environment Variable File" 8 112); then # make sure the folder exist mkdir -p "${VDM_SRC_PATH}" # so we creat the file echo "${1}" >"${VDM_SRC_PATH}/.env" # make sure the permissions are secured chmod 600 "${VDM_SRC_PATH}/.env" else showError "The ${VDM_SRC_PATH}/.env file does not exist. So ${1} could not be added!" # we return false return 12 fi # we return true return 0 } # to set a container Env Variable function setContainerEnvVariable() { # check if the env file exist if [ -f "${VDM_REPO_PATH}/${VDM_CONTAINER_TYPE}/.env" ]; then grep -q "${1}" "${VDM_REPO_PATH}/${VDM_CONTAINER_TYPE}/.env" || echo "${1}" >>"${VDM_REPO_PATH}/${VDM_CONTAINER_TYPE}/.env" elif (whiptail --yesno "Can we create the ${VDM_REPO_PATH}/${VDM_CONTAINER_TYPE}/.env file" --title "Container Environment Variable File" 8 112); then # make sure the folder exist mkdir -p "${VDM_REPO_PATH}/${VDM_CONTAINER_TYPE}" # so we creat the file echo "${1}" >"${VDM_REPO_PATH}/${VDM_CONTAINER_TYPE}/.env" # make sure the permissions are secured chmod 600 "${VDM_REPO_PATH}/${VDM_CONTAINER_TYPE}/.env" else showError "The ${VDM_REPO_PATH}/${VDM_CONTAINER_TYPE}/.env file does not exist. So ${1} could not be added!" fi } # take down apache function downApache() { # make sure port 80 is not used by apache command -v apache2 >/dev/null 2>&1 && [[ $(service apache2 status) == *"active (running)"* ]] && { if (whiptail --yesno "Traefik needs port 80/443 and since Apache is also enabled (we dont know if is using these ports) so Traefik may not work. Can we disable Apache?" --defaultno --title "Disable Apache" 12 112); then sudo systemctl stop apache2.service sudo systemctl disable apache2.service fi } } # check if some thing is a function function isFunc() { declare -F "$1" >/dev/null } # update the host file function updateHostFile() { # check if we have secure switch set if [ "${VDM_UPDATE_HOST:-not}" = 'not' ]; then # check the security switch if (whiptail --yesno "Would you like to update your host file with each new domain you add?" --defaultno --title "Update /etc/hosts" 8 112); then # we set the secure switch VDM_UPDATE_HOST=true else VDM_UPDATE_HOST=false fi # add this value since its not set variable setEnvVariable "VDM_UPDATE_HOST=${VDM_UPDATE_HOST}" fi # check if we should add to host file if $VDM_UPDATE_HOST; then # check if already in host file if grep -q "${1:-$VDM_SUBDOMAIN}.${2:-$VDM_DOMAIN}" /etc/hosts; then showNotice "${USER^}, ${1:-$VDM_SUBDOMAIN}.${2:-$VDM_DOMAIN} is already in the /etc/hosts file." elif (whiptail --yesno "${USER^}, to add the ${1:-$VDM_SUBDOMAIN}.${2:-$VDM_DOMAIN} entry to your host file we need sudo privileges." --title "Give sudo Privileges" 8 112); then # add the domain to the host file echo "127.0.0.1 ${1:-$VDM_SUBDOMAIN}.${2:-$VDM_DOMAIN}" | sudo tee -a /etc/hosts >/dev/null # show notice showNotice "${USER^}, ${1:-$VDM_SUBDOMAIN}.${2:-$VDM_DOMAIN} was added to the /etc/hosts file." fi fi } #####################################################################################################################VDM ######################################## CLI MENU ʕ•ᴥ•ʔ # help message function showHelp() { cat < set type you would like to work with example: ${0##*/:-} --type joomla ====================================================== --task set type of task you would like to perform example: ${0##*/:-} --task setup ====================================================== --container Directly enabling or disabling a container with the type=joomla and task=enable/disable set The container must exist, which means it was setup previously Used without type and task Joomla-Enable is (default) example: ${0##*/:-} --container "io.vdm.dev" ====================================================== --update to update your install example: ${0##*/:-} --update ====================================================== --access-token to update the program you will need an access token from https://git.vdm.dev/user/settings/applications example: docker-deploy --access-token xxxxxxxxxxx ====================================================== --uninstall to uninstall this script example: ${0##*/:-} --uninstall ====================================================== AVAILABLE FOR TO ANY CONTAINER ====================================================== -k|--key set key for the docker compose container naming !! no spaces allowed in the key !! example: ${0##*/:-} -k="vdm" example: ${0##*/:-} --key="vdm" ====================================================== -e|--env-key set key for the environment variable naming !! no spaces allowed in the key & must be UPPERCASE !! example: ${0##*/:-} -e="VDM" example: ${0##*/:-} --env-key="VDM" ====================================================== -d|--domain set key website domain !! must be domain.tld !! example: ${0##*/:-} -d="vdm.dev" example: ${0##*/:-} --domain="vdm.dev" ====================================================== AVAILABLE FOR JOOMLA CONTAINER ====================================================== -j|--joomla-version set Joomla version number !! only number allowed !! example: ${0##*/:-} -j=3.10 example: ${0##*/:-} --joomla-version=3.10 ====================================================== -s|--sub-domain set key website sub domain !! no spaces allowed in the sub domain !! example: ${0##*/:-} -s="jcb" example: ${0##*/:-} --sub-domain="jcb" ====================================================== AVAILABLE FOR OPENSSH CONTAINER ====================================================== -u|--username set username of the container example: ${0##*/:-} -u="ubuntu" example: ${0##*/:-} --username="ubuntu" ====================================================== --uid set container user id example: ${0##*/:-} --uid=1000 ====================================================== --gid set container user group id example: ${0##*/:-} --gid=1000 ====================================================== -p|--port set ssh port to use !! do not use 22 !! example: ${0##*/:-} -p=2239 example: ${0##*/:-} --port=2239 ====================================================== --ssh-dir set ssh directory name found in the .ssh dir of this repo for the container keys This directory has separate files for each public key allowed to access the container example: ${0##*/:-} --ssh-dir="teamname" ====================================================== --sudo switch to add the container user to the sudo group of the container example: ${0##*/:-} --sudo ====================================================== -t|--time-zone