Skip to content

get.configserver.dev

The subdomain get.configserver.dev provides a simple online service for downloading the latest version of CSF using a Bash script.

By default, running the script downloads the latest CSF release to the current directory. Optional arguments allow you to extend its functionality, including automatically extracting the archive and installing CSF immediately after download.

.zip vs .tgz format

Our documentation frequently mentions both .zip and .tgz releases of CSF.

When we initially developed addons for CSF, we pushed all of our releases in a .zip archive.

However, after taking over full development of CSF, we opted to migrate back to the .tgz format to keep conformity with how the original developer packaged releases. This is why our scripts mention both extensions, and why our scripts look for both.


Usage

This section explains how the get.sh script can be utilized when obtaining the latest version of CSF from our servers.

Examples

Command Description
bash <(wget -qO - https://get.configserver.dev) Download CSF w/ filename csf.zip or csf.tgz
bash <(wget -qO - https://get.configserver.dev) --preserve-name Download CSF w/ filename csf-firewall-vXX.XX.zip or csf-firewall-vXX.XX.tgz
bash <(wget -qO - https://get.configserver.dev) --extract Download CSF w/ filename csf.zip or csf.tgz, extract to csf
bash <(wget -qO - https://get.configserver.dev) --extract --folder csftest Download CSF w/ filename csf.zip or csf.tgz, extract to csftest
bash <(wget -qO - https://get.configserver.dev) --install Download CSF w/ filename csf.zip or csf.tgz, extract to csf, install CSF
bash <(wget -qO - https://get.configserver.dev) --install --folder csftest Download CSF w/ filename csf.zip or csf.tgz, extract to csftest, install CSF
bash <(wget -qO - https://get.configserver.dev) --install --dryrun Download CSF w/ filename csf.zip or csf.tgz, extract to csf, simulate install CSF
bash <(wget -qO - https://get.configserver.dev) --install --folder csftest --dryrun Download CSF w/ filename csf.zip or csf.tgz, extract to csftest, simulate install CSF
bash <(wget -qO - https://get.configserver.dev) --install-only No download, install existing local folder csf
bash <(wget -qO - https://get.configserver.dev) --install-only --folder csftest No download, install existing local folder csftest
bash <(wget -qO - https://get.configserver.dev) --install-only --dryrun No download, simulate install existing local folder csf
bash <(wget -qO - https://get.configserver.dev) --install-only --folder csftest --dryrun No download, simulate install existing local folder csftest
bash <(wget -qO - https://get.configserver.dev) --clean Delete existing csf.zip or csf.tgz, remove folder csf
bash <(wget -qO - https://get.configserver.dev) --clean --folder csftest Delete existing csf.zip or csf.tgz, remove folder csftest


Standard

The command below will download the latest version of CSF and place the archive file on your machine in the folder where you ran the command. The archive file will either be csf.zip or csf.tgz, depending on which release is available.

bash <(wget -qO - https://get.configserver.dev)
bash <(curl -sL https://get.configserver.dev)



Advanced

The get.sh script has additional arguments that you can pass which expands on its functionality.


Download Only

To download the latest version of CSF and do nothing else; pass no arguments.

bash <(wget -qO - https://get.configserver.dev)
bash <(curl -sL https://get.configserver.dev)




Download + Extract

Downloads the latest version of CSF to your local machine as the file csf.zip or csf.tgz and extracts to csf

bash <(wget -qO - https://get.configserver.dev) --extract
bash <(curl -sL https://get.configserver.dev)  --extract


Out of box, this script extracts CSF to the folder csf; you can change the default extraction folder with:

bash <(wget -qO - https://get.configserver.dev) --extract --folder csf-folder




Download + Extract + Install

Downloads the latest version of CSF to your local machine as the file csf.zip or csf.tgz, extracts to csf, and installs by running csf/install.sh

bash <(wget -qO - https://get.configserver.dev) --install
bash <(curl -sL https://get.configserver.dev)  --install


Out of box, this script extracts CSF to the folder csf, and then installs by running the file csf/install.sh. You can change the default folder with:

bash <(wget -qO - https://get.configserver.dev) --install --folder csf-folder




Download + Extract + Install (Dryrun)

Downloads the latest version of CSF to your local machine as the file csf.zip or csf.tgz, extracts to csf, and does a dry-run install without actually installing anything

bash <(wget -qO - https://get.configserver.dev) --install --dryrun
bash <(curl -sL https://get.configserver.dev)  --install --dryrun


Out of box, this script extracts CSF to the folder csf, and then installs by running the file csf/install.sh. You can change the default folder with:

bash <(wget -qO - https://get.configserver.dev) --install --folder csf-folder --dryrun




Install Local Folder

Does not download or extract CSF. Installs an existing local copy of CSF contained within the folder csf. This will error if you attempt to pass this argument and the file csf/install.sh does not exist.

bash <(wget -qO - https://get.configserver.dev) --install-only
bash <(curl -sL https://get.configserver.dev)  --install-only


Out of box, this script looks for the install file csf/install.sh; you can change the folder with the command below. You must have the file csf-folder/install.sh:

bash <(wget -qO - https://get.configserver.dev) --install-only --folder csf-folder




Install Local Folder (Dryrun)

Does a dry-run installs on an existing local copy of CSF contained within the folder csf, but does not actually install CSF. This will error if you attempt to pass this argument and the file csf/install.sh does not exist.

bash <(wget -qO - https://get.configserver.dev) --install-only --dryrun
bash <(curl -sL https://get.configserver.dev)  --install-only --dryrun


Out of box, this script looks for the install file csf/install.sh; you can change the folder with the command below. You must have the path csf-folder/install.sh:

bash <(wget -qO - https://get.configserver.dev) --install-only --folder csf-folder --dryrun




Clean

Removes any existing .zip and .tgz files, removes local csf folders.

bash <(wget -qO - https://get.configserver.dev) --clean
bash <(curl -sL https://get.configserver.dev)  --clean




Preserve Preserve Filename

Out of box, the get.sh script finds the latest version of CSF. When it downloads the archive .zip or .tgz to your machine, it automatically re-names the archive file csf.xxx.

You can skip the re-name to csf.zip/tgz and preseve the original release's archive name, which is typically csf-firewall-vXX.XX.zip or csf-firewall-vXX.XX.tgz.

bash <(wget -qO - https://get.configserver.dev) --preserve-name
bash <(curl -sL https://get.configserver.dev)  --preserve-name


We have provided examples of what each command does:

Running this command will download the latest CSF release, and name the archive file csf.zip or csf.tgz.

bash <(wget -qO - https://get.configserver.dev)

Running this command will download the latest CSF release, and name the archive file csf-firewall-vXX.XX.zip or csf-firewall-vXX.XX.tgz.

bash <(wget -qO - https://get.configserver.dev)  --preserve-name




Arguments

The get.sh script includes numerous arguments that can be passed to expand the functionality. The available arguments are listed below.


Extract

15.10 .sh get.sh -e, --extract

Downloads the latest version of CSF, saves it to your machine as csf.zip or csf.tgz, extracts it to a local folder.



Install

15.10 .sh get.sh -i, --install

Downloads the latest version of CSF, saves it to your machine as csf.zip or csf.tgz, extracts it to a local folder., and then run the CSF install.sh installation wizard.



Install Only

15.10 .sh get.sh -I, --install-only

Requires an existing local extracted version of CSF which resides in a folder (defaults to csf). Default folder can be changed with -f, --folder



Folder

15.10 .sh get.sh -f, --folder

Allows you to override the default extraction and installation folder csf. Can be used in combination with:



Preserve Original Filename

15.10 .sh get.sh -p, --preserve-name

When downloading the latest version of CSF, the script automatically re-names the latest release archive file from csf-firewall-vXX.XX.zip to csf.zip. Passing this parameter skips the re-name, and downloads the file to your system as csf-firewall-vXX.XX.zip.



Dryrun

15.10 .sh get.sh -D, --dryrun

When --install or --install-only are passed, this arguments simulations installation, but does not actually install CSF to your system.



Clean

15.10 .sh get.sh -c, --clean

Removes any csf.zip or csf.tgz files lintering within the folder. Also removes any extracted csf files and folders.



Help

15.10 .sh get.sh -h, --help

Shows the help menu for the get.sh script. Performs no other actions.



Version

15.10 .sh get.sh -v, --version

Shows the current version of the get.sh script being used.




Source Code

The source code for get.configserver.dev can be found within the official CSF repository below:

get.sh
#!/bin/sh

# #
#   @app                ConfigServer Firewall & Security (CSF)
#                       Login Failure Daemon (LFD)
#   @service            get.configserver.dev
#   @script             Bash › Script › Installation
#   @desc               installation script for csf
#   @website            https://configserver.dev
#   @docs               https://docs.configserver.dev
#   @download           https://download.configserver.dev
#   @repo               https://github.com/Aetherinox/csf-firewall
#   @copyright          Copyright (C) 2025-2026 Aetherinox
#   @license            GPLv3
#   @updated            09.28.2025
#
#   This program is free software; you can redistribute it and/or modify
#   it under the terms of the GNU General Public License as published by
#   the Free Software Foundation; either version 3 of the License, or (at
#   your option) any later version.
#
#   This program is distributed in the hope that it will be useful, but
#   WITHOUT ANY WARRANTY; without even the implied warranty of
#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
#   General Public License for more details.
#
#   You should have received a copy of the GNU General Public License
#   along with this program; if not, see <https://www.gnu.org/licenses>.
# #

# #
#   @usage              Download Only                               sh get.sh
#                       Download Only (Maintain original filename)  sh get.sh --preserve-name
#                       Download + Extract                          sh get.sh --extract
#                       Download + Extract Custom Dir               sh get.sh --extract --folder csftemp
#                       Download + Extract + Install                sh get.sh --install
#                       Download + Extract + Install Custom Dir     sh get.sh --install --folder csftemp
#                       Download + Install (Dryrun)                 sh get.sh --install --dryrun
#                       Install Only Existing Archive               sh get.sh --install-only
#                       Install Only Existing Archive (Dryrun)      sh get.sh --install-only --dryrun
#                       Clean existing archive + folder             sh get.sh --clean
#                       Help menu                                   sh get.sh --help
#                       Version information                         sh get.sh --version
#   
#   @notes              --install                                   automatically extracts
#                       --dryrun                                    passed to csf install.sh script when used
#                       --install-only                              requires existing .tar/.zip; 
#                                                                   will not download new from github.
#                       --clean                                     removes .tar/.zip and csf folder
# #

# #
#   define › colors
# #

esc=$(printf '\033')
end="${esc}[0m"
bold="${esc}[1m"
dim="${esc}[2m"
underline="${esc}[4m"
blink="${esc}[5m"
white="${esc}[97m"
black="${esc}[0;30m"
redl="${esc}[0;91m"
redd="${esc}[38;5;196m"
magental="${esc}[0;95m"
magentad="${esc}[0;35m"
fuchsial="${esc}[38;5;205m"
fuchsiad="${esc}[38;5;198m"
bluel="${esc}[38;5;75m"
blued="${esc}[38;5;33m"
greenl="${esc}[38;5;76m"
greend="${esc}[38;5;2m"
orangel="${esc}[0;93m"
oranged="${esc}[38;5;202m"
yellowl="${esc}[38;5;190m"
yellowd="${esc}[38;5;184m"
greyl="${esc}[38;5;250m"
greym="${esc}[38;5;244m"
greyd="${esc}[0;90m"
navy="${esc}[38;5;62m"
olive="${esc}[38;5;144m"
peach="${esc}[38;5;210m"

# #
#   define › general
# #

app_title="ConfigServer Firewall & Security"
app_about="Bash utility to download the latest version of ConfigServer Firewall from the official github repository."
app_repo_branch="main"
app_ver=1.0.0
app_repo="Aetherinox/csf-firewall"
github_url="https://github.com/$app_repo"
api_url="https://api.github.com/repos/$app_repo/releases/latest"
file_release="csf-firewall-v"
file_installer="install.sh"
folder_extract="csf"

# #
#   define › args
# #

argExtract="false"
argInstall="false"
argInstallOnly="false"
argDryrun="false"
argInstaller=""
argDev="false"
argStatus="downloaded"
argOriginalName="false"
argFolder="$folder_extract"

# #
#   define › files
# #

app_file_this=$(basename "$0")          #  get.sh (with ext)
app_file_bin="${app_file_this%.*}"      #  get (without ext)

# #
#   define › folders
# #

app_dir=$(dirname -- "$0")
app_dir=$(cd "$app_dir" && pwd)
app_dir_this_dir=$PWD

# #
#   https://man7.org/linux/man-pages/man1/date.1.html
#   
#   Thu, 01 May 2025 14:33:00 +0200
#   
#   %a      locale's abbreviated weekday name (e.g., Sun)
#   %d      day of month (e.g., 01)
#   %b      locale's abbreviated month name (e.g., Jan)
#   %Y      year
#   %H      hour (00..23)
#   %M      minute (00..59)
#   %S      second (00..60)
# #

date_now=$(date -u '+%a, %d %b %Y %H:%M:%S')
date_stamp=$(date -u '+%m/%d/%Y %H:%M')

# #
#   func › usage menu
# #

opt_usage()
{
    echo
    printf "  ${bluel}${app_title}${end}\n" 1>&2
    printf "  ${greym}${app_about}${end}\n" 1>&2
    printf "  ${greyd}version:${end} ${greyd}$app_ver${end}\n" 1>&2
    printf "  ${fuchsiad}$app_file_this${end} ${greyd}[${greym}--help${greyd}]${greyd}  |  ${greyd}[${greym}--version${greyd}]${greyd}  |  ${greyd}[${greym}--clean${greyd}]${greyd}  |  ${greyd}[${greym}--extract${greyd}${end} ${greyd}[${greym}--install${greyd}] ${end}${greyd}[${greym}--dryrun${greyd}]]${greyd}  |  ${greyd}[${greym}--install-only${greyd} ${greyd}[${greym}--dryrun${greyd}]]${greyd}  |  ${greyd}[${greym}--install${greyd} ${greyd}[${greym}--dryrun${greyd}]]${end}" 1>&2
    echo
    echo
    printf '  %-5s %-40s\n' "${greyd}Syntax:${end}" "" 1>&2
    printf '  %-5s %-30s %-40s\n' "    " "${greyd}Command${end}           " "${fuchsiad}$app_file_this${greyd} [ ${greym}-option ${greyd}[ ${yellowd}arg${greyd} ]${greyd} ]${end}" 1>&2
    printf '  %-5s %-30s %-40s\n' "    " "${greyd}Options${end}           " "${fuchsiad}$app_file_this${greyd} [ ${greym}-h${greyd} | ${greym}--help${greyd} ]${end}" 1>&2
    printf '  %-5s %-30s %-40s\n' "    " "    ${greym}-A${end}            " " ${white}required" 1>&2
    printf '  %-5s %-30s %-40s\n' "    " "    ${greym}-A...${end}         " " ${white}required; multiple can be specified" 1>&2
    printf '  %-5s %-30s %-40s\n' "    " "    ${greym}[ -A ]${end}        " " ${white}optional" 1>&2
    printf '  %-5s %-30s %-40s\n' "    " "    ${greym}[ -A... ]${end}     " " ${white}optional; multiple can be specified" 1>&2
    printf '  %-5s %-30s %-40s\n' "    " "    ${greym}{ -A | -B }${end}   " " ${white}one or the other; do not use both" 1>&2
    printf '  %-5s %-30s %-40s\n' "    " "${greyd}Arguments${end}         " "${fuchsiad}$app_file_this${end} ${greyd}[ ${greym}-d${yellowd} arg${greyd} | ${greym}--name ${yellowd}arg${greyd} ]${end}${yellowd} arg${end}" 1>&2
    printf '  %-5s %-30s %-40s\n' "    " "${greyd}Examples${end}          " "${fuchsiad}$app_file_this${end} ${end}" 1>&2
    printf '  %-5s %-30s %-40s\n' "    " "${greyd}${end}                  " "${fuchsiad}$app_file_this${end} ${greym}--install${yellowd} ${end}" 1>&2
    printf '  %-5s %-30s %-40s\n' "    " "${greyd}${end}                  " "${fuchsiad}$app_file_this${end} ${greym}--extract${yellowd} ${greym}--install${yellowd} ${end}" 1>&2
    printf '  %-5s %-30s %-40s\n' "    " "${greyd}${end}                  " "${fuchsiad}$app_file_this${end} ${greym}--extract${yellowd} ${greym}--install${yellowd} ${greym}--dryrun${yellowd} ${end}" 1>&2
    printf '  %-5s %-30s %-40s\n' "    " "${greyd}${end}                  " "${fuchsiad}$app_file_this${end} ${greym}--install${yellowd} ${greym}--dryrun${yellowd} ${end}" 1>&2
    printf '  %-5s %-30s %-40s\n' "    " "${greyd}${end}                  " "${fuchsiad}$app_file_this${end} ${greym}--install-only${yellowd} ${end}" 1>&2
    printf '  %-5s %-30s %-40s\n' "    " "${greyd}${end}                  " "${fuchsiad}$app_file_this${end} ${greym}--install-only${yellowd} ${greym}--dryrun${yellowd} ${end}" 1>&2
    printf '  %-5s %-30s %-40s\n' "    " "${greyd}${end}                  " "${fuchsiad}$app_file_this${end} ${greyd}[ ${greym}--help${greyd} | ${greym}-h${greyd} | ${greym}/?${greyd} ]${end}" 1>&2
    echo
    printf '  %-5s %-40s\n' "${greyd}Options:${end}" "" 1>&2
    printf '  %-5s %-81s %-40s\n' "    " "${blued}-e${greyd},${blued}  --extract ${yellowd}${end}                    " "download, extract latest version of csf ${navy}<default> ${peach}$argExtract ${end}" 1>&2
    printf '  %-5s %-81s %-40s\n' "    " "${blued}-i${greyd},${blued}  --install ${yellowd}${end}                    " "download, extract, and install latest version of csf ${end} ${navy}<default> ${peach}$argInstall ${end}" 1>&2
    printf '  %-5s %-81s %-40s\n' "    " "${blued}-I${greyd},${blued}  --install-only ${yellowd}${end}               " "no download, no extract, installs csf from existing folder ${navy}<default> ${peach}$argInstallOnly ${end}" 1>&2
    printf '  %-5s %-81s %-40s\n' "    " "${blued}-p${greyd},${blued}  --preserve-name ${yellowd}${end}              " "preserves original filename, skips rename to csf.zip ${navy}<default> ${peach}$argOriginalName ${end}" 1>&2
    printf '  %-5s %-81s %-40s\n' "    " "${blued}-f${greyd},${blued}  --folder ${yellowd}<string>${end}             " "override default folder where csf is extracted ${navy}<default> ${peach}$argFolder ${end}" 1>&2
    printf '  %-5s %-81s %-40s\n' "    " "${blued}-c${greyd},${blued}  --clean ${yellowd}${end}                      " "cleans up lingering archive and tmp folders and exits ${end}" 1>&2
    printf '  %-5s %-81s %-40s\n' "    " "${blued}-D${greyd},${blued}  --dryrun ${yellowd}${end}                     " "pass dryrun to csf installer script, does not install csf ${end} ${navy}<default> ${peach}$argDryrun ${end}" 1>&2
    printf '  %-5s %-81s %-40s\n' "    " "${blued}-V${greyd},${blued}  --version ${yellowd}${end}                    " "current version of this utilty ${end}" 1>&2
    printf '  %-5s %-81s %-40s\n' "    " "${blued}-d${greyd},${blued}  --dev ${yellowd}${end}                        " "developer mode; verbose logging ${end}" 1>&2
    printf '  %-5s %-81s %-40s\n' "    " "${blued}-h${greyd},${blued}  --help ${yellowd}${end}                       " "show this help menu ${end}" 1>&2
    echo
    echo
}

# #
#   args › handle
# #

while [ "$#" -gt 0 ]; do
    case "$1" in
        -d|--dev)
            argDev="true"
            ;;
        -e|--extract)
            argExtract="true"
            argStatus="extracted"
            ;;
        -i|--install)
            argExtract="true"
            argInstall="true"
            argStatus="installed"
            ;;
        -f|--folder|--install-folder)
            case "$1" in
                *=*) argFolder="${1#*=}" ;;
                *) shift; argFolder="$1" ;;
            esac
            ;;
        -I|--installOnly|--install-only|--install-local)
            argInstallOnly="true"
            argStatus="installed local"
            ;;
        -c|--clean)
            printf '%-31s %-65s\n' "  ${bluel} STATUS ${end}" \
                "${greym} cleaning existing files and folders ${end}"

            rm -rf "./$argFolder" "./$file_release"*.zip "./$file_release"*-tgz

            # #
            #   Verify cleanup / deletion
            # #

            if [ ! -d "./$argFolder" ] && [ ! -e "./$file_release"*.zip ] && [ ! -e "./$file_release"*-tgz ]; then
                printf '%-31s %-65s\n' "  ${greenl} SUCCESS ${end}" \
                    "${greym} all files and folders removed ${end}"
            else
                printf '%-31s %-65s\n' "  ${redd} ERROR ${end}" \
                    "${greym} some files or folders could not be removed ${end}"
            fi

            exit 0
            ;;
        -D|--dryrun)
            if [ -n "$argInstaller" ]; then
                argInstaller="$argInstaller --dryrun"
            else
                argInstaller="--dryrun"
            fi
            ;;
        -o|-p|--original-name|--preserve-name|--preserve-filename)
            argOriginalName="true"
            ;;
        -v|--version|/v)
            echo
            printf "  ${bluel}${app_title} (v$app_ver) ${end}\n" 1>&2
            printf "  ${end}${app_about} ${end}\n" 1>&2
            printf "  ${greyd}${github_url} ${end}\n" 1>&2
            echo
            exit 1
            ;;
        -h|--help|/?)
            opt_usage
            return
            ;;
        *)
            printf '%-28s %-65s\n' "  ${redl} ERROR ${end}" "${greym} Unknown parameter:${redl} $1 ${greym}. Aborting ${end}"
            exit 1
            ;;
    esac
    shift
done

# #
#   output › header
# #

echo
echo " ${greyd}―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― ${end}"
printf '%-32s %-65s\n' "  ${greym} App${end}" "${fuchsial} $app_title › Downloader  ${end}"
printf '%-32s %-65s\n' "  ${greym} Repository${end}" "${fuchsial} ${app_repo}  ${end}"
printf '%-32s %-65s\n' "  ${greym} Api${end}" "${fuchsial} ${api_url}  ${end}"
printf '%-32s %-65s\n' "  ${greym} Version${end}" "${fuchsial} v${app_ver}  ${end}"
echo " ${greyd}―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― ${end}"
echo

# #
#   api url › missing
# #

if [ -z "$api_url" ]; then
    printf '%-28s %-65s\n' "  ${redl} ERROR ${end}" "${greym} api_url empty, cannot retrieve from api.github.com. Aborting ${end}"
    exit 1
fi

# #
#   get json information from latest releases
# #

printf '%-31s %-65s\n' "  ${bluel} STATUS ${end}" "${greym} fetching latest release info from${bluel} $api_url ${end}"
release_json=$(curl -sL "$api_url")

# #
#   extract latest tag
# #

tag_latest=$(echo "$release_json" | grep -m1 '"tag_name"' | awk -F'"' '{print $4}')
if [ -z "$tag_latest" ]; then
    printf '%-28s %-65s\n' "  ${redl} ERROR ${end}" "${greym} could not find latest release tag. Aborting ${end}"
    exit 1
else
    printf '%-31s %-65s\n' "  ${greenl} OK ${end}" "${greym} found latest release tag${greenl} $tag_latest ${end}"
fi

# #
#   extract download URL for latest release, detect zip or tgz
# #

DOWNLOAD_URL=$(echo "$release_json" \
    | grep '"browser_download_url"' \
    | awk -F'"' '{print $4}' \
    | grep "$file_release$tag_latest" \
    | grep -E '\.zip$|\.tgz$|\.tar\.gz$|-tgz$' \
    | grep -vE 'helpers|theme' \
    | head -n1)

if [ -z "$DOWNLOAD_URL" ]; then
    printf '%-28s %-65s\n' "  ${redl} ERROR ${end}" "${greym} could not find download url for latest release tag (zip or tgz). Aborting ${end}"
    exit 1
fi

# #
#   get latest release filename from URL
# #

file_name_orig=$(basename "$DOWNLOAD_URL")
file_name_out="$file_name_orig"

# #
#   normalize filename to csf.zip / csf.tgz unless --original-name provided
# #

if [ "$argOriginalName" = "false" ]; then
    case "$file_name_orig" in
        *.zip)
            file_name_out="csf.zip"
            ;;
        *.tar.gz|*.tgz|*-tgz)
            file_name_out="csf.tgz"
            ;;
        *)
            file_name_out="$file_name_orig"
            ;;
    esac
else
    file_name_out="$file_name_orig"
fi

# #
#   download latest release unless --install-only
# #

if [ "$argInstallOnly" = "false" ]; then
    printf '%-31s %-65s\n' "  ${bluel} STATUS ${end}" "${greym} downloading file${bluel} $file_name_out ${greym}from${bluel} $DOWNLOAD_URL ${end}"
    echo 
    curl -L -o "$file_name_out" "$DOWNLOAD_URL"
    echo 
fi

# #
#   check if new release file downloaded / exists
# #

if [ -f "$file_name_out" ]; then
    printf '%-31s %-65s\n' "  ${greenl} OK ${end}" "${greym} file${bluel} $file_name_out ${greym}downloaded successfully. ${end}"
else
    printf '%-28s %-65s\n' "  ${redl} ERROR ${end}" "${greym} archive file${bluel} $file_name_out ${greym}missing or not downloaded. Please check the URL or your connection. Aborting ${end}"
    exit 1
fi

# #
#   extract archive if -e, --extract arg specified
# #

if [ "$argExtract" = "true" ] || [ "$argInstall" = "true" ]; then
    printf '%-31s %-65s\n' "  ${bluel} STATUS ${end}" "${greym} extracting file${bluel} $file_name_out ${end}"
    [ ! -d $argFolder ] && mkdir $argFolder

    case "$file_name_out" in
        *.zip)
            unzip -oq "$file_name_out" -d "$argFolder"
            ;;
        *.tar.gz|*.tgz)
            tar -xzf "$file_name_out" -C "$argFolder"
            ;;
        *)
            printf '%-28s %-65s\n' "  ${redl} ERROR ${end}" "${greym} unknown archive format for file${redl} $file_name_out ${greym}. Aborting ${end}"
            exit 1
            ;;
    esac

    printf '%-31s %-65s\n' "  ${greenl} OK ${end}" "${greym} extracted to ${greenl}./$argFolder/ ${end}"
fi

# #
#   install
# #

if [ "$argInstall" = "true" ] || [ "$argInstallOnly" = "true" ]; then
    path_installer="./$argFolder/$file_installer"
    if [ ! -f "$path_installer" ]; then
        printf '%-28s %-65s\n' "  ${redl} ERROR ${end}" "${greym} install script not found at${redl} $path_installer ${greym}. Aborting ${end}"
        exit 1
    fi

    printf '%-31s %-65s\n' "  ${bluel} STATUS ${end}" "${greym} running install script${bluel} $path_installer ${greym}with elevated permissions ${end}"

    #  sudo check
    if command -v sudo >/dev/null 2>&1; then
        sudo sh "$path_installer" $argInstaller
    else
        sh "$path_installer" $argInstaller
    fi

    printf '%-31s %-65s\n' "  ${greenl} OK ${end}" "${greym} installation script ${greenl} $path_installer ${greym}finished with args${greenl} $argInstaller ${end}"
fi

# #
#   output › footer
# #

printf '%-31s %-65s\n' "  ${greenl} OK ${end}" "${greym} successfully $argStatus $app_title ${end}"