#!/bin/bash #################################################################################################### #### author: SlickStack ############################################################################ #### link: https://slickstack.io ################################################################### #### mirror: littlebizzy/slickstack/blob/master/bash/ss-install.txt ################################ #### path: /var/www/ss-install ##################################################################### #### destination: n/a (not a boilerplate) ########################################################## #### purpose: Reinstalls the entire SlickStack LEMP environment and all modules (idempotent) ####### #### module version: Ubuntu 22.04 LTS ############################################################## #### sourced by: n/a (wget -O ss slick.fyi/ss && bash ss) ########################################## #### bash aliases: ss install ###################################################################### #################################################################################################### ## SS-CONFIG MUST BE PROPERLY CONFIGURED AND ON CURRENT BUILD BEFORE RUNNING SS-INSTALL ## ## ENSURE THAT YOUR SS-CONFIG BUILD REMAINS CURRENT BY RUNNING SS-UPDATE-CONFIG ## #################################################################################################### #### TABLE OF CONTENTS (SS-Install) ################################################################ #################################################################################################### ## this is a brief summary of the different code snippets you will find in this script ## ## each section should be commented so you understand what is being accomplished ## ## A. Build Version ## A. Validate (Repair) SS-Functions ## C. Source SS-Config (Conditional) + SS-Functions ## D. Touch Timestamp File ## E. Verify Environment Compatibility ## F. Retrieve Latest SS-Config Boilerplate ## G. Interactive Setup Wizard (Populates SS-Config) ## H. Activate SS-Config File Generated By Wizard ## I. Retrieve SS-Check ## J. Force Exit (Conditional) If SSH Keys Or Third-Party Cert Missing ## K. Message (Last Chance To Exit + Begin Install) ## L. Message (Welcome Back If SS-Config Already Exists) ## M. Source SS-Config (After Setup Wizard Complete) ## N. Run SS-Check ## O. Upgrade Ubuntu Packages + Linux Kernel ## P. Configure Ubuntu ## Q. Install PHP-FPM (Before Nginx) ## R. Install Nginx (Includes SSL Certificates) ## S. Enable Maintenance Mode (After Nginx Installed) ## T. Install MySQL ## U. Install Memcached ## W. Install CMS (WordPress, PrestaShop, MediaWiki, Etc) ## X. Sync Staging Site ## Y. Install Rclone ## Z. Install UFW Firewall ## AA. Install Fail2ban ## BB. Reset All Logs To NULL ## CC. Reset Permissions (All Permissions) ## DD. Disable Maintenance Mode ## EE. Purge Caches (All Caches) ## FF. Restart Modules (All Modules) ## GG. Validate (Repair) Crontab ## HH. Display SlickStack Overview ## II. Message (Installation Successful) #################################################################################################### #### A. SS-Install: Build Version ################################################################## #################################################################################################### ## this build version ensures compatibility with the currently active ss-config file ## ## it must match the localhost ss-config otherwise installation will fail ## SS_INSTALL_BUILD="APR2024FF" #################################################################################################### #### B. SS-Install: Validate (Repair) SS-Functions ################################################# #################################################################################################### ## this attempts to restore missing or outdated ss-functions from our public mirrors ## ## we perform this check before ss-install runs and before any cron job tasks ## ## THIS SNIPPET DOES NOT RELY ON SS-CONFIG OR SS-FUNCTIONS ## SNIPPET: ss-install, ss cron jobs ## UPDATED: 15FEB2023 VALIDATE_SS_FUNCTIONS=$(grep 'SS_EOF' /var/www/ss-functions 2> /dev/null) OUTDATED_SS_FUNCTIONS=$(find "/var/www/ss-functions" -mtime 2> /dev/null) if [[ -z "${VALIDATE_SS_FUNCTIONS}" ]] || [[ -n "${OUTDATED_SS_FUNCTIONS}" ]]; then wget --no-check-certificate --no-cache --no-cookies --quiet --inet4-only --tries=30 --timeout=300 --waitretry=15 -O /tmp/ss-functions https://raw.githubusercontent.com/littlebizzy/slickstack/master/bash/ss-functions.txt VALIDATE_TMP_SS_FUNCTIONS=$(grep 'SS_EOF' /tmp/ss-functions 2> /dev/null) if [[ -n "${VALIDATE_TMP_SS_FUNCTIONS}" ]]; then mkdir -p /var/www > /dev/null 2>&1 mv -f /tmp/ss-functions /var/www/ss-functions chown root:root /var/www/ss-functions ## must be root:root chmod 0700 /var/www/ss-functions ## 0700 means only root can execute else wget --no-check-certificate --no-cache --no-cookies --quiet --inet4-only --tries=30 --timeout=300 --waitretry=15 -O /tmp/ss-functions https://gitlab.com/littlebizzy/slickstack/-/raw/master/bash/ss-functions.txt VALIDATE_TMP_SS_FUNCTIONS=$(grep 'SS_EOF' /tmp/ss-functions 2> /dev/null) if [[ -n "${VALIDATE_TMP_SS_FUNCTIONS}" ]]; then mkdir -p /var/www > /dev/null 2>&1 mv -f /tmp/ss-functions /var/www/ss-functions chown root:root /var/www/ss-functions ## must be root:root chmod 0700 /var/www/ss-functions ## 0700 means only root can execute else wget --no-check-certificate --no-cache --no-cookies --quiet --inet4-only --tries=30 --timeout=300 --waitretry=15 -O /tmp/ss-functions https://sourceforge.net/p/slickstack/code/ci/master/tree/bash/ss-functions.txt?format=raw mkdir -p /var/www > /dev/null 2>&1 mv -f /tmp/ss-functions /var/www/ss-functions chown root:root /var/www/ss-functions ## must be root:root chmod 0700 /var/www/ss-functions ## 0700 means only root can execute fi fi fi #################################################################################################### #### C. SS-Install: Source SS-Config (Conditional) + SS-Functions ################################## #################################################################################################### ## at this point we have restored ss-functions and ss-config may or may not exist yet ## ## so we source ss-functions at this point but conditionally source ss-config ## ## source ss-config (if exists) ## SS_CONFIG="/var/www/ss-config" test -f "${SS_CONFIG}" && source "${SS_CONFIG}" ## does not rely on ss-functions ## source ss-functions ## source /var/www/ss-functions ## BELOW THIS RELIES ON SS-CONFIG AND SS-FUNCTIONS #################################################################################################### #### D. SS-Install: Touch Timestamp File ########################################################### #################################################################################################### ## this is a dummy timestamp file that will remember the last time this script was run ## ## it can be useful for developer reference and is sometimes used by SlickStack ## ss_touch "${TIMESTAMP_SS_INSTALL}" #################################################################################################### #### E. SS-Install: Verify Environment Compatibility ############################################### #################################################################################################### ## here we perform some checks to ensure compatibility between different applications ## ## SlickStack requires matching build versions, Ubuntu LTS, no Docker, and etc ## ## verify ss-install build matches ss-config (if exists) ## if [[ -f "/var/www/ss-config" ]] && [[ "${SS_BUILD}" != "${SS_INSTALL_BUILD}" ]]; then ss_echo "${COLOR_WARN}ss-install: Please run ss-update-config and then run ss-install again... ${COLOR_RESET}" exit 1 fi ## verify supported ubuntu version ## if [[ "${SYSTEM_UBUNTU_VERSION}" != @(24.04|22.04|20.04|18.04) ]]; then ss_echo "${COLOR_WARN}Exiting ss-install: SlickStack is designed for Ubuntu LTS (but this VPS is running ${SYSTEM_UBUNTU_VERSION})... ${COLOR_RESET}" exit 1 fi ## REDUCE THIS to be like 500mb or something ## verify at least 5GB free disk space remains ## # if [[ "${SYSTEM_DISK_FREE}" -lt 5242880 ]]; then ## 10G = 10485760 / 5GB = 5242880 # ss_echo "${COLOR_WARN}Exiting ss-install: It looks like your server has less than 5GB free space available, please upgrade your server and then run ss-install again. ${COLOR_RESET}" # exit 1 # fi ## very not in docker/lxc container ## if [[ -f "/.dockerenv" ]] || grep -Eq '(lxc|docker)' /proc/1/cgroup; then ss_echo "${COLOR_WARN}Exiting ss-install: It appears your server is running Docker or another container... but SlickStack requires normal Ubuntu LTS without containers. ${COLOR_RESET}" exit 1 fi ## check for undefined options in ss-config ## SS_CONFIG_OPTION_PLACEHOLDER=$(grep -c '"@' "${PATH_SS_CONFIG}" 2> /dev/null) if [[ -f "${PATH_SS_CONFIG}" ]]; then if [[ "${SS_CONFIG_OPTION_PLACEHOLDER}" -gt 0 ]]; then ss_echo "${COLOR_WARN}Exiting ss-install: Replace all "@..." placeholders in ss-config and try again... ${COLOR_RESET}" exit 1 fi fi #################################################################################################### #### F. SS-Install: Retrieve Latest SS-Config Boilerplate ########################################## #################################################################################################### ## here we retrieve the ss-config boilerplate from our public mirrors to begin wizard ## ## in case the first mirror fails to validate our backup mirrors will be tried ## ss_rm "${TMP_SS_CONFIG_WIZARD}" ## retrieve ss-config-sample ## ss_wget "${TMP_SS_CONFIG_WIZARD}" "${GITHUB_SS_CONFIG_SAMPLE}" VALIDATE_TMP_SS_CONFIG_WIZARD=$(grep 'SS_EOF' "${TMP_SS_CONFIG_WIZARD}" 2> /dev/null) if [[ -z "${VALIDATE_TMP_SS_CONFIG_WIZARD}" ]]; then ss_wget "${TMP_SS_CONFIG_WIZARD}" "${GITLAB_SS_CONFIG_SAMPLE}" fi #################################################################################################### #### G. SS-Install: Interactive Setup Wizard (Populates SS-Config) ################################# #################################################################################################### ## this basic wizard will allow you to interactively setup your ss-config file options ## ## advanced users can setup ss-config before running ss-install to avoid this ## ## clear screen ## clear -x ## check build version ## SS_BUILD_CURRENT=$(source /tmp/ss-config-wizard; echo "${SS_BUILD}" 2> /dev/null) ## intro variables ## FIRST_LINE="${COLOR_INFO}#### ${LIGHTGRAY}Build: ${LIGHTGREEN}${SS_BUILD_CURRENT} ${COLOR_INFO}${FILLER}${COLOR_RESET}" FIRST_LINE_TRIM=${FIRST_LINE::120} SECOND_LINE="${COLOR_INFO}#### ${LIGHTGRAY}Operating System: ${LIGHTGREEN}Ubuntu ${SYSTEM_UBUNTU_VERSION} LTS ${COLOR_INFO}${FILLER}${COLOR_RESET}" SECOND_LINE_TRIM=${SECOND_LINE::120} THIRD_LINE="${COLOR_INFO}#### ${LIGHTGRAY}Hostname: ${LIGHTGREEN}${SYSTEM_HOSTNAME} ${COLOR_INFO}${FILLER}${COLOR_RESET}" THIRD_LINE_TRIM=${THIRD_LINE::120} FOURTH_LINE="${COLOR_INFO}#### ${LIGHTGRAY}Virtualization: ${LIGHTGREEN}${SYSTEM_VIRTUAL_UPPERCASE} (for best results use KVM servers) ${COLOR_INFO}${FILLER}${COLOR_RESET}" FOURTH_LINE_TRIM=${FOURTH_LINE::120} FIFTH_LINE="${COLOR_INFO}#### ${LIGHTGRAY}Disk Space: ${LIGHTGREEN}${SYSTEM_DISK_FREE_EASY} free space out of ${SYSTEM_DISK_TOTAL_EASY} total space (${SYSTEM_DISK_USED_PERCENT} currently used) ${COLOR_INFO}${FILLER}${COLOR_RESET}" FIFTH_LINE_TRIM=${FIFTH_LINE::120} INTRO_SWAPFILE="${COLOR_INFO}#### ${LIGHTGRAY}Swapfile: ${LIGHTGREEN}${SYSTEM_SWAP_TOTAL_FINAL} (will be installed if not exists) ${COLOR_INFO}${FILLER}${COLOR_RESET}" INTRO_SWAPFILE_TRIM=${INTRO_SWAPFILE::120} INTRO_MEMORY="${COLOR_INFO}#### ${LIGHTGRAY}RAM Memory (Total): ${LIGHTGREEN}${SYSTEM_RAM_TOTAL} (2GB+ best for WooCommerce and such) ${COLOR_INFO}${FILLER}${COLOR_RESET}" INTRO_MEMORY_TRIM=${INTRO_MEMORY::120} SIXTH_LINE="${COLOR_INFO}#### ${LIGHTGRAY}vCPU Cores: ${LIGHTGREEN}${SYSTEM_CPU_CORES} core(s) ${COLOR_INFO}${FILLER}${COLOR_RESET}" SIXTH_LINE_TRIM=${SIXTH_LINE::120} EIGHT_LINE="${COLOR_INFO}#### ${LIGHTGRAY}IPv4 Address: ${LIGHTGREEN}${SYSTEM_IPV4_ADDRESS} ${COLOR_INFO}${FILLER}${COLOR_RESET}" EIGHT_LINE_TRIM=${EIGHT_LINE::120} NINE_LINE="${COLOR_INFO}#### ${LIGHTGRAY}IPv6 Address: ${LIGHTGREEN}${SYSTEM_IPV6_ADDRESS} ${COLOR_INFO}${FILLER}${COLOR_RESET}" NINE_LINE_TRIM=${NINE_LINE::120} ss_echo "${COLOR_INFO}" cat << "EOF" ___ __ __ __ _____/ (_)____/ /_______/ /_____ ______/ /__ / ___/ / / ___/ //_/ ___/ __/ __ `/ ___/ //_/ (__ ) / / /__/ ,< (__ ) /_/ /_/ / /__/ ,< /____/_/_/\___/_/|_/____/\__/\__,_/\___/_/|_| EOF ss_echo "${COLOR_RESET}" ## if ss-config file not exists ## if [[ ! -f "/var/www/ss-config" ]]; then ss_echo "${COLOR_INFO}################################################################################ ${COLOR_RESET}" ss_echo "${FIRST_LINE_TRIM}" ss_echo "${SECOND_LINE_TRIM}" ss_echo "${THIRD_LINE_TRIM}" ss_echo "${FOURTH_LINE_TRIM}" ss_echo "${FIFTH_LINE_TRIM}" ss_echo "${INTRO_MEMORY_TRIM}" ss_echo "${INTRO_SWAPFILE_TRIM}" ss_echo "${SIXTH_LINE_TRIM}" ss_echo "${EIGHT_LINE_TRIM}" ss_echo "${NINE_LINE_TRIM}" ss_echo "${COLOR_INFO}################################################################################ ${COLOR_RESET}" ss_echo "" ss_echo "${COLOR_WARN}Welcome to SlickStack! It appears your /var/www/ss-config file has not been ${COLOR_RESET}" ss_echo "${COLOR_WARN}setup yet and/or this is a new installation. Before proceeding, please ensure ${COLOR_RESET}" ss_echo "${COLOR_WARN}that your domain is active in Cloudflare, with proxying and Full SSL enabled, ${COLOR_RESET}" ss_echo "${COLOR_WARN}and that your A records for @ and www are pointing to the IP address of this ${COLOR_RESET}" ss_echo "${COLOR_WARN}cloud server, along with staging/dev subdomains if you will use those features. ${COLOR_RESET}" ss_echo "${COLOR_WARN}If you are not ready to install SlickStack on your production site, you can ${COLOR_RESET}" ss_echo "${COLOR_WARN}install on a temporary subdomain for testing, and later change domain settings ${COLOR_RESET}" ss_echo "${COLOR_WARN}in your ss-config file (simply run ss-install again after changing it). ${COLOR_RESET}" ss_echo "" ss_echo "${COLOR_WARN}SlickStack installs both self-signed OpenSSL and Lets Encrypt certs, but uses ${COLOR_RESET}" ss_echo "${COLOR_WARN}the OpenSSL by default. If you are not using Cloudflare, be sure to change ${COLOR_RESET}" ss_echo "${COLOR_WARN}settings to the Lets Encrypt cert to avoid browser warnings. ${COLOR_RESET}" ss_echo "" ss_echo "${COLOR_WARN}Please use the below wizard to configure required options, or hit Ctrl+C to ${COLOR_RESET}" wait_time=30 # seconds temp_cnt=${wait_time} while [[ ${temp_cnt} -gt 0 ]]; do ss_print "${COLOR_WARN}\rexit and configure your ss-config file manually: ${LIGHTGRAY}%2d ${COLOR_RESET}" ${temp_cnt} sleep 1 ((temp_cnt--)) done ss_echo "" ss_echo "" ss_echo "${COLOR_INFO}################################################################################ ${COLOR_RESET}" ss_echo "${COLOR_INFO}#### SlickStack Interactive Setup Wizard (SS-Config) ########################### ${COLOR_RESET}" ss_echo "${COLOR_INFO}################################################################################ ${COLOR_RESET}" ss_echo "" ## replace placeholders with random strings ## ss_sed "s/@DB_PASSWORD_ROOT/pass-$(openssl rand -hex 10)/g" /tmp/ss-config-wizard ss_sed "s/@DB_PASSWORD_USER/pass-$(openssl rand -hex 10)/g" /tmp/ss-config-wizard ss_sed "s/@SFTP_PASSWORD/pass-$(openssl rand -hex 10)/g" /tmp/ss-config-wizard ss_sed "s/@GUEST_PASSWORD/pass-$(openssl rand -hex 10)/g" /tmp/ss-config-wizard ss_sed "s/@SFTP_USER/sftp-$(openssl rand -hex 3)/g" /tmp/ss-config-wizard ss_sed "s/@DB_USER/mysql-$(openssl rand -hex 3)/g" /tmp/ss-config-wizard ss_sed "s/@GUEST_USER/guest-$(openssl rand -hex 3)/g" /tmp/ss-config-wizard ## random string for Adminer URL ## ss_sed "s/@RANDOM_STRING_ADMINER_URL/$(openssl rand -hex 12)/g" /tmp/ss-config-wizard ## removing most of this soon!! ## ## replace other placeholders with default ## ss_sed "s|@SS_PILOT_FILE||g" /tmp/ss-config-wizard ## PROMPT: choose sudo username (default = random) ## sudouser_random="sudo-$(openssl rand -hex 3)" read -t 300 -p "$(ss_echo ${LIGHTGRAY}"Choose sudo username (for SSH):" ${LIGHTGREEN})" -e -i 'batman' ss_var_sudo_user || ss_var_sudo_user=${sudouser_random} ss_sed "s|@SUDO_USER|${ss_var_sudo_user}|g" /tmp/ss-config-wizard ## new line ## ss_print "${COLOR_RESET}\n" ## PROMPT: choose sudo password (default = random) ## sudopass_random=$(openssl rand -hex 12) read -t 300 -p "$(ss_echo ${LIGHTGRAY}"Choose sudo password (should be strong): "${LIGHTGREEN})" -e -i ${sudopass_random} ss_var_sudo_password || ss_var_sudo_password=${sudopass_random} ss_sed "s|@SUDO_PASSWORD|${ss_var_sudo_password}|g" /tmp/ss-config-wizard ## new line ## ss_print "${COLOR_RESET}\n" ## PROMPT: choose site TLD (otherwise example.com) ## read -t 300 -p "$(ss_echo ${LIGHTGRAY}"Choose site TLD (subdomains not allowed): "${LIGHTGREEN})" -e -i 'example.com' ss_var_site_tld || ss_var_site_tld=${SYSTEM_HOSTNAME_TLD} ss_sed "s|@SITE_TLD|${ss_var_site_tld}|g" /tmp/ss-config-wizard ## new line ## ss_print "${COLOR_RESET}\n" ## PROMPT: choose site domain (otherwise www.example.com) ## read -t 300 -p "$(ss_echo ${LIGHTGRAY}"Choose site domain (subdirectories not allowed): "${LIGHTGREEN})" -e -i 'www.example.com' ss_var_site_domain || ss_var_site_tld=www.${SYSTEM_HOSTNAME_TLD} ss_sed "s|@SITE_DOMAIN|${ss_var_site_domain}|g" /tmp/ss-config-wizard ## new line ## ss_print "${COLOR_RESET}\n" #################################################################################################### #### H. SS-Install: Activate SS-Config File Generated By Wizard #################################### #################################################################################################### ss_mkdir /var/www ss_mv "${TMP_SS_CONFIG_WIZARD}" "${PATH_SS_CONFIG}" ss_chown root:root "${PATH_SS_CONFIG}" ## must be root:root chmod 0700 "${PATH_SS_CONFIG}" ## 0700 means only root can execute #################################################################################################### #### I. SS-Install: Retrieve SS-Check ############################################################## #################################################################################################### ## now that ss-config is configured we must retrieve ss-check script to prepare for next ## ## ss-check is a critical file at this stage for both automated and manual installs ## ## retrieve ss-check ## ss_wget "${TMP_SS_CHECK}" "${GITHUB_SS_CHECK}" VALIDATE_TMP_SS_CHECK=$(grep 'SS_EOF' "${TMP_SS_CHECK}" 2> /dev/null) if [[ -z "${VALIDATE_TMP_SS_CHECK}" ]]; then ss_wget "${TMP_SS_CHECK}" "${GITLAB_SS_CHECK}" fi ## copy files to destination ## ss_mv "${TMP_SS_CHECK}" "${PATH_SS_CHECK}" ss_chown root:root /var/www/ss* ## must be root:root chmod 0700 /var/www/ss* ## 0700 means root can execute #################################################################################################### #### J SS-Install: Force Exit (Conditional) If SSH Keys Or Third-Party Cert Missing ################ #################################################################################################### ## this is a simple message that announces to the shell the purpose of this bash script ## ## it will only be noticed by sudo users who manually call ss core bash scripts ## ## force exit if SSH keys chosen ## SSHKEYS_CHOSEN=$(source /var/www/ss-config; echo ${SSH_KEYS} 2> /dev/null) if [[ "${SSHKEYS_CHOSEN}" == "true" ]] && [[ ! -f "/var/www/auth/id_rsa.pub" ]]; then ss_echo "${YELLOW}Exiting ss-install: Please upload your /var/www/auth/id_rsa.pub file before proceeding... ${COLOR_RESET}" ss_echo "${YELLOW}Alternatively SlickStack will create a new key pair for you (just run ss-install again now)... ${COLOR_RESET}" fi ## force exit if thirdparty SSL chosen ## THIRDPARTY_CHOSEN=$(source /var/www/ss-config; echo ${SSL_TYPE}) if [[ "${THIRDPARTY_CHOSEN}" == "thirdparty" ]] && [[ ! -f "/var/www/certs/thirdparty.pem" || ! -f "/var/www/certs/keys/thirdparty.key" ]]; then ss_echo "${YELLOW}Exiting ss-install: Since you chose thirdparty SSL please upload your cert/key before proceeding... ${COLOR_RESET}" fi #################################################################################################### #### K. SS-Install: Message (Last Chance To Exit + Begin Install) ################################## #################################################################################################### ## this is a simple message that announces to the shell the purpose of this bash script ## ## it will only be seen by sudo users who manually run this script in the shell ## ## echo message ## ss_echo "${COLOR_WARN}Your /var/www/ss-config file is now ready! Ctrl+C to exit now if you ${COLOR_RESET}" WAIT_TIME_LAST_CHANCE="15" # seconds WAIT_TIME_LAST_CHANCE_TMP="${WAIT_TIME_LAST_CHANCE}" while [[ ${WAIT_TIME_LAST_CHANCE_TMP} -gt 0 ]]; do ss_print "${COLOR_WARN}\rwant to review options before proceeding, otherwise wait... ${COLOR_RESET}%2d ${COLOR_RESET}" ${WAIT_TIME_LAST_CHANCE_TMP} sleep 1 ((WAIT_TIME_LAST_CHANCE_TMP--)) done ## begin install message ## ss_echo "" ss_echo "" ss_echo "${COLOR_INFO}################################################################################ ${COLOR_RESET}" ss_echo "${COLOR_INFO}#### SlickStack Automated Installation (SS-Install) ############################ ${COLOR_RESET}" ss_echo "${COLOR_INFO}################################################################################ ${COLOR_RESET}" ss_echo "" ss_echo "${COLOR_INFO}Running ss-install... ${COLOR_RESET}" #################################################################################################### #### L. SS-Install: Message (Welcome Back If SS-Config Already Exists) ############################# #################################################################################################### ## in case ss-config file already exists in the proper location we skip to installation ## ## you can run the ss-install script as many times as you want without conflicts ## else ss_echo "${COLOR_INFO}################################################################################ ${COLOR_RESET}" ss_echo "${FIRST_LINE_TRIM}" ss_echo "${SECOND_LINE_TRIM}" ss_echo "${THIRD_LINE_TRIM}" ss_echo "${FOURTH_LINE_TRIM}" ss_echo "${FIFTH_LINE_TRIM}" ss_echo "${INTRO_MEMORY_TRIM}" ss_echo "${INTRO_SWAPFILE_TRIM}" ss_echo "${SIXTH_LINE_TRIM}" ss_echo "${EIGHT_LINE_TRIM}" ss_echo "${NINE_LINE_TRIM}" ss_echo "${COLOR_INFO}################################################################################ ${COLOR_RESET}" ss_echo "" ss_echo "${COLOR_INFO}Running ss-install... ${COLOR_RESET}" fi #################################################################################################### #### M. SS-Install: Source SS-Config (After Setup Wizard Complete) ################################# #################################################################################################### ## here we must source ss-config again after the setup wizard has completed generation ## ## this is different than the conditional sourcing at the top of this script ## ## source ss-config ## source /var/www/ss-config #################################################################################################### #### N. SS-Install: Run SS-Check ################################################################### #################################################################################################### ## here we run ss-check after ss-config exists so that we can continue with installation ## ## whether or not user has exited the wizard to review ss-config it should work fine ## ## source ss-check ## source "${PATH_SS_CHECK}" #################################################################################################### ##### SS-Install: Reset Permissions (SlickStack) ################################################### #################################################################################################### ## SNIPPET: ss-check, ss-install, ss-worker, ss core cron jobs ss_mkdir /var/www ss_mkdir /var/www/auth ss_mkdir /var/www/backups ss_mkdir /var/www/backups/config ss_mkdir /var/www/backups/html ss_mkdir /var/www/backups/mysql ss_mkdir /var/www/backups/mysql/data ss_mkdir /var/www/cache ss_mkdir /var/www/cache/nginx ss_mkdir /var/www/cache/opcache ss_mkdir /var/www/cache/system ss_mkdir /var/www/certs ss_mkdir /var/www/certs/keys ss_mkdir /var/www/crons ss_mkdir /var/www/crons/custom ss_mkdir /var/www/html ss_mkdir /var/www/html/.well-known ss_mkdir /var/www/html/.well-known/acme-challenge ss_mkdir /var/www/logs ss_mkdir /var/www/meta ss_mkdir /var/www/meta/timestamps ss_mkdir /var/www/sites ss_touch /var/www/meta/.htpasswd ## if staging enabled if [[ "${STAGING_SITE}" != "false" ]]; then ss_mkdir /var/www/html/staging ss_mkdir /var/www/html/staging/.well-known ss_mkdir /var/www/html/staging/.well-known/acme-challenge fi ## if dev enabled if [[ "${DEV_SITE}" != "false" ]]; then ss_mkdir /var/www/html/dev ss_mkdir /var/www/html/dev/.well-known ss_mkdir /var/www/html/dev/.well-known/acme-challenge fi ## user/group ownership ## ss_chown root:root /var/www ## must be root:root ss_chown root:root /var/www/backups ## must be root:root ss_chown root:root /var/www/backups/config ## must be root:root ss_chown root:root /var/www/backups/mysql ## must be root:root ss_chown root:root /var/www/backups/mysql/data ## must be root:root ss_chown root:root /var/www/cache/system ## must be root:root ss_chown root:root /var/www/certs ## must be root:root ss_chown root:root /var/www/certs/keys ## must be root:root ss_chown root:root /var/www/crons ## must be root:root ss_chown root:root /var/www/crons/custom ## must be root:root #################################################################################################### #### O. SS-Install: Upgrade Ubuntu Packages + Linux Kernel ######################################### #################################################################################################### ## the main purpose of ss-update is to upgrade all currently installed Ubuntu packages ## ## we use apt full-upgrade (not apt-get) in order to upgrade the Linux kernel ## source "${PATH_SS_UPDATE_MODULES}" #################################################################################################### #### P. SS-Install: Configure Ubuntu ############################################################### #################################################################################################### ## first we need to setup all users and passwords for Ubuntu and set sudo permissions ## ## this process will also set the default SSH port and disable root logins ## ## run ss-install-ubuntu-utils ## source "${PATH_SS_INSTALL_UBUNTU_UTILS}" ## run ss-install-ubuntu-users ## source "${PATH_SS_INSTALL_UBUNTU_USERS}" ## run ss-install-ubuntu-bash ## source "${PATH_SS_INSTALL_UBUNTU_BASH}" ## run ss-install-ubuntu-ssh ## source "${PATH_SS_INSTALL_UBUNTU_SSH}" ## run ss-install-ubuntu-crontab ## source "${PATH_SS_INSTALL_UBUNTU_CRONTAB}" ## run ss-install-ubuntu-swapfile ## source "${PATH_SS_INSTALL_UBUNTU_SWAPFILE}" ## run ss-install-ubuntu-kernel ## source "${PATH_SS_INSTALL_UBUNTU_KERNEL}" #################################################################################################### #### Q. SS-Install: Install PHP-FPM (Before Nginx) ################################################# #################################################################################################### ## here we install the PHP-FPM module which includes OPcache for better performance ## ## FastCGI is configured to interface with Nginx using TCP (127.0.0.1:9000) ## ## run ss-install-php-packages ## source "${PATH_SS_INSTALL_PHP_PACKAGES}" ## run ss-install-php-config ## source "${PATH_SS_INSTALL_PHP_CONFIG}" #################################################################################################### #### R. SS-Install: Install Nginx (Includes SSL Certificates) ###################################### #################################################################################################### ## the Nginx installer includes OpenSSL and Lets Encrypt generation to avoid conflicts ## ## default settings allow for very high-traffic so CloudFlare is recommended ## ## run ss-install-nginx-packages ## source "${PATH_SS_INSTALL_NGINX_PACKAGES}" ## run ss-install-nginx-config ## source "${PATH_SS_INSTALL_NGINX_CONFIG}" #################################################################################################### #### S. SS-Install: Enable Maintenance Mode (After Nginx Installed) ################################ #################################################################################################### ## this is a nifty snippet that will put up a public maintenance page during install ## ## it helps prevent users from interacting with your website at this stage ## source "${PATH_SS_MAINTENANCE_ENABLE}" #################################################################################################### #### T. SS-Install: Install MySQL ################################################################## #################################################################################################### ## here we install MySQL server (no client) and users based on the ss-config settings ## ## root@localhost will use sockets and PHP apps will connect via 127.0.0.1 (TCP) ## ## run ss-install-mysql-packages ## source "${PATH_SS_INSTALL_MYSQL_PACKAGES}" ## run ss-install-mysql-config ## source "${PATH_SS_INSTALL_MYSQL_CONFIG}" #################################################################################################### #### U. SS-Install: Install Memcached ############################################################## #################################################################################################### ## Memcached is installed to enable object caching in WordPress (requires MU plugin) ## ## some websites may not benefit from it and can thus disable it in ss-config ## ## run ss-install-memcached-packages ## source "${PATH_SS_INSTALL_MEMCACHED_PACKAGES}" ## run ss-install-memcached-config ## source "${PATH_SS_INSTALL_MEMCACHED_CONFIG}" #################################################################################################### #### W. SS-Install: Install CMS (WordPress, PrestaShop, MediaWiki, Etc) ############################ #################################################################################################### ## this snippet fetches the latest stable version of WordPress from SlickStack mirrors ## ## major CMS releases (unpatched) are never considered stable for our purposes ## if [[ "${SS_APP}" == "wordpress" ]]; then ## run ss-install-wordpress-cli ## source "${PATH_SS_INSTALL_WORDPRESS_CLI}" ## run ss-install-wordpress-config ## source "${PATH_SS_INSTALL_WORDPRESS_CONFIG}" ## run ss-install-wordpress-packages ## source "${PATH_SS_INSTALL_WORDPRESS_PACKAGES}" ## run ss-install-wordpress-mu-plugins ## source "${PATH_SS_INSTALL_WORDPRESS_MU_PLUGINS}" fi if [[ "${SS_APP}" == "prestashop" ]]; then ## run ss-install-prestashop-packages ## source "${PATH_SS_INSTALL_PRESTASHOP_PACKAGES}" ## run ss-install-prestashop-config ## source "${PATH_SS_INSTALL_PRESTASHOP_CONFIG}" fi if [[ "${SS_APP}" == "mediawiki" ]]; then ## run ss-install-prestashop-packages ## source "${PATH_SS_INSTALL_MEDIAWIKI_PACKAGES}" ## run ss-install-prestashop-config ## source "${PATH_SS_INSTALL_MEDIAWIKI_CONFIG}" fi #################################################################################################### #### X. SS-Install: Sync Staging Site ############################################################## #################################################################################################### ## now that everything is setup and permissions fixed we sync production to staging ## ## it will only sync files/database if staging site is enabled in ss-config ## source "${PATH_SS_SYNC_STAGING}" #################################################################################################### #### Y. SS-Install: Install Rclone ################################################################# #################################################################################################### ## run ss-install-rclone-packages ## source "${PATH_SS_INSTALL_RCLONE_PACKAGES}" ## run ss-install-rclone-config ## source "${PATH_SS_INSTALL_RCLONE_CONFIG}" #################################################################################################### #### Z. SS-Install: Install UFW Firewall ########################################################### #################################################################################################### ## here we install and configure the very simple UFW Firewall that Ubuntu maintains ## ## only ports 80, 443, and your designated SSH port (22) will be allowed ## ## run ss-install-ufw-packages ## source "${PATH_SS_INSTALL_UFW_PACKAGES}" ## run ss-install-ufw-config ## source "${PATH_SS_INSTALL_UFW_CONFIG}" #################################################################################################### #### AA. SS-Install: Install Fail2ban ############################################################## #################################################################################################### ## here we install and configure the very simple UFW Firewall that Ubuntu maintains ## ## only ports 80, 443, and your designated SSH port (22) will be allowed ## ## run ss-install-fail2ban-packages ## source "${PATH_SS_INSTALL_FAIL2BAN_PACKAGES}" ## run ss-install-fail2ban-config ## # source "${PATH_SS_INSTALL_FAIL2BAN_CONFIG}" #################################################################################################### #### BB. SS-Install: Reset All Logs To NULL ######################################################## #################################################################################################### source "${PATH_SS_EMPTY_LOGS}" #################################################################################################### #### CC. SS-Install: Reset Permissions (All Permissions) ########################################### #################################################################################################### ## intuitively resets all file and user permissions across the entire SlickStack server ## ## depending on the CMS installed it will also reset those permissions as well ## source "${PATH_SS_PERMS}" #################################################################################################### #### DD. SS-Install: Disable Maintenance Mode ###################################################### #################################################################################################### ## since everything is now setup including perms and staging we disable maintenance ## ## for good measure we also purge all caches immediately after this snippet ## source "${PATH_SS_MAINTENANCE_DISABLE}" #################################################################################################### #### EE. SS-Install: Purge Caches (All Caches) ##################################################### #################################################################################################### ## this clears all caches i.e. Nginx, OPcache, Redis object cache, and WP transients ## ## we run this after ss-perms and before ss-restart-modules to avoid conflicts ## ## run ss-purge-nginx ## source "${PATH_SS_PURGE_NGINX}" ## run ss-purge-opcache ## source "${PATH_SS_PURGE_OPCACHE}" ## run ss-purge-memcached ## source "${PATH_SS_PURGE_MEMCACHED}" ## run ss-purge-transients ## source "${PATH_SS_PURGE_TRANSIENTS}" #################################################################################################### #### FF. SS-Install: Restart Modules (All Modules) ################################################# #################################################################################################### ## this script is using init.d instead of systemd shortcuts to allow for absolute paths ## ## we are looking into including other snippets here such as unmasking (etc) ## ## run ss-restart-php ## source "${PATH_SS_RESTART_PHP}" ## run ss-restart-nginx ## source "${PATH_SS_RESTART_NGINX}" ## run ss-restart-memcached ## source "${PATH_SS_RESTART_MEMCACHED}" ## run ss-restart-mysql ## source "${PATH_SS_RESTART_MYSQL}" ## run ss-restart-ufw ## source "${PATH_SS_RESTART_UFW}" #################################################################################################### #### GG. SS-Install: Validate (Repair) Crontab ##################################################### #################################################################################################### ## this is a final check to ensure the root crontab was installed properly by ss-install ## ## otherwise it will attempt to reinstall the crontab one more time here ## ## validate crontab ## VALIDATE_CRONTAB=$(ss_grep_boolean 'SS_EOF' /var/spool/cron/crontabs/root) if [[ -z "${VALIDATE_CRONTAB}" ]]; then source "${PATH_SS_INSTALL_UBUNTU_CRONTAB}" fi #################################################################################################### #### HH. SS-Install: Display SlickStack Overview ################################################### #################################################################################################### ## the shell will echo the most important ss-config settings (and beyond) currently used ## ## this allows you to easily copy/paste for your records or for your clients ## source "${PATH_SS_STACK_OVERVIEW}" #################################################################################################### #### II. SS-Install: Message (Installation Successful) ############################################# #################################################################################################### if [[ "${SSH_KEYS}" == "true" ]]; then ss_echo "" ss_echo "${COLOR_WARN}Since you enabled SSH keys be sure to add your public key to: ${PATH_SSH_AUTHORIZED_KEYS_FILE} ${COLOR_RESET}" ss_echo "${COLOR_WARN}...or simply use the default public key if you prefer (we added it already). ${COLOR_RESET}" ss_echo "" fi ## confirm installation complete ## ss_echo "" ss_echo "${COLOR_INFO}################################################################################ ${COLOR_RESET}" ss_echo "${COLOR_INFO}#### Congrats! SlickStack installation is now complete. ######################## ${COLOR_RESET}" ss_echo "${COLOR_INFO}################################################################################ ${COLOR_RESET}" ss_echo "" ss_echo "${COLOR_WARN}Please write down your sudo user/password, as the root user will no longer ${COLOR_RESET}" ss_echo "${COLOR_WARN}have SSH access for security reasons. The WP Admin user/password is the same ${COLOR_RESET}" ss_echo "${COLOR_WARN}as your SFTP login until otherwise changed by your team. Use the bash alias ${COLOR_RESET}" ss_echo "${COLOR_WARN}ss to save on keystrokes (type ss help for a full list of commands). If this ${COLOR_RESET}" ss_echo "${COLOR_WARN}is the first time you installed SlickStack on this server, type bash below ${COLOR_RESET}" ss_echo "${COLOR_WARN}and hit ENTER to reload this shell session and activate these shortcuts. ${COLOR_RESET}" ss_echo "" ss_echo "${COLOR_WARN}If you are using Cloudflare, you can also enable DNSSEC and HSTS on their ${COLOR_RESET}" ss_echo "${COLOR_WARN}platform for extra security (recommended). For an extra boost, set Cloudflare ${COLOR_RESET}" ss_echo "${COLOR_WARN}Page Rules for /wp-content/* requests to [cache all] and force an edge TTL ${COLOR_RESET}" ss_echo "${COLOR_WARN}of 1 month. You can also set the minimum TLS version to 1.2+ as well, which ${COLOR_RESET}" ss_echo "${COLOR_WARN}helps ensure top scores on auditing tools such as SSL Labs. ${COLOR_RESET}" ss_echo "" ss_echo "${COLOR_WARN}To run ss-install again, simply run sudo bash /var/www/ss-install or if you ${COLOR_RESET}" ss_echo "${COLOR_WARN}reloaded your shell session already ss install should also work. Running the ${COLOR_RESET}" ss_echo "${COLOR_WARN}installation again usually resolves most issues. ${COLOR_RESET}" ss_echo "" ss_echo "${COLOR_WARN}Lastly, be sure to reboot your server, esp. on Ubuntu 22.04, as there are ${COLOR_RESET}" ss_echo "${COLOR_WARN}known issues with the Linux kernel requiring a reboot after updating. To do ${COLOR_RESET}" ss_echo "${COLOR_WARN}this simply run sudo reboot now. Cheers! ${COLOR_RESET}" ss_echo "" ss_echo "${COLOR_INFO}Ctrl/Cmd + click to open --> ${LIGHTGREEN}https://${SITE_DOMAIN}/wp-login.php ${COLOR_RESET}" ss_echo "" #################################################################################################### #### SlickStack: Reset Permissions (SlickStack Scripts) ############################################ #################################################################################################### ## we include this permissions reset in all cron jobs and bash scripts for redundancy ## ## chmod 0700 means only the root/sudo users can execute any SlickStack scripts ## ## THIS SNIPPET DOES NOT RELY ON SS-CONFIG OR SS-FUNCTIONS ## SNIPPET: ss bash scripts, ss cron jobs ## UPDATED: 02JUL2022 chown root:root /var/www/ss* ## must be root:root chown root:root /var/www/crons/*cron* ## must be root:root chown root:root /var/www/crons/custom/*cron* ## must be root:root chmod 0700 /var/www/ss* ## 0700 means only root/sudo can execute chmod 0700 /var/www/crons/*cron* ## 0700 means only root/sudo can execute chmod 0700 /var/www/crons/custom/*cron* ## 0700 means only root/sudo can execute #################################################################################################### #### SlickStack: External References Used To Improve This Script (Thanks, Interwebz) ############### #################################################################################################### ## Ref: http://wproller.com ## ## Ref: https://github.com/bjornjohansen/deploy-wp-on-vps/blob/master/deploy.sh ## ## Ref: https://github.com/sm0k3net/Useful-Scripts/blob/master/wordpress.sh ## ## Ref: https://github.com/techandme/wordpress-vm ## ## Ref: https://github.com/QROkes/webinoly ## ## Ref: https://github.com/WordOps/WordOps ## ## Ref: https://www.isicca.com/en/lemp-howto-install-nginx-php7-mariadb/ ## ## Ref: https://gist.github.com/FeChagas/54b0cdf354b197dc8e417357d7687e8b ## ## Ref: https://github.com/GeekPress/WP-Quick-Install ## ## Ref: https://github.com/bajpangosh/High-Traffic-wordpress-server-configuration ## ## Ref: https://gist.github.com/nickfox-taterli/2c283d73ba817392fb0f9f15d9cfa514 ## ## Ref: https://gist.github.com/beardedinbinary/79d7ad34f9980f0a4c23 ## ## Ref: https://www.linuxbabe.com/security/letsencrypt-webroot-tls-certificate ## Ref: https://stackoverflow.com/questions/49668542/create-a-script-that-adds-lines-of-code-to-bashrc-then-reloads-the-terminal ## Ref: https://peteris.rocks/blog/unattended-installation-of-wordpress-on-ubuntu-server/ ## Ref: https://serverfault.com/questions/783527/non-interactive-silent-install-of-mysql-5-7-on-ubuntu-16-04-lts/830352#830352 ## Ref: https://www.percona.com/blog/2016/10/18/upgrading-to-mysql-5-7-beware-of-the-new-strict-mode/ ## Ref: https://stackoverflow.com/questions/3601515/how-to-check-if-a-variable-is-set-in-bash ## Ref: https://serverfault.com/questions/773964/calculating-the-percentage-of-the-total-available-memory-on-linux-as-an-integer ## Ref: https://stackoverflow.com/questions/29271593/bash-check-for-amount-of-memory-installed-on-a-system-as-sanity-check ## Ref: https://stackoverflow.com/questions/50177216/how-to-grant-all-privileges-to-root-user-in-mysql-8-0 ## Ref: https://stackoverflow.com/questions/28118296/bash-script-is-super-slow ## Ref: https://stackoverflow.com/questions/15445361/speeding-up-bash-scripts ## Ref: https://unix.stackexchange.com/questions/67057/bash-script-optimization-of-processing-speed ## Ref: https://unix.stackexchange.com/questions/313256/why-write-an-entire-bash-script-in-functions ## Ref: http://nginx.org/en/linux_packages.html ## Ref: https://www.digitalocean.com/community/questions/nginx-stable-or-mainline-for-production-server ## Ref: https://precisionsec.com/changing-the-wordpress-site-url-using-the-mysql-command-line/ ## Ref: https://magc.co/box/notes/change-wp-urls-mysql/ ## Ref: https://wordpress.stackexchange.com/questions/281814/wordpress-multisite-redirecting-to-wp-signup-php ## Ref: https://wordpress.stackexchange.com/questions/165507/site-redirecting-to-wp-signup-php ## Ref: https://askubuntu.com/questions/86849/how-to-unzip-a-zip-file-from-the-terminal ## Ref: https://www.computerhope.com/unix/rsync.htm ## Ref: https://lowendbox.com/blog/wordpress-cheap-vps-lowendscript/ ## Ref: https://unix.stackexchange.com/questions/67057/bash-script-optimization-of-processing-speed ## Ref: http://www.los-gatos.ca.us/davidbu/faster_sh.html ## Ref: https://blog.eduonix.com/shell-scripting/learn-how-to-write-interactive-shell-scripts/ ## Ref: https://www.stefanjudis.com/today-i-learned/how-to-add-interactive-questions-to-bash-scripts/ ## Ref: https://askubuntu.com/questions/998640/bash-interactive-script ## Ref: https://ryanstutorials.net/bash-scripting-tutorial/bash-input.php ## Ref: http://www.linfo.org/clear.html ## Ref: https://gist.github.com/jonsuh/3c89c004888dfc7352be ## Ref: https://stackoverflow.com/questions/2924697/how-does-one-output-bold-text-in-bash/2924755 ## Ref: https://medium.com/@jasonrigden/cowsay-is-the-most-important-unix-like-command-ever-35abdbc22b7f ## Ref: https://stackoverflow.com/questions/37052899/what-is-the-preferred-method-to-echo-a-blank-line-in-a-shell-script ## Ref: https://tldp.org/LDP/abs/html/options.html ## Ref: https://fernandobasso.dev/shell/shell-script-input-default-values.html ## Ref: https://stackoverflow.com/questions/10735574/include-source-script-if-it-exists-in-bash ## Ref: https://scripter.co/count-down-timer-in-shell/ ## Ref: https://stackoverflow.com/questions/4332478/read-the-current-text-color-in-a-xterm/4332530#4332530 ## Ref: https://stackoverflow.com/questions/24998434/read-command-display-the-prompt-in-color-or-enable-interpretation-of-backslas ## Ref: https://stackoverflow.com/questions/714915/using-the-passwd-command-from-within-a-shell-script/715802#comment52196688_19745733 ## Ref: https://askubuntu.com/questions/1214103/how-to-automate-changing-old-password ## Ref: https://unix.stackexchange.com/questions/223965/i-cant-change-users-passwd-on-ubuntu ## Ref: https://www.tecmint.com/fix-passwd-authentication-token-manipulation-error-in-linux/ ## Ref: https://stackoverflow.com/questions/4332478/read-the-current-text-color-in-a-xterm/4332530#4332530 ## Ref: https://medium.com/@smohajer85/bash-scripting-tutorial-part-11-8ce0c17b01c1 ## Ref: https://linuxhint.com/tput-printf-and-shell-expansions-how-to-create-awesome-outputs-with-bash-scripts/ ## Ref: https://stackoverflow.com/questions/8467424/echo-newline-in-bash-prints-literal-n ## Ref: https://askubuntu.com/questions/420784/what-do-the-disabled-login-and-gecos-options-of-adduser-command-stand ## Ref: https://stackoverflow.com/questions/55822739/does-echo-userpass-usr-sbin-chpasswd-override-the-root-password ## Ref: https://stackoverflow.com/questions/8110530/check-free-disk-space-for-current-partition-in-bash ## Ref: https://unix.stackexchange.com/questions/14961/how-to-find-out-which-interface-am-i-using-for-connecting-to-the-internet ## Ref: https://unix.stackexchange.com/questions/297139/sourcing-a-file-multiple-times-in-a-bash-script ## Ref: https://stackoverflow.com/questions/23513045/how-to-check-if-a-process-is-running-inside-docker-container ## Ref: https://stackoverflow.com/questions/20010199/how-to-determine-if-a-process-runs-inside-lxc-docker ## Ref: https://unix.stackexchange.com/questions/343942/shell-check-if-docker-container-is-existing ## Ref: https://stackoverflow.com/questions/20406134/read-a-bash-variable-assignment-from-other-file ## Ref: https://unix.stackexchange.com/questions/311758/remove-specific-word-in-variable ## Ref: https://stackoverflow.com/questions/13210880/replace-one-substring-for-another-string-in-shell-script ## Ref: https://stackoverflow.com/questions/11953185/counting-the-number-of-dots-in-a-string ## Ref: https://stackoverflow.com/questions/21157435/how-can-i-compare-a-string-to-multiple-correct-values-in-bash ## Ref: https://stackoverflow.com/questions/4792434/redis-on-web-server-front-end-or-database-server-back-end ## Ref: https://blog.danslimmon.com/2019/07/15/do-nothing-scripting-the-key-to-gradual-automation/ ## Ref: https://unix.stackexchange.com/questions/148761/how-do-i-suppress-stderr-warning-messages-from-a-command-inside-command-substitu ## Ref: https://unix.stackexchange.com/questions/510614/how-can-i-store-output-in-bash-variable-and-suppress-output-to-stderr-and-stdout ## Ref: https://patorjk.com/software/taag/#p=display&f=Slant&t=slickstack ## Ref: https://stackoverflow.com/questions/25214084/cant-get-ascii-art-to-echo-to-console/25214148 ## Ref: https://superuser.com/questions/315386/how-do-i-clear-my-bash-screen-while-maintaining-scrollback ## SS_EOF