diff --git a/.env b/.env index ca05320..06c53cd 100644 --- a/.env +++ b/.env @@ -74,7 +74,7 @@ PERMIT_DOCKER=none # `/etc/localtime`, which you can alternatively mount into the container. The value of this variable # must follow the pattern `AREA/ZONE`, i.e. of you want to use Germany's time zone, use `Europe/Berlin`. # You can lookup all available timezones here: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones#List -TZ= +TZ=Europe/Paris # In case you network interface differs from 'eth0', e.g. when you are using HostNetworking in Kubernetes, # you can set NETWORK_INTERFACE to whatever interface you want. This interface will then be used. @@ -118,7 +118,7 @@ ENABLE_POLICYD_SPF=1 # Enables POP3 service # - **0** => Disabled # - 1 => Enabled -ENABLE_POP3= +ENABLE_POP3=0 # Enables IMAP service # - 0 => Disabled @@ -128,7 +128,7 @@ ENABLE_IMAP=1 # Enables ClamAV, and anti-virus scanner. # 1 => Enabled # **0** => Disabled -ENABLE_CLAMAV=0 +ENABLE_CLAMAV=1 # Add the value of this ENV as a prefix to the mail subject when spam is detected. # NOTE: This subject prefix may be redundant (by default spam is delivered to a junk folder). diff --git a/README.md b/README.md index c4b6d82..aca0f0c 100644 --- a/README.md +++ b/README.md @@ -37,5 +37,13 @@ Modification des labels pour traefik docker compose logs -f ~~~ +~~~bash + docker exec -ti mailserver setup email add info@tips-of-mine.com +~~~ + +~~~bash +docker exec -ti mailserver setup config dkim +~~~ + # Buy me a coffe Buy Me a Coffee at ko-fi.com \ No newline at end of file diff --git a/setup.sh b/setup.sh new file mode 100644 index 0000000..6a89a43 --- /dev/null +++ b/setup.sh @@ -0,0 +1,201 @@ +#!/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='ghcr.io/docker-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 "${@}"