chore: bump mail server to 10.2.0
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/pr Build is passing Details

pull/7/head
Davide Polonio 2021-10-14 13:04:17 +00:00
parent 783a3060a3
commit e2dbd48835
2 changed files with 136 additions and 316 deletions

View File

@ -2,7 +2,7 @@
version: '3.7' version: '3.7'
services: services:
mail: mail:
image: mailserver/docker-mailserver:10.1.2 image: mailserver/docker-mailserver:10.2.0
hostname: ${HOSTNAME} hostname: ${HOSTNAME}
domainname: ${DOMAINNAME} domainname: ${DOMAINNAME}
container_name: ${CONTAINER_NAME} container_name: ${CONTAINER_NAME}

450
mail/setup.sh Executable file → Normal file
View File

@ -1,162 +1,62 @@
#! /bin/bash #! /bin/bash
# version v0.3.0 stable # version v1.0.0
# executed manually / via Make # executed manually / via Make
# task wrapper for various setup scripts # task wrapper for various setup scripts
SCRIPT='setup.sh' CONFIG_PATH=
CONTAINER_NAME=
CRI=
DEFAULT_CONFIG_PATH=
DESIRED_CONFIG_PATH=
DIR="$(pwd)"
DMS_CONFIG='/tmp/docker-mailserver'
IMAGE_NAME=
INFO=
PODMAN_ROOTLESS=false
USE_SELINUX=
USE_TTY=
VOLUME=
RED="\e[31m\e[1m"
WHITE="\e[37m" WHITE="\e[37m"
RED="\e[31m"
PURPLE="\e[35m"
YELLOW="\e[93m"
ORANGE="\e[38;5;214m" ORANGE="\e[38;5;214m"
CYAN="\e[96m"
BLUE="\e[34m"
LBLUE="\e[94m" LBLUE="\e[94m"
BOLD="\e[1m"
RESET="\e[0m" RESET="\e[0m"
set -euEo pipefail set -euEo pipefail
trap '__log_err "${FUNCNAME[0]:-?}" "${BASH_COMMAND:-?}" "${LINENO:-?}" "${?:-?}"' ERR trap '__err "${BASH_SOURCE}" "${FUNCNAME[0]:-?}" "${BASH_COMMAND:-?}" "${LINENO:-?}" "${?:-?}"' ERR
function __log_err function __err
{ {
printf "\n--- ${BOLD}${RED}UNCHECKED ERROR${RESET}\n%s\n%s\n%s\n%s\n\n" \ [[ ${5} -gt 1 ]] && exit 1
" - script = ${SCRIPT:-${0}}" \
" - function = ${1} / ${2}" \
" - line = ${3}" \
" - exit code = ${4}" >&2
printf "Make sure you use a version of this script that matches local ERR_MSG="\n--- ${RED}UNCHECKED ERROR${RESET}"
the version / tag of docker-mailserver. Please read the ERR_MSG+="\n - script = ${1}"
'Get the tools' section in the README on GitHub careful- ERR_MSG+="\n - function = ${2}"
ly and use ./setup.sh help and read the VERSION section.\n" >&2 ERR_MSG+="\n - command = ${3}"
ERR_MSG+="\n - line = ${4}"
ERR_MSG+="\n - exit code = ${5}"
ERR_MSG+='\n\nThis should not have happened. Please file a bug report.\n'
echo -e "${ERR_MSG}"
} }
function _get_absolute_script_directory function _show_local_usage
{
if [[ "$(uname)" == "Darwin" ]]
then
readlink() {
greadlink "${@:+$@}" # Requires coreutils
}
fi
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
}
DIR="$(pwd)"
_get_absolute_script_directory
CRI=
CONFIG_PATH=
CONTAINER_NAME=
DEFAULT_CONFIG_PATH="${DIR}/config"
IMAGE_NAME=
INFO=
USE_CONTAINER=false
USE_TTY=
USE_SELINUX=
VOLUME=
WISHED_CONFIG_PATH=
function _check_root
{
if [[ ${EUID} -ne 0 ]]
then
echo "Curently docker-mailserver doesn't support podman's rootless mode, please run this script as root user."
exit 1
fi
}
function _update_config_path
{
if [[ -n ${CONTAINER_NAME} ]]
then
VOLUME=$(${CRI} inspect "${CONTAINER_NAME}" \
--format="{{range .Mounts}}{{ println .Source .Destination}}{{end}}" | \
grep "/tmp/docker-mailserver$" 2>/dev/null)
fi
if [[ -n ${VOLUME} ]]
then
CONFIG_PATH=$(echo "${VOLUME}" | awk '{print $1}')
fi
}
function _inspect
{
if _docker_image_exists "${IMAGE_NAME}"
then
echo "Image: ${IMAGE_NAME}"
else
echo "Image: '${IMAGE_NAME}' cant be found."
fi
if [[ -n ${CONTAINER_NAME} ]]
then
echo "Container: ${CONTAINER_NAME}"
echo "Config mount: ${CONFIG_PATH}"
else
echo "Container: Not running, please start docker-mailserver."
fi
}
function _usage
{ {
# shellcheck disable=SC2059 # shellcheck disable=SC2059
printf "${PURPLE}SETUP${RED}(${YELLOW}1${RED}) printf "${ORANGE}OPTIONS${RESET}
${ORANGE}NAME${RESET}
${SCRIPT:-${0}} - docker-mailserver administration script
${ORANGE}SYNOPSIS${RESET}
./${SCRIPT:-${0}} [ OPTIONS${RED}...${RESET} ] COMMAND [ help ${RED}|${RESET} ARGUMENTS${RED}...${RESET} ]
COMMAND ${RED}:=${RESET} { email ${RED}|${RESET} alias ${RED}|${RESET} quota ${RED}|${RESET} config ${RED}|${RESET} relay ${RED}|${RESET} debug } SUBCOMMAND
${ORANGE}DESCRIPTION${RESET}
This is the main administration script that you use for all interactions with your
mail server. Setup, configuration and much more is done with this script.
Please note that the script executes most of the commands inside the container itself.
If the image was not found, this script will pull the ${WHITE}:latest${RESET} tag of
${WHITE}mailserver/docker-mailserver${RESET}. This tag refers to the latest release,
see the tagging convention in the README under
${BLUE}https://github.com/docker-mailserver/docker-mailserver/blob/master/README.md${RESET}
You will be able to see detailed information about the script you're invoking and
its arguments by appending ${WHITE}help${RESET} after your command. Currently, this
does not work with all scripts.
${ORANGE}VERSION${RESET}
The current version of this script is backwards compatible with versions of
${WHITE}docker-mailserver${RESET} ${BOLD}after${RESET} ${BLUE}8.0.1${RESET}. In case that there is not a more recent release,
this script is currently only working with the ${WHITE}:edge${RESET} tag.
You can download the script for your release by substituting TAG from the
following URL, where TAG looks like 'vX.X.X':
https://raw.githubusercontent.com/docker-mailserver/docker-mailserver/TAG/setup.sh
${ORANGE}OPTIONS${RESET}
${LBLUE}Config path, container or image adjustments${RESET} ${LBLUE}Config path, container or image adjustments${RESET}
-i IMAGE_NAME -i IMAGE_NAME
Provides the name of the docker-mailserver image. The default value is Provides the name of the 'docker-mailserver' image. The default value is
${WHITE}docker.io/mailserver/docker-mailserver:latest${RESET} '${WHITE}docker.io/mailserver/docker-mailserver:latest${RESET}'
-c CONTAINER_NAME -c CONTAINER_NAME
Provides the name of the running container. Provides the name of the running container.
-p PATH -p PATH
Provides the config folder path. The default is Provides the local path of the config folder to the temporary container instance.
${WHITE}${DIR}/config/${RESET} Does not work if an existing a 'docker-mailserver' container is already running.
${LBLUE}SELinux${RESET} ${LBLUE}SELinux${RESET}
-z -z
@ -167,52 +67,16 @@ ${ORANGE}OPTIONS${RESET}
Allows container access to the bind mount content that is private and Allows container access to the bind mount content that is private and
unshared with other containers on a SELinux-enabled host. unshared with other containers on a SELinux-enabled host.
${RED}[${ORANGE}SUB${RED}]${ORANGE}COMMANDS${RESET} ${LBLUE}Podman${RESET}
${LBLUE}COMMAND${RESET} email ${RED}:=${RESET} -R
${0} email ${CYAN}add${RESET} <EMAIL ADDRESS> [<PASSWORD>] Accept running in Podman rootless mode. Ignored when using Docker / Docker Compose.
${0} email ${CYAN}update${RESET} <EMAIL ADDRESS> [<PASSWORD>]
${0} email ${CYAN}del${RESET} [ OPTIONS${RED}...${RESET} ] <EMAIL ADDRESS> [ <EMAIL ADDRESS>${RED}...${RESET} ]
${0} email ${CYAN}restrict${RESET} <add${RED}|${RESET}del${RED}|${RESET}list> <send${RED}|${RESET}receive> [<EMAIL ADDRESS>]
${0} email ${CYAN}list${RESET}
${LBLUE}COMMAND${RESET} alias ${RED}:=${RESET} "
${0} alias ${CYAN}add${RESET} <EMAIL ADDRESS> <RECIPIENT>
${0} alias ${CYAN}del${RESET} <EMAIL ADDRESS> <RECIPIENT>
${0} alias ${CYAN}list${RESET}
${LBLUE}COMMAND${RESET} quota ${RED}:=${RESET} [[ ${1:-} == 'no-exit' ]] && return 0
${0} quota ${CYAN}set${RESET} <EMAIL ADDRESS> [<QUOTA>]
${0} quota ${CYAN}del${RESET} <EMAIL ADDRESS>
${LBLUE}COMMAND${RESET} config ${RED}:=${RESET} # shellcheck disable=SC2059
${0} config ${CYAN}dkim${RESET} [ ARGUMENTS${RED}...${RESET} ] printf "${ORANGE}EXIT STATUS${RESET}
${LBLUE}COMMAND${RESET} relay ${RED}:=${RESET}
${0} relay ${CYAN}add-domain${RESET} <DOMAIN> <HOST> [<PORT>]
${0} relay ${CYAN}add-auth${RESET} <DOMAIN> <USERNAME> [<PASSWORD>]
${0} relay ${CYAN}exclude-domain${RESET} <DOMAIN>
${LBLUE}COMMAND${RESET} debug ${RED}:=${RESET}
${0} debug ${CYAN}fetchmail${RESET}
${0} debug ${CYAN}fail2ban${RESET} [unban <IP>]
${0} debug ${CYAN}show-mail-logs${RESET}
${0} debug ${CYAN}inspect${RESET}
${0} debug ${CYAN}login${RESET} <COMMANDS>
${ORANGE}EXAMPLES${RESET}
${WHITE}./setup.sh email add test@domain.tld${RESET}
Add the email account ${WHITE}test@domain.tld${RESET}. You will be prompted
to input a password afterwards since no password was supplied.
${WHITE}./setup.sh config dkim keysize 2048 domain 'whoami.com,whoareyou.org'${RESET}
Creates keys of length 2048 but in an LDAP setup where domains are not known to
Postfix by default, so you need to provide them yourself in a comma-separated list.
${WHITE}./setup.sh config dkim help${RESET}
This will provide you with a detailed explanation on how to use the ${WHITE}
config dkim${RESET} command, showing what arguments can be passed and what they do.
${ORANGE}EXIT STATUS${RESET}
Exit status is 0 if the command was successful. If there was an unexpected error, an error 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 message is shown describing the error. In case of an error, the script will exit with exit
status 1. status 1.
@ -220,63 +84,125 @@ ${ORANGE}EXIT STATUS${RESET}
" "
} }
function _docker_image_exists function _get_absolute_script_directory
{ {
${CRI} history -q "${1}" &>/dev/null if [[ "$(uname)" == 'Darwin' ]]
return ${?} then
readlink() {
# requires coreutils
greadlink "${@:+$@}"
}
fi
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
DEFAULT_CONFIG_PATH="${DIR}/config"
} }
function _docker_image function _handle_config_path
{ {
if ${USE_CONTAINER} if [[ -z ${DESIRED_CONFIG_PATH} ]]
then then
# reuse existing container specified on command line # no desired config path
${CRI} exec "${USE_TTY}" "${CONTAINER_NAME}" "${@:+$@}" if [[ -n ${CONTAINER_NAME} ]]
else
# start temporary container with specified image
if ! _docker_image_exists "${IMAGE_NAME}"
then then
echo "Image '${IMAGE_NAME}' not found. Pulling ..." VOLUME=$(${CRI} inspect "${CONTAINER_NAME}" \
${CRI} pull "${IMAGE_NAME}" --format="{{range .Mounts}}{{ println .Source .Destination}}{{end}}" | \
grep "${DMS_CONFIG}$" 2>/dev/null || :)
fi fi
${CRI} run --rm \ if [[ -n ${VOLUME} ]]
-v "${CONFIG_PATH}:/tmp/docker-mailserver${USE_SELINUX}" \ then
"${USE_TTY}" "${IMAGE_NAME}" "${@:+$@}" 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 fi
} }
function _docker_container function _run_in_new_container
{ {
if [[ -n ${CONTAINER_NAME} ]] # start temporary container with specified image
if ! ${CRI} history -q "${IMAGE_NAME}" &>/dev/null
then then
${CRI} exec "${USE_TTY}" "${CONTAINER_NAME}" "${@:+$@}" echo "Image '${IMAGE_NAME}' not found. Pulling ..."
else ${CRI} pull "${IMAGE_NAME}"
echo "The mailserver is not running!"
exit 1
fi fi
${CRI} run --rm "${USE_TTY}" \
-v "${CONFIG_PATH}:${DMS_CONFIG}${USE_SELINUX}" \
"${IMAGE_NAME}" "${@:+$@}"
} }
function _main function _main
{ {
_get_absolute_script_directory
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 if command -v docker &>/dev/null
then then
CRI=docker CRI=docker
elif command -v podman &>/dev/null elif command -v podman &>/dev/null
then then
CRI=podman CRI=podman
_check_root 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 else
echo "No supported Container Runtime Interface detected." echo 'No supported Container Runtime Interface detected.'
exit 10 exit 1
fi fi
INFO=$(${CRI} ps --no-trunc --format "{{.Image}};{{.Names}}" --filter \ INFO=$(${CRI} ps --no-trunc --format "{{.Image}};{{.Names}}" --filter \
label=org.opencontainers.image.title="docker-mailserver" | tail -1) label=org.opencontainers.image.title="docker-mailserver" | tail -1)
IMAGE_NAME=${INFO%;*}
CONTAINER_NAME=${INFO#*;} CONTAINER_NAME=${INFO#*;}
[[ -z ${IMAGE_NAME} ]] && IMAGE_NAME=${INFO%;*}
if [[ -z ${IMAGE_NAME} ]] if [[ -z ${IMAGE_NAME} ]]
then then
IMAGE_NAME=${NAME:-docker.io/mailserver/docker-mailserver:latest} IMAGE_NAME=${NAME:-docker.io/mailserver/docker-mailserver:latest}
@ -284,7 +210,7 @@ function _main
if test -t 0 if test -t 0
then then
USE_TTY="-ti" USE_TTY="-it"
else else
# GitHub Actions will fail (or really anything else # GitHub Actions will fail (or really anything else
# lacking an interactive tty) if we don't set a # lacking an interactive tty) if we don't set a
@ -292,124 +218,18 @@ function _main
USE_TTY="-t" USE_TTY="-t"
fi fi
local OPTIND _handle_config_path
while getopts ":c:i:p:hzZ" OPT
do
case ${OPT} in
i ) IMAGE_NAME="${OPTARG}" ;;
z ) USE_SELINUX=":z" ;;
Z ) USE_SELINUX=":Z" ;;
c )
# container specified, connect to running instance
CONTAINER_NAME="${OPTARG}"
USE_CONTAINER=true
;;
p ) if [[ -n ${CONTAINER_NAME} ]]
case "${OPTARG}" in
/* ) WISHED_CONFIG_PATH="${OPTARG}" ;;
* ) WISHED_CONFIG_PATH="${DIR}/${OPTARG}" ;;
esac
if [[ ! -d ${WISHED_CONFIG_PATH} ]]
then
echo "Directory doesn't exist"
_usage
exit 40
fi
;;
* )
echo "Invalid option: -${OPT}" >&2
;;
esac
done
shift $(( OPTIND - 1 ))
if [[ -z ${WISHED_CONFIG_PATH} ]]
then then
# no wished config path ${CRI} exec "${USE_TTY}" "${CONTAINER_NAME}" setup "${@:+$@}"
_update_config_path
if [[ -z ${CONFIG_PATH} ]]
then
CONFIG_PATH=${DEFAULT_CONFIG_PATH}
fi
else else
CONFIG_PATH=${WISHED_CONFIG_PATH} _run_in_new_container setup "${@:+$@}"
fi fi
[[ ${1} == 'help' ]] && _show_local_usage
case ${1:-} in return 0
email )
case ${2:-} in
add ) shift 2 ; _docker_image addmailuser "${@:+$@}" ;;
update ) shift 2 ; _docker_image updatemailuser "${@:+$@}" ;;
del ) shift 2 ; _docker_container delmailuser "${@:+$@}" ;;
restrict ) shift 2 ; _docker_container restrict-access "${@:+$@}" ;;
list ) _docker_container listmailuser ;;
* ) _usage ;;
esac
;;
alias )
case ${2:-} in
add ) shift 2 ; _docker_image addalias "${1}" "${2}" ;;
del ) shift 2 ; _docker_image delalias "${1}" "${2}" ;;
list ) shift 2 ; _docker_image listalias ;;
* ) _usage ;;
esac
;;
quota )
case ${2:-} in
set ) shift 2 ; _docker_image setquota "${@:+$@}" ;;
del ) shift 2 ; _docker_image delquota "${@:+$@}" ;;
* ) _usage ;;
esac
;;
config )
case ${2:-} in
dkim ) shift 2 ; _docker_image open-dkim "${@:+$@}" ;;
* ) _usage ;;
esac
;;
relay )
case ${2:-} in
add-domain ) shift 2 ; _docker_image addrelayhost "${@:+$@}" ;;
add-auth ) shift 2 ; _docker_image addsaslpassword "${@:+$@}" ;;
exclude-domain ) shift 2 ; _docker_image excluderelaydomain "${@:+$@}" ;;
* ) _usage ;;
esac
;;
debug )
case ${2:-} in
fetchmail ) _docker_image debug-fetchmail ;;
fail2ban ) shift 2 ; _docker_container fail2ban "${@:+$@}" ;;
show-mail-logs ) _docker_container cat /var/log/mail/mail.log ;;
inspect ) _inspect ;;
login )
shift 2
if [[ -z ${1:-} ]]
then
_docker_container /bin/bash
else
_docker_container /bin/bash -c "${@:+$@}"
fi
;;
* ) _usage ; exit 1 ;;
esac
;;
help ) _usage ;;
* ) _usage ; exit 1 ;;
esac
} }
_main "${@:+$@}" _main "${@:+$@}"