diff --git a/config/nginx/default.conf b/config/nginx/default.conf new file mode 100644 index 0000000..ae7ee20 --- /dev/null +++ b/config/nginx/default.conf @@ -0,0 +1,17 @@ +server { + index index.php index.html; + server_name php-docker.local; + error_log /var/log/nginx/error.log; + access_log /var/log/nginx/access.log; + root /var/www/html; + + location ~ \.php$ { + try_files $uri =404; + fastcgi_split_path_info ^(.+\.php)(/.+)$; + fastcgi_pass ${NGINX_PHP_CGI}; + fastcgi_index index.php; + include fastcgi_params; + fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; + fastcgi_param PATH_INFO $fastcgi_path_info; + } +} diff --git a/setup.sh b/setup.sh new file mode 100644 index 0000000..7c6fbfd --- /dev/null +++ b/setup.sh @@ -0,0 +1,223 @@ +#!/bin/bash + +# version v1.0.0 +# executed manually / via Make +# task wrapper for various setup scripts + +CONFIG_PATH= +CONTAINER_NAME= +CRI= +DEFAULT_CONFIG_PATH= +DESIRED_CONFIG_PATH= +DIR=$(pwd) +DMS_CONFIG='/tmp/docker-mailserver' +IMAGE_NAME= +DEFAULT_IMAGE_NAME='docker.io/mailserver/docker-mailserver:latest' +INFO= +PODMAN_ROOTLESS=false +USE_SELINUX= +USE_TTY= +VOLUME= + +WHITE=$(echo -ne '\e[37m') +ORANGE=$(echo -ne '\e[38;5;214m') +LBLUE=$(echo -ne '\e[94m') +RESET=$(echo -ne '\e[0m') + +set -euEo pipefail +shopt -s inherit_errexit 2>/dev/null || true + +function _show_local_usage +{ + # shellcheck disable=SC2059 + printf '%s' "${ORANGE}OPTIONS${RESET} + ${LBLUE}Config path, container or image adjustments${RESET} + -i IMAGE_NAME + Provides the name of the 'docker-mailserver' image. The default value is + '${WHITE}${DEFAULT_IMAGE_NAME}${RESET}' + + -c CONTAINER_NAME + Provides the name of the running container. + + -p PATH + Provides the local path of the config folder to the temporary container instance. + Does not work if an existing a 'docker-mailserver' container is already running. + + ${LBLUE}SELinux${RESET} + -z + Allows container access to the bind mount content that is shared among + multiple containers on a SELinux-enabled host. + + -Z + Allows container access to the bind mount content that is private and + unshared with other containers on a SELinux-enabled host. + + ${LBLUE}Podman${RESET} + -R + Accept running in Podman rootless mode. Ignored when using Docker / Docker Compose. + +" + + [[ ${1:-} == 'no-exit' ]] && return 0 + + # shellcheck disable=SC2059 + printf '%s' "${ORANGE}EXIT STATUS${RESET} + Exit status is 0 if the command was successful. If there was an unexpected error, an error + message is shown describing the error. In case of an error, the script will exit with exit + status 1. + +" +} + +function _get_absolute_script_directory +{ + if dirname "$(readlink -f "${0}")" &>/dev/null + then + DIR=$(dirname "$(readlink -f "${0}")") + elif realpath -e -L "${0}" &>/dev/null + then + DIR=$(realpath -e -L "${0}") + DIR="${DIR%/setup.sh}" + fi +} + +function _set_default_config_path +{ + if [[ -d "${DIR}/config" ]] + then + # legacy path (pre v10.2.0) + DEFAULT_CONFIG_PATH="${DIR}/config" + else + DEFAULT_CONFIG_PATH="${DIR}/docker-data/dms/config" + fi +} + +function _handle_config_path +{ + if [[ -z ${DESIRED_CONFIG_PATH} ]] + then + # no desired config path + if [[ -n ${CONTAINER_NAME} ]] + then + VOLUME=$(${CRI} inspect "${CONTAINER_NAME}" \ + --format="{{range .Mounts}}{{ println .Source .Destination}}{{end}}" | \ + grep "${DMS_CONFIG}$" 2>/dev/null || :) + fi + + if [[ -n ${VOLUME} ]] + then + CONFIG_PATH=$(echo "${VOLUME}" | awk '{print $1}') + fi + + if [[ -z ${CONFIG_PATH} ]] + then + CONFIG_PATH=${DEFAULT_CONFIG_PATH} + fi + else + CONFIG_PATH=${DESIRED_CONFIG_PATH} + fi +} + +function _run_in_new_container +{ + # start temporary container with specified image + if ! ${CRI} history -q "${IMAGE_NAME}" &>/dev/null + then + echo "Image '${IMAGE_NAME}' not found. Pulling ..." + ${CRI} pull "${IMAGE_NAME}" + fi + + ${CRI} run --rm "${USE_TTY}" \ + -v "${CONFIG_PATH}:${DMS_CONFIG}${USE_SELINUX}" \ + "${IMAGE_NAME}" "${@}" +} + +function _main +{ + _get_absolute_script_directory + _set_default_config_path + + local OPTIND + while getopts ":c:i:p:zZR" OPT + do + case ${OPT} in + ( i ) IMAGE_NAME="${OPTARG}" ;; + ( z | Z ) USE_SELINUX=":${OPT}" ;; + ( c ) CONTAINER_NAME="${OPTARG}" ;; + ( R ) PODMAN_ROOTLESS=true ;; + ( p ) + case "${OPTARG}" in + ( /* ) DESIRED_CONFIG_PATH="${OPTARG}" ;; + ( * ) DESIRED_CONFIG_PATH="${DIR}/${OPTARG}" ;; + esac + + if [[ ! -d ${DESIRED_CONFIG_PATH} ]] + then + echo "Specified directory '${DESIRED_CONFIG_PATH}' doesn't exist" >&2 + exit 1 + fi + ;; + + ( * ) + echo "Invalid option: '-${OPTARG}'" >&2 + echo -e "Use './setup.sh help' to get a complete overview.\n" >&2 + _show_local_usage 'no-exit' + exit 1 + ;; + + esac + done + shift $(( OPTIND - 1 )) + + if command -v docker &>/dev/null + then + CRI=docker + elif command -v podman &>/dev/null + then + CRI=podman + if ! ${PODMAN_ROOTLESS} && [[ ${EUID} -ne 0 ]] + then + read -r -p "You are running Podman in rootless mode. Continue? [Y/n] " + [[ -n ${REPLY} ]] && [[ ${REPLY} =~ (n|N) ]] && exit 0 + fi + else + echo 'No supported Container Runtime Interface detected.' + exit 1 + fi + + INFO=$(${CRI} ps --no-trunc --format "{{.Image}};{{.Names}}" --filter \ + label=org.opencontainers.image.title="docker-mailserver" | tail -1) + + [[ -z ${CONTAINER_NAME} ]] && CONTAINER_NAME=${INFO#*;} + [[ -z ${IMAGE_NAME} ]] && IMAGE_NAME=${INFO%;*} + if [[ -z ${IMAGE_NAME} ]] + then + IMAGE_NAME=${NAME:-${DEFAULT_IMAGE_NAME}} + fi + + if test -t 0 + then + USE_TTY="-it" + else + # GitHub Actions will fail (or really anything else + # lacking an interactive tty) if we don't set a + # value here; "-t" alone works for these cases. + USE_TTY="-t" + fi + + _handle_config_path + + if [[ -n ${CONTAINER_NAME} ]] + then + ${CRI} exec "${USE_TTY}" "${CONTAINER_NAME}" setup "${@}" + else + _run_in_new_container setup "${@}" + fi + + [[ ${1:-} == 'help' ]] && _show_local_usage + + return 0 +} + +[[ -z ${1:-} ]] && set 'help' +_main "${@}"