#!/bin/bash # https://caddyserver.com/download # https://caddyserver.com/download/build?os=darwin&arch=amd64&features=DNS,awslambda,cors,expires,filemanager,filter,git,hugo,ipfilter,jsonp,jwt,locale,mailout,minify,multipass,prometheus,ratelimit,realip,search,upload,cloudflare,digitalocean,dnsimple,dyn,gandi,googlecloud,linode,namecheap,ovh,rfc2136,route53,vultr installer_base="https://git.daplie.com/Daplie/caddy-installer/raw/master" caddy_systemd_service="$installer_base/etc/systemd/system/caddy.service" caddy_systemd_tmpfiles="$installer_base/etc/tmpfiles.d/caddy.conf" caddy_launchd_service="$installer_base/Library/LaunchDaemons/com.caddyserver.web.plist" caddy_localhost_index="$installer_base/srv/www/index.html" all_oses="windows,darwin,linux,freebsd,openbsd" all_arches="arm64,amd64,386,armv5,armv6l,armv7l" all_plugins="DNS,awslambda,cors,expires,filemanager,filter,git,hugo,ipfilter,jsonp,jwt,locale,mailout,minify,multipass,prometheus,ratelimit,realip,search,upload,cloudflare,digitalocean,dnsimple,dyn,gandi,googlecloud,linode,namecheap,ovh,rfc2136,route53,vultr" caddy_os="" default_os="" caddy_arch="" default_arch="" caddy_arm="" caddy_features="" caddy_user=www-data caddy_group=www-data install_path="/usr/local/bin" http_get="" http_opts="" http_out="" caddy_bin="caddy" caddy_dl_ext=".tar.gz" detect_http_get() { if type -p curl >/dev/null 2>&1; then http_get="curl" http_opts="-fsSL" http_out="-o" #curl -fsSL "$caddy_url" -o "$PREFIX/tmp/$caddy_pkg" elif type -p wget >/dev/null 2>&1; then http_get="wget" http_opts="--quiet" http_out="-O" #wget --quiet "$caddy_url" -O "$PREFIX/tmp/$caddy_pkg" else echo "Aborted, could not find curl or wget" return 7 fi } detect_arch() { trap 'echo -e "Aborted, error $? in command: $BASH_COMMAND"; trap ERR; return 1' ERR ######################### # Which OS and version? # ######################### default_arch="unknown" # NOTE: `uname -m` is more accurate and universal than `arch` # See https://en.wikipedia.org/wiki/Uname unamem="$(uname -m)" if [[ $unamem == *aarch64* ]]; then default_arch="arm64" elif [[ $unamem == *64* ]]; then default_arch="amd64" elif [[ $unamem == *86* ]]; then default_arch="386" elif [[ $unamem == *armv5* ]]; then default_arch="armv5" elif [[ $unamem == *armv6l* ]]; then default_arch="armv6l" elif [[ $unamem == *armv7l* ]]; then default_arch="armv7l" else default_arch="$unamem" fi trap ERR } detect_os() { trap 'echo -e "Aborted, error $? in command: $BASH_COMMAND"; trap ERR; return 1' ERR default_os="unsupported" uname="$(uname)" #declare -u unameu=$uname # requires bash v4+, not supported on macOS unameu="$(echo $uname | tr '/a-z/' '/A-Z/')" if [[ ${unameu} == *DARWIN* ]]; then default_os="darwin" vers=$(sw_vers) version=${vers##*ProductVersion:} IFS='.' read OSX_MAJOR OSX_MINOR _ <<<"$version" # Major if ((OSX_MAJOR < 10)); then echo "Aborted, unsupported OS X version (9-)" return 3 fi if ((OSX_MAJOR > 10)); then echo "Aborted, unsupported OS X version (11+)" return 4 fi # Minor if ((OSX_MINOR < 5)); then echo "Aborted, unsupported OS X version (10.5-)" return 5 fi elif [[ ${unameu} == *LINUX* ]]; then default_os="linux" elif [[ ${unameu} == *FREEBSD* ]]; then default_os="freebsd" elif [[ ${unameu} == *OPENBSD* ]]; then default_os="openbsd" elif [[ ${unameu} == *WIN* ]]; then # Should catch cygwin default_os="windows" caddy_dl_ext=".zip" caddy_bin=$caddy_bin.exe else default_os="$uname" fi trap ERR } detect_target() { trap 'echo -e "Aborted, error $? in command: $BASH_COMMAND"; trap ERR; return 1' ERR detect_arch detect_os while [[ $# -gt 0 ]]; do key="$1" case $key in --arch) caddy_arch="$2" shift # past argument ;; --os) caddy_os="$2" shift # past argument ;; -h|--help) echo "" echo "Usage: install-caddy [plugin1,plugin2,...]" echo "" echo "Optional arguments (defaults shown)" echo " --os ${default_os} # options: $(echo $all_oses | tr "," " ")" echo " --arch ${default_arch}${caddy_arm} # options: $(echo $all_arches | tr "," " ")" echo "" echo "Features:" echo "$(echo $all_plugins)" echo "" exit 0 ;; -*) # unknown argument echo "unrecognized argument '$1'" exit 13 ;; *) # unknown value if [ -z "${caddy_features}" ]; then caddy_features=$1 else echo "unrecognized value '$1'" exit 1 fi ;; esac shift # past argument or value done # use commandline-specified caddy os or the host OS if [ -z "$caddy_os" ]; then caddy_os=$default_os fi if [[ ${caddy_os} == "darwin" ]]; then caddy_user=_www caddy_group=_www caddy_dl_ext=".zip" elif [[ ${caddy_os} == "linux" ]]; then ignore=true elif [[ ${caddy_os} == "freebsd" ]]; then ignore=true elif [[ ${caddy_os} == "openbsd" ]]; then ignore=true elif [[ ${caddy_os} == "windows" ]]; then caddy_dl_ext=".zip" caddy_bin=$caddy_bin.exe else echo "Aborted, unsupported or unknown os: $caddy_os" return 6 fi # use commandline-specified caddy arch or the host arch if [ -z "$caddy_arch" ]; then caddy_arch=$default_arch fi if [[ ${caddy_arch} == "arm64" ]]; then ignore=true elif [[ ${caddy_arch} == "amd64" ]]; then ignore=true elif [[ ${caddy_arch} == "386" ]]; then ignore=true elif [[ ${caddy_arch} == "armv5" ]]; then caddy_arch="arm" caddy_arm=5 elif [[ ${caddy_arch} == "armv6l" ]]; then caddy_arch="arm" caddy_arm=6 elif [[ ${caddy_arch} == "armv7l" ]]; then caddy_arch="arm" caddy_arm=7 else echo "Aborted, unsupported or unknown architecture: $caddy_arch" return 2 fi trap ERR } download_caddy() { trap 'echo -e "Aborted, error $? in command: $BASH_COMMAND"; trap ERR; return 1' ERR ######################## # Download and extract # ######################## echo "Downloading Caddy for $caddy_os/$caddy_arch$caddy_arm..." #caddy_file="caddy_${caddy_os}_$caddy_arch${caddy_arm}_custom$caddy_dl_ext" caddy_pkg="caddy_${caddy_os}_$caddy_arch${caddy_arm}_custom$caddy_dl_ext" caddy_dir="caddy_${caddy_os}_$caddy_arch${caddy_arm}_custom" # new.caddyserver.com caddy_url="https://caddyserver.com/download/$caddy_os/$caddy_arch$caddy_arm?plugins=$caddy_features" # old caddyserver.com #caddy_url="https://caddyserver.com/download/build?os=$caddy_os&arch=$caddy_arch&arm=$caddy_arm&features=$caddy_features" echo "$caddy_url" # Use $PREFIX for compatibility with Termux on Android rm -rf "$PREFIX/tmp/$caddy_pkg" "$PREFIX/tmp/$caddy_dir" $http_get $http_opts "$caddy_url" $http_out "$PREFIX/tmp/$caddy_pkg" echo "Extracting..." case "$caddy_pkg" in *.zip) unzip -o "$PREFIX/tmp/$caddy_pkg" "$caddy_bin" -d "$PREFIX/tmp/$caddy_dir/" ;; #*.tar.gz) tar -xzf "$PREFIX/tmp/$caddy_file" -C "$PREFIX/tmp/" "$caddy_bin" ;; *.tar.gz) mkdir -p "$PREFIX/tmp/$caddy_dir/"; tar -xzf "$PREFIX/tmp/$caddy_pkg" -C "$PREFIX/tmp/$caddy_dir/" ;; esac trap ERR } install_caddy() { trap 'echo -e "Aborted, error $? in command: $BASH_COMMAND"; trap ERR; return 1' ERR if [ "$caddy_os" != "$default_os" ]; then echo "caddy os does not match $default_os, skipping install" fi if [ "$caddy_arch" != "$default_arch" ]; then echo "caddy arch does not match $default_arch, skipping install" fi # Termux on Android has $PREFIX set which already ends with /usr if [[ -n "$ANDROID_ROOT" && -n "$PREFIX" ]]; then install_path="$PREFIX/bin" fi # Fall back to /usr/bin if necessary if [[ ! -d $install_path ]]; then install_path="/usr/bin" fi # Not every platform has or needs sudo (see issue #40) ((EUID)) && [[ -z "$ANDROID_ROOT" ]] && sudo_cmd="sudo" # Back up existing caddy, if any caddy_cur_ver="$("$caddy_bin" --version 2>/dev/null | cut -d ' ' -f2)" if [[ $caddy_cur_ver ]]; then # caddy of some version is already installed caddy_path="$(type -p "$caddy_bin")" caddy_backup="${caddy_path}_$caddy_cur_ver" echo "Backing up $caddy_path to $caddy_backup" echo "(Password may be required.)" $sudo_cmd mv "$caddy_path" "$caddy_backup" fi echo "Putting caddy in $install_path (may require password)" $sudo_cmd mv "$PREFIX/tmp/$caddy_dir/$caddy_bin" "$install_path/$caddy_bin" $sudo_cmd mkdir -p $PREFIX/etc/caddy if [ ! -f "$PREFIX/etc/caddy/Caddyfile" ] || [ -z "$(cat $PREFIX/etc/caddy/Caddyfile)" ]; then cat <<'CADDY_EOF' >> $PREFIX/tmp/$caddy_dir/Caddyfile http://localhost { root /srv/www/localhost } CADDY_EOF $sudo_cmd mv "$PREFIX/tmp/$caddy_dir/Caddyfile" "$PREFIX/etc/caddy/Caddyfile" fi $sudo_cmd mkdir -p $PREFIX/etc/ssl/caddy $sudo_cmd mkdir -p $PREFIX/var/log/caddy $sudo_cmd mkdir -p $PREFIX/srv/www/localhost $sudo_cmd chmod +x "$install_path/$caddy_bin" $sudo_cmd chmod 755 $PREFIX/etc/caddy $sudo_cmd chmod 755 $PREFIX/etc/caddy $sudo_cmd chmod 750 $PREFIX/etc/ssl/caddy $sudo_cmd chmod 750 $PREFIX/var/log/caddy $sudo_cmd chmod 755 $PREFIX/srv/www $sudo_cmd chmod 755 $PREFIX/srv/www/localhost if [ ! -f "$PREFIX/srv/www/localhost/index.html" ] || [ -z "$(cat $PREFIX/srv/www/localhost)" ]; then $http_get $http_opts "$caddy_localhost_index" $http_out $PREFIX/tmp/$caddy_dir/index.html $sudo_cmd mv $PREFIX/tmp/$caddy_dir/index.html $PREFIX/srv/www/localhost/ $sudo_cmd chown -R $caddy_user:$caddy_group $PREFIX/srv/www/localhost/ $sudo_cmd chmod 664 $PREFIX/srv/www/localhost/index.html fi if setcap_cmd=$(type -p setcap); then $sudo_cmd $setcap_cmd cap_net_bind_service=+ep "$install_path/$caddy_bin" fi $sudo_cmd rm -- "$PREFIX/tmp/$caddy_pkg" echo "" # check installation $caddy_bin --version echo "Successfully installed" echo "" echo "Trying to set permissions to $caddy_user:$caddy_group" echo '(if this fails please file a bug with the output of "uname -a" and "cat /etc/group")' # TODO if this fails perhaps catch and create a www-data group? # TODO grep $caddy_user $PREFIX/etc/passwd # TODO grep $caddy_group $PREFIX/etc/group # TODO adduser $caddy_user $sudo_cmd chown -R $caddy_user:$caddy_group $PREFIX/etc/caddy $sudo_cmd chown -R $caddy_user:$caddy_group $PREFIX/etc/ssl/caddy $sudo_cmd chown -R $caddy_user:$caddy_group $PREFIX/var/log/caddy $sudo_cmd chown -R $caddy_user:$caddy_group $PREFIX/srv/www echo "" echo "Successfully changed permissions" echo "" if [ -d "$PREFIX/etc/systemd/system" ]; then echo "" echo "Installing as systemd service" echo "" $http_get $http_opts "$caddy_systemd_service" $http_out $PREFIX/tmp/$caddy_dir/caddy.service $sudo_cmd mv $PREFIX/tmp/$caddy_dir/caddy.service $PREFIX/etc/systemd/system/caddy.service $sudo_cmd chown -R root:root $PREFIX/etc/systemd/system/caddy.service $sudo_cmd chmod 644 $PREFIX/etc/systemd/system/caddy.service $http_get $http_opts "$caddy_systemd_tmpfiles" $http_out $PREFIX/tmp/$caddy_dir/caddy.conf $sudo_cmd mv $PREFIX/tmp/$caddy_dir/caddy.conf $PREFIX/etc/tmpfiles.d/caddy.conf $sudo_cmd chown -R root:root $PREFIX/etc/tmpfiles.d/caddy.conf $sudo_cmd chmod 644 $PREFIX/etc/tmpfiles.d/caddy.conf $sudo_cmd systemctl stop caddy.service >/dev/null 2>/dev/null $sudo_cmd systemctl daemon-reload $sudo_cmd systemctl start caddy.service $sudo_cmd systemctl enable caddy.service echo "caddy started with systemctl" elif [ -d "/Library/LaunchAgents" ]; then echo "" echo "Installing as launchd service" echo "" # See http://www.launchd.info/ $http_get $http_opts "$caddy_launchd_service" $http_out $PREFIX/tmp/$caddy_dir/com.caddyserver.web.plist $sudo_cmd mv $PREFIX/tmp/$caddy_dir/com.caddyserver.web.plist /Library/LaunchAgents/com.caddyserver.web.plist $sudo_cmd chown root:wheel /Library/LaunchAgents/com.caddyserver.web.plist $sudo_cmd chmod 0644 /Library/LaunchAgents/com.caddyserver.web.plist $sudo_cmd launchctl unload -w /Library/LaunchAgents/com.caddyserver.web.plist >/dev/null 2>/dev/null $sudo_cmd launchctl load -w /Library/LaunchAgents/com.caddyserver.web.plist echo "caddy started with launchd" else echo "" echo "Unknown system service init type. You must install as a system service manually." echo '(please file a bug with the output of "uname -a")' echo "" fi # cleanup $sudo_cmd rm -rf -- "$PREFIX/tmp/$caddy_dir/" trap ERR } run() { trap 'echo -e "Aborted, error $? in command: $BASH_COMMAND"; trap ERR; return 1' ERR detect_http_get detect_target "$@" download_caddy "$@" if [ -f "$PREFIX/tmp/$caddy_dir/install.sh" ]; then chmod a+x $PREFIX/tmp/$caddy_dir/install.sh $PREFIX/tmp/$caddy_dir/install.sh "$PREFIX/tmp/$caddy_dir" "$@" else install_caddy "$@" fi trap ERR return 0 } run "$@"