commit dc940d4afeb531b75615c0b552ad0eed8f866644 Author: Freya Murphy Date: Thu Jun 6 17:27:05 2024 -0400 initial diff --git a/README.md b/README.md new file mode 100644 index 0000000..4d7592e --- /dev/null +++ b/README.md @@ -0,0 +1,5 @@ +### images + +a collection of docker images + +they can be pulled at `g.freya.cat/freya/` diff --git a/bind9/Dockerfile b/bind9/Dockerfile new file mode 100644 index 0000000..61a5f7a --- /dev/null +++ b/bind9/Dockerfile @@ -0,0 +1,9 @@ +FROM alpine:3.19 + +# install packages +RUN apk add --no-cache tini bind +RUN rm -fr /var/cache/apk/* + +# execute +ENTRYPOINT ["/sbin/tini", "--" ] +CMD ["/usr/sbin/named", "-c", "/etc/bind/named.conf", "-g", "-u", "named"] diff --git a/bind9/README.md b/bind9/README.md new file mode 100644 index 0000000..806c93f --- /dev/null +++ b/bind9/README.md @@ -0,0 +1,7 @@ +### images/bind9 + +runs a bind9 server! + +#### config + +the named.conf file is loaded from /etc/bind/named.conf, put a volume at /etc/bind to modify it. diff --git a/build.sh b/build.sh new file mode 100755 index 0000000..ba48e56 --- /dev/null +++ b/build.sh @@ -0,0 +1,21 @@ +#!/bin/sh + +remote="g.freya.cat" +user="freya" + +docker login "$remote" -u "$user" + +build() { + image="$(echo "$1" | tr -d './')" + echo "building $image" + docker build "$image" -t "$remote/$user/$image:latest" + docker push "$remote/$user/$image" +} + +if [ "$#" -gt 0 ]; then + build "$1" +else + images="$(find . -mindepth 1 -type d \( -name '.*' -prune -o -print \))" + IFS=$'\n' + for image in $images; do build "$image"; done; +fi diff --git a/caddy/Dockerfile b/caddy/Dockerfile new file mode 100644 index 0000000..0260dda --- /dev/null +++ b/caddy/Dockerfile @@ -0,0 +1,13 @@ +FROM alpine:3.19 + +# install packages +RUN apk add --no-cache tini wget +RUN rm -fr /var/cache/apk/* + +# copy entrypoint +COPY ./entrypoint.sh /usr/local/bin/entrypoint.sh +RUN chmod +x /usr/local/bin/entrypoint.sh + +# execute +ENTRYPOINT ["/sbin/tini", "--" ] +CMD ["/usr/local/bin/entrypoint.sh"] diff --git a/caddy/README.md b/caddy/README.md new file mode 100644 index 0000000..c0b5d62 --- /dev/null +++ b/caddy/README.md @@ -0,0 +1,19 @@ +### images/caddy + +runs a caddy server! + +#### volumes + +- /data - stores certificates, ocsp, and most of caddys state +- /config - stores autosave.json + +#### environment + +using the MODULES environment variables you can configure +extra modules to add to caddy. view the modules [here](https://caddyserver.com/download). + +MODULES should be seperated by a space and not include the github.com/ part. (e.g. "caddy-dns/cloudflare aksdb/caddy-cgi/v2") + +#### config + +the caddy file is run at /etc/caddy/Caddyfile, put a volume at /etc/caddy to modify it. diff --git a/caddy/entrypoint.sh b/caddy/entrypoint.sh new file mode 100644 index 0000000..d8c4fc4 --- /dev/null +++ b/caddy/entrypoint.sh @@ -0,0 +1,23 @@ +#!/bin/sh + +URL="https://caddyserver.com/api/download?os=linux&arch=amd64" +IFS=" " +for module in $MODULES +do + module=$(echo "$module" | sed 's/\//%2F/g') + URL="$URL&p=github.com/$module" +done + +wget "$URL" -O /usr/sbin/caddy +chmod +x /usr/sbin/caddy + +if [ ! -f "/etc/caddy/Caddyfile" ]; then + cp /etc/default/Caddyfile /etc/caddy/Caddyfile +fi + +export XDG_CONFIG_HOME=/config +export XDG_DATA_HOME=/data + +exec /usr/sbin/caddy run \ + --config /etc/caddy/Caddyfile \ + --adapter caddyfile diff --git a/minecraft/Dockerfile b/minecraft/Dockerfile new file mode 100644 index 0000000..f44c751 --- /dev/null +++ b/minecraft/Dockerfile @@ -0,0 +1,32 @@ +FROM alpine:3.19 + +# set environment +ENV LANG en_US.UTF-8 +ENV JAVA_HOME=/usr/lib/jvm/java-21-openjdk +ENV PATH=/usr/lib/jvm/java-21-openjdk/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin + +# install packages +RUN apk add --no-cache tini wget openjdk21-jre jq curl shadow fontconfig ttf-dejavu +RUN rm -fr /var/cache/apk/* + +# copy scripts +COPY ./mcjar /usr/local/bin/mcjar +COPY ./mclauncher /usr/local/bin/mclauncher +RUN chmod +x /usr/local/bin/mcjar +RUN chmod +x /usr/local/bin/mclauncher + +# make user +RUN addgroup -S mc && adduser -S mc -G mc +RUN groupmod --gid 1000 mc +RUN usermod --uid 1000 mc + +# make volumes +RUN mkdir /data && chown mc:mc /data +VOLUME /data + +# final +USER mc +WORKDIR /data +ENV SERVER_DIR=/data +ENTRYPOINT ["/sbin/tini", "--" ] +CMD ["/usr/local/bin/mclauncher", "-l"] diff --git a/minecraft/README.md b/minecraft/README.md new file mode 100644 index 0000000..daedb32 --- /dev/null +++ b/minecraft/README.md @@ -0,0 +1,22 @@ +### images/minecraft + +runs a miencraft server, very cool + +#### volumes + +- /data stores the minecraft server files + +#### environment + +- MC_TYPE can be `vanilla`,`paper`,`waterfall`,`velocity`,`folia`,`fabric`, or `forge` +- MC_VERSION is the minecraft version [`latest`,`snapshot`,``] + +extra environment variables include +- PAPERMC_BUILD +- FABRIC_LOADER +- FABRIC_INSTALLER +- FORGE_VERSION [`recommended`, `latest`, ``] + +jvm configuration +- JVMARGS - overwrites the default jvm args +- MEMORY - sets the jvm memory amount (default 1G) diff --git a/minecraft/mcjar b/minecraft/mcjar new file mode 100644 index 0000000..29eb118 --- /dev/null +++ b/minecraft/mcjar @@ -0,0 +1,386 @@ +#!/bin/sh +set -e + +lower() { + echo "$1" | tr '[:upper:]' '[:lower:]' +} + +upper() { + echo "$1" | tr '[:lower:]' '[:upper:]' +} + +# global +MC_TYPE="$(lower "${MC_TYPE:-vanilla}")" +MC_VERSION="$(lower "${MC_VERSION:-latest}")" + +# papermc +PAPERMC_BUILD="$(lower "${PAPERMC_BUILD:-latest}")" + +# fabric +FABRIC_LOADER="$(lower "${FABRIC_LOADER:-latest}")" +FABRIC_INSTALLER="$(lower "${FABRIC_INSTALLER:-latest}")" + +# forge +FORGE_VERSION="$(lower "${FORGE_VERSION:-recommended}")" + +# other +QUIET=1 + +# all output +ALL=0 + +req() { + res=$(curl --fail --silent "$1") + code=$? + + if [ $code -ne 0 ] || [ "$res" = "" ]; then + echo "null"; + else + echo "$res"; + fi +} + +error() { + printf '\x1b[31m[ERROR]\t\x1b[0m%s\n' "$*" > /dev/stderr + exit 1; +} + +log() { + if [ "$QUIET" -eq 0 ]; then + printf '\x1b[0m[LOG]\t%s\n' "$*" > /dev/stderr + fi +} + +index_array() { + array="$1" + key="$2" + type="$3" + + if [ "$key" = "latest" ]; then + index=$(echo "$array" | jq ". | index( last )"); + else + index=$(echo "$array" | jq ". | index( \"$key\" )"); + fi + + if [ "$index" = "null" ]; then + error "Invalid $type: $key" + else + echo "$array" | jq -r ".[$index]"; + fi +} + +#https://api.papermc.io/v2/projects/velocity/versions/3.3.0-SNAPSHOT/ + +papermc() { + api="https://api.papermc.io/v2/projects" + + log "Using papermc api v2" + + get_version() { + log "Getting VERSION for '$MC_TYPE'" + versions=$(req "$api/$MC_TYPE" | jq -r '.versions') + if [ "$versions" = "null" ]; then + error "Invalid TYPE: $MC_TYPE (no versions)" + fi + MC_VERSION=$(index_array "$versions" "$MC_VERSION" "VERSION") + log "VERSION: $MC_VERSION" + } + + get_build() { + log "Getting BUILD for '$MC_TYPE@$MC_VERSION'" + builds=$(req "$api/$MC_TYPE/versions/$MC_VERSION" | jq -r ".builds") + if [ "$builds" = "null" ]; then + error "Invalid VERSION: $MC_TYPE@$MC_TYPE (no builds)" + fi + PAPERMC_BUILD=$(index_array "$builds" "$PAPERMC_BUILD" "BUILD") + log "BUILD: $PAPERMC_BUILD" + } + + get_version + get_build + + name="$MC_TYPE-$MC_VERSION-$PAPERMC_BUILD.jar" + url="$api/$MC_TYPE/versions/$MC_VERSION/builds/$PAPERMC_BUILD/downloads/$name" + + if [ $ALL -eq 1 ]; then + echo "JAR_NAME=$name" + echo "JAR_URL=$url" + echo "MC_TYPE=$MC_TYPE" + echo "MC_VERSION=$MC_VERSION" + echo "PAPERMC_BUILD=$PAPERMC_BUILD" + else + echo "$url" + fi +} + +fabric() { + api="https://meta.fabricmc.net/v2/versions" + + log "Using fabric api v2" + + get_fabric_impl() { + type="$1" + value="$2" + res="" + if [ "$value" = "latest" ]; then + res=$(req "$api/$type" | jq -r 'map(select(.stable == true) | .version) | reverse') + else + res=$(req "$api/$type" | jq -r 'map(.version) | reverse') + fi; + echo $res; + } + + get_game() { + log "Getting VERSION for '$MC_TYPE'" + games=$(get_fabric_impl "game" "$MC_VERSION") + MC_VERSION=$(index_array "$games" "$MC_VERSION" "VERSION") + log "VERSION: $MC_VERSION" + } + + get_loader() { + log "Getting LOADER for '$MC_TYPE'" + loaders=$(get_fabric_impl "loader" "$FABRIC_LOADER") + FABRIC_LOADER=$(index_array "$loaders" "$FABRIC_LOADER" "LOADER") + log "LOADER: $FABRIC_LOADER" + } + + get_installer() { + log "Getting INSTALLER for '$MC_TYPE'" + installers=$(get_fabric_impl "installer" "$FABRIC_INSTALLER") + FABRIC_INSTALLER=$(index_array "$installers" "$FABRIC_INSTALLER" "INSTALLER") + log "INSTALLER: $FABRIC_INSTALLER" + } + + get_game + get_loader + get_installer + + url="$api/loader/$MC_VERSION/$FABRIC_LOADER/$FABRIC_INSTALLER/server/jar" + + if [ $ALL -eq 1 ]; then + echo "JAR_NAME=fabric-$MC_VERSION-$FABRIC_LOADER-$FABRIC_INSTALLER.jar" + echo "JAR_URL=$url" + echo "MC_TYPE=$MC_TYPE" + echo "MC_VERSION=$MC_VERSION" + echo "FABRIC_LOADER=$FABRIC_LOADER" + echo "FABRIC_INSTALLER=$FABRIC_INSTALLER" + else + echo "$url" + fi +} + +vanilla() { + versions=$(req 'https://launchermeta.mojang.com/mc/game/version_manifest.json' | jq '.versions | map({ "id": .id, "type": .type, "url": .url }) | reverse'); + + map_type_impl() { + type="$1" + echo "$versions" | jq -r "map(select(.type == \"$type\"))" + } + + url="" + + get_version() { + log "Getting VERSION for '$MC_TYPE'" + version="" + case "$MC_VERSION" in + "latest") + version=$(map_type_impl "release" | jq -r 'last') + ;; + "snapshot") + version=$(map_type_impl "snapshot" | jq -r 'last') + ;; + *) + version=$(echo "$versions" | jq ".[] | select(.id == \"$MC_VERSION\")") + ;; + esac + + if [ "$version" = "null" ] || [ "$version" = "" ]; then + error "Invalid VERSION: $MC_VERSION" + fi + + MC_VERSION=$(echo "$version" | jq -r '.id') + log "VERSION: $MC_VERSION" + + json=$(echo "$version" | jq -r '.url') + url=$(req "$json" | jq -r '.downloads.server.url') + + if [ "$url" = "null" ]; then + error "Cannot get server jar for VERSION: $MC_VERSION" + fi + } + + get_version + + if [ $ALL -eq 1 ]; then + echo "JAR_NAME=minecraft-$MC_VERSION.jar" + echo "JAR_URL=$url" + echo "MC_TYPE=$MC_TYPE" + echo "MC_VERSION=$MC_VERSION" + else + echo "$url" + fi + +} + +forge() { + versions=$(req "https://files.minecraftforge.net/net/minecraftforge/forge/promotions_slim.json" | jq -r '.promos'); + + log "Using forge promotions slim json" + + url="" + + get_forge_url() { + url="https://maven.minecraftforge.net/net/minecraftforge/forge/$1/forge-$1-installer.jar" + code=0 + wget -q --spider "$url" || code=$? + if [ $code -eq 0 ]; then + echo "$url"; + fi + } + + get_version() { + log "Getting VERSION for '$MC_TYPE'" + if [ "$MC_VERSION" = "latest" ]; then + MC_VERSION=$(echo "$versions" | jq -r '. | keys | .[]' | awk -F '-' '{print $1}' | sort -t "." -n -k1,1 -k2,2 -k3,3 | tail -n1) + fi + log "VERSION: $MC_VERSION" + } + + try_forge_version() { + ver=$(echo "$versions" | jq -r ".\"$MC_VERSION-$FORGE_VERSION\"") + if [ "$ver" = "null" ] && [ "$FORGE_VERSION" != "latest" ]; then + FORGE_VERSION=latest + try_forge_version + else + echo "$ver" + fi + } + + get_forge_version() { + log "Getting FORGE VERSION for '$MC_TYPE'" + if [ "$FORGE_VERSION" != "latest" ] && [ "$FORGE_VERSION" != "recommended" ]; then + return; + fi + ver=$(try_forge_version) + if [ "$ver" = "null" ]; then + error "Invalid VERSION: $MC_VERSION-$FORGE_VERSION" + fi + FORGE_VERSION="$ver" + log "FORGE VERSION: $FORGE_VERSION" + } + + search_for_url() { + log "Searching for forge URL" + log "Trying MC_VERSION-FORGE_VERSION" + ver=$(get_forge_url "$MC_VERSION-$FORGE_VERSION") + if [ "$ver" != "" ]; then url="$ver"; return 0; fi + log "Trying MC_VERSION-FORGE_VERSION-MC_VERSION" + ver=$(get_forge_url "$MC_VERSION-$FORGE_VERSION-$MC_VERSION") + if [ "$ver" != "" ]; then url="$ver"; return 0; fi + log "Trying MC_VERSION-FORGE_VERSION-mc172" + ver=$(get_forge_url "$MC_VERSION-$FORGE_VERSION-mc172") + if [ "$ver" != "" ]; then url="$ver"; return 0; fi + error "Invalid VERSION: $MC_VERSION-$FORGE_VERSION" + } + + get_version + get_forge_version + search_for_url + + if [ $ALL -eq 1 ]; then + echo "JAR_NAME=forge-$MC_VERSION-$FORGE_VERSION-installer.jar" + echo "JAR_URL=$url" + echo "MC_TYPE=$MC_TYPE" + echo "MC_VERSION=$MC_VERSION" + echo "FORGE_VERSION=$FORGE_VERSION" + else + echo "$url" + fi +} + +get_url() { + log "TYPE: $MC_TYPE" + + case "$MC_TYPE" in + "vanilla") + vanilla + ;; + "paper" | "waterfall" | "velocity" | "folia") + papermc + ;; + "fabric") + fabric + ;; + "forge") + forge + ;; + *) + error "Invalid TYPE: $MC_TYPE" + ;; + esac +} + +usage() { + printf "usage: mcjar [options]\n" +} + +help() { + printf "usage: mcjar [options]\n\n" + printf "options:\n" + printf "\t-h\tshow this message\n" + printf "\t-l\tshow logging (verbose)\n\n" + printf "\t-a\toutput all variables\n\n" + + printf "\t-t TYPE\t\tset the mc server type\n" + printf "\t [vanilla,fabric,forge,paper,folia,velocity,waterfall]\n\n" + printf "\t-v VERSION\tset the mc server version\n" + printf "\t [latest,snapshot,]\n\n" + + printf "environment:\n" + printf "\tMC_TYPE\t\tsets the mc server type (same as -t TYPE)\n" + printf "\tMC_VERSION\tsets the mc server version (same as -v VERSION)\n\n" + + printf "\tPAPERMC_BUILD\tsets the papermc build\n\n" + + printf "\tFABRIC_LOADER\t\tsets the fabric loder version\n" + printf "\tFABRIC_INSTALLER\tsets the fabric installer version\n\n" + + printf "\tFORGE_VERSION\tsets the forge loader version\n\n" +} + +chk_command() { + if ! command -v "$1" > /dev/null; then + >&2 echo "error: command '$1' could not be found" + exit 1 + fi +} + +chk_command jq +chk_command curl +chk_command getopts + +while getopts "hlat:v:" arg 2> /dev/null; do + case $arg in + h) + help + exit 0 + ;; + l) + QUIET=0 + ;; + a) + ALL=1 + ;; + t) + MC_TYPE=${OPTARG} + ;; + v) + MC_VERSION=${OPTARG} + ;; + ?) + error "unknown option" + ;; + esac; +done; + +get_url diff --git a/minecraft/mclauncher b/minecraft/mclauncher new file mode 100644 index 0000000..721b48f --- /dev/null +++ b/minecraft/mclauncher @@ -0,0 +1,259 @@ +#!/bin/sh + +set -e + +# +# DEFAULT VARIABLE GENERATORS +# + +jvm_args() { + MEMORY="${MEMORY:-1G}" + printf -- "-Xms$MEMORY -Xmx$MEMORY " + printf -- "-XX:+UseG1GC -XX:+ParallelRefProcEnabled -XX:MaxGCPauseMillis=200 " + printf -- "-XX:+UnlockExperimentalVMOptions -XX:+DisableExplicitGC -XX:+AlwaysPreTouch " + printf -- "-XX:G1NewSizePercent=30 -XX:G1MaxNewSizePercent=40 -XX:G1HeapRegionSize=8M " + printf -- "-XX:G1ReservePercent=20 -XX:G1HeapWastePercent=5 -XX:G1MixedGCCountTarget=4 " + printf -- "-XX:InitiatingHeapOccupancyPercent=15 -XX:G1MixedGCLiveThresholdPercent=90 " + printf -- "-XX:G1RSetUpdatingPauseTimePercent=5 -XX:SurvivorRatio=32 -XX:+PerfDisableSharedMem " + printf -- "-XX:MaxTenuringThreshold=1 " +} + +# +# ENV VARS +# + +SERVER_DIR="$(realpath ${MC_DIR:-./server})" +JVMARGS=${JVMARGS:-$(jvm_args)} + +# +# PREDEFINE VARS +# + +MCLAUNCHER_INFO="" +MCLAUNCHER_BINARY="" +MCLAUNCHER_QUIET=1 + +# +# HELPERS +# + +error() { + printf '\x1b[31m[ERROR]\t\x1b[0m%s\n' "$*" > /dev/stderr + exit 1; +} + +log() { + if [ "$MCLAUNCHER_QUIET" -eq 0 ]; then + printf '\x1b[0m[LOG]\t%s\n' "$*" > /dev/stderr + fi +} + +step() { + if [ "$MCLAUNCHER_QUIET" -eq 0 ]; then + printf '\x1b[36m[STEP]\t\x1b[0m%s\n' "$*" > /dev/stderr + fi +} + +get_key() { + echo "$MCLAUNCHER_INFO" | grep "$1=" | awk -F '=' '{ print $2 }' +} + +# +# INFO STEP +# gets the up to date information from mcjar +# + +info_step() { + step "info" + + # getting latest info from mcjar + MCLAUNCHER_INFO="$(mcjar -a)" + + [ "$MCLAUNCHER_QUIET" -eq 1 ] || echo "$MCLAUNCHER_INFO"; +} + +# +# BINARY STEP +# attempts to find the current binary installed on the system +# + +binary_step_forge() { + jar_name="$(get_key "JAR_NAME")" + jar_prefix="${jar_name%-installer.jar}" + suffixs="$(echo ".jar;-shim.jar;-universal.jar" | tr ";" "\n")" + + IFS=$'\n' + for suffix in $suffixs; do + if [ -f "$SERVER_DIR/$jar_prefix$suffix" ]; then + MCLAUNCHER_BINARY="$jar_prefix$suffix" + return; + fi + done +} + +binary_step_default() { + jar_name="$(get_key "JAR_NAME")" + if [ -f "$SERVER_DIR/$jar_name" ]; then + MCLAUNCHER_BINARY="$jar_name" + fi +} + +binary_step() { + step "binary" + + MCLAUNCHER_BINARY="" + type="$(get_key "MC_TYPE")" + case "$type" in + "forge") + binary_step_forge + ;; + *) + binary_step_default + ;; + esac + + if [ "$MCLAUNCHER_BINARY" != "" ]; then + log "found binary '$MCLAUNCHER_BINARY'" + else + log "could not locate binary... will download" + fi +} + +# +# DOWNLOAD STEP +# download the binary if it needs to needs updated +# + +download_step() { + step "download" + + if [ "$MCLAUNCHER_BINARY" != "" ]; then + log "jar is up to date... skipping" + return; + fi + + # clean up old files + rm -f "$SERVER_DIR"/*.jar + rm -f "$SERVER_DIR"/*.jar.log + rm -f "$SERVER_DIR"/*.bat + rm -f "$SERVER_DIR/run.sh" + + # update the jar + log "jar is out of date... updating" + jar_url="$(get_key "JAR_URL")" + jar_name="$(get_key "JAR_NAME")" + log "downloading '$jar_url'" + wget -q "$jar_url" -O "$SERVER_DIR/$jar_name" + MCLAUNCHER_BINARY="$jar_name" +} + +# +# INSTALL STEP +# some mc types need an extra install step to setup the server files before running +# + +install_step_forge() { + log "installing forge server" + jar_name="$(get_key "JAR_NAME")" + java -jar "$SERVER_DIR/$jar_name" --installServer + + binary_step_forge + if [ "$MCLAUNCHER_BINARY" = "" ]; then + error "could not locate forge binary" + fi +} + +install_step() { + step "install" + + type="$(get_key "MC_TYPE")" + case "$type" in + "forge") + install_step_forge + ;; + *) + log "install step not needed for '$type'" + ;; + esac +} + +# +# EXECUTE STEP +# run the thing!!!!!! +# + +execute_step_default() { + jar_name="$(get_key "JAR_NAME")" + exec java $JVMARGS -jar "$SERVER_DIR/$jar_name" nogui +} + +execute_step_forge() { + if [ -f "$SERVER_DIR/run.sh" ]; then + echo "$JVMARGS" > "$SERVER_DIR/user_jvm_args.txt" + chmod +x "$SERVER_DIR/run.sh" + exec "$SERVER_DIR/run.sh" nogui + else + exec java $JVMARGS -jar "$SERVER_DIR/$MCLAUNCHER_BINARY" nogui + fi +} + +execute_step() { + step "execute" + + echo "eula=true" > "$SERVER_DIR/eula.txt" + + type="$(get_key "MC_TYPE")" + case "$type" in + "forge") + execute_step_forge + ;; + *) + execute_step_default + ;; + esac +} + +chk_command() { + if ! command -v "$1" > /dev/null; then + >&2 echo "error: command '$1' could not be found" + exit 1 + fi +} + +help() { + printf "usage: mclauncher [options]\n\n" + printf "options:\n" + printf "\t-h\tshow this message\n" + printf "\t-l\tshow logging (verbose)\n\n" + printf "environment:\n" + printf "\tsee 'mcjar -h' for environment\n" +} + +chk_command mcjar +chk_command java +chk_command awk +chk_command getopts + +while getopts "hl" arg 2>/dev/null; do + case "$arg" in + h) + help + exit 0 + ;; + l) + MCLAUNCHER_QUIET=0 + ;; + ?) + error "unknown option" + ;; + esac; +done; + +mkdir -p "$SERVER_DIR" +cd "$SERVER_DIR" + +info_step +binary_step +download_step +install_step +execute_step