2019-01-27 20:40:11 +02:00
#!/usr/bin/env bash
2017-06-19 23:31:43 +02:00
2019-01-29 13:13:04 +02:00
# Check permissions
if [ " $( id -u) " -ne "0" ] ; then
echo "You need to be root"
exit 1
fi
2021-07-31 00:21:15 +02:00
SCRIPT_DIR = " $( cd " $( dirname " ${ BASH_SOURCE [0] } " ) " && pwd ) "
# Run pre-update-hook
if [ -f " ${ SCRIPT_DIR } /pre_update_hook.sh " ] ; then
bash " ${ SCRIPT_DIR } /pre_update_hook.sh "
fi
2019-09-03 22:01:47 +02:00
if [ [ " $( uname -r) " = ~ ^4\. 15\. 0-60 ] ] ; then
echo "DO NOT RUN mailcow ON THIS UBUNTU KERNEL!" ;
echo "Please update to 5.x or use another distribution."
exit 1
fi
2019-12-05 15:27:51 +02:00
if [ [ " $( uname -r) " = ~ ^4\. 4\. ] ] ; then
if grep -q Ubuntu <<< $( uname -a) ; then
2019-12-18 22:35:17 +02:00
echo "DO NOT RUN mailcow ON THIS UBUNTU KERNEL!"
2019-12-05 15:27:51 +02:00
echo "Please update to linux-generic-hwe-16.04 by running \"apt-get install --install-recommends linux-generic-hwe-16.04\""
2019-12-18 22:35:17 +02:00
exit 1
2019-12-05 15:27:51 +02:00
fi
2019-12-18 22:35:17 +02:00
echo "mailcow on a 4.4.x kernel is not supported. It may or may not work, please upgrade your kernel or continue at your own risk."
read -p "Press any key to continue..." < /dev/tty
2019-12-05 15:27:51 +02:00
fi
2019-03-03 00:48:20 +02:00
# Exit on error and pipefail
2018-02-20 10:31:01 +02:00
set -o pipefail
2019-05-25 22:29:25 +02:00
# Setting high dc timeout
2019-05-25 22:37:51 +02:00
export COMPOSE_HTTP_TIMEOUT = 600
2019-05-25 22:29:25 +02:00
2019-03-03 00:48:20 +02:00
# Add /opt/bin to PATH
PATH = $PATH :/opt/bin
2018-07-13 13:06:56 +02:00
umask 0022
2017-09-08 10:02:50 +02:00
for bin in curl docker-compose docker git awk sha1sum; do
2018-01-24 10:24:40 +02:00
if [ [ -z $( which ${ bin } ) ] ] ; then echo " Cannot find ${ bin } , exiting... " ; exit 1; fi
2017-09-08 10:02:50 +02:00
done
2017-06-24 00:04:05 +02:00
2018-02-01 10:40:08 +02:00
export LC_ALL = C
DATE = $( date +%Y-%m-%d_%H_%M_%S)
BRANCH = $( git rev-parse --abbrev-ref HEAD)
2020-05-16 08:37:07 +02:00
check_online_status( ) {
CHECK_ONLINE_IPS = ( 1.1.1.1 9.9.9.9 8.8.8.8)
for ip in " ${ CHECK_ONLINE_IPS [@] } " ; do
if timeout 3 ping -c 1 ${ ip } > /dev/null; then
return 0
fi
done
return 1
}
prefetch_images( ) {
2019-07-08 18:45:57 +02:00
[ [ -z ${ BRANCH } ] ] && { echo -e "\e[33m\nUnknown branch...\e[0m" ; exit 1; }
2019-08-04 09:23:19 +02:00
git fetch origin #${BRANCH}
2019-07-08 18:45:57 +02:00
while read image; do
RET_C = 0
until docker pull ${ image } ; do
RET_C = $(( RET_C + 1 ))
echo -e " \e[33m\nError pulling $image , retrying...\e[0m "
[ ${ RET_C } -gt 3 ] && { echo -e "\e[31m\nToo many failed retries, exiting\e[0m" ; exit 1; }
sleep 1
done
done < <( git show origin/${ BRANCH } :docker-compose.yml | grep "image:" | awk '{ gsub("image:","", $3); print $2 }' )
2019-07-08 18:42:51 +02:00
}
2018-07-25 01:08:12 +02:00
docker_garbage( ) {
IMGS_TO_DELETE = ( )
for container in $( grep -oP "image: \Kmailcow.+" docker-compose.yml) ; do
REPOSITORY = ${ container / : * }
TAG = ${ container /* : }
V_MAIN = ${ container /*. }
V_SUB = ${ container /*. }
EXISTING_TAGS = $( docker images | grep ${ REPOSITORY } | awk '{ print $2 }' )
for existing_tag in ${ EXISTING_TAGS [@] } ; do
V_MAIN_EXISTING = ${ existing_tag /*. }
V_SUB_EXISTING = ${ existing_tag /*. }
# Not an integer
[ [ ! $V_MAIN_EXISTING = ~ ^[ 0-9] +$ ] ] && continue
[ [ ! $V_SUB_EXISTING = ~ ^[ 0-9] +$ ] ] && continue
if [ [ $V_MAIN_EXISTING = = "latest" ] ] ; then
echo " Found deprecated label \"latest\" for repository $REPOSITORY , it should be deleted. "
IMGS_TO_DELETE += ( $REPOSITORY :$existing_tag )
elif [ [ $V_MAIN_EXISTING -lt $V_MAIN ] ] ; then
echo " Found tag $existing_tag for $REPOSITORY , which is older than the current tag $TAG and should be deleted. "
IMGS_TO_DELETE += ( $REPOSITORY :$existing_tag )
elif [ [ $V_SUB_EXISTING -lt $V_SUB ] ] ; then
echo " Found tag $existing_tag for $REPOSITORY , which is older than the current tag $TAG and should be deleted. "
IMGS_TO_DELETE += ( $REPOSITORY :$existing_tag )
fi
done
done
if [ [ ! -z ${ IMGS_TO_DELETE [*] } ] ] ; then
echo "Run the following command to delete unused image tags:"
echo
echo " docker rmi ${ IMGS_TO_DELETE [*] } "
echo
2020-04-07 13:28:51 +02:00
if [ ! $FORCE ] ; then
read -r -p "Do you want to delete old image tags right now? [y/N] " response
if [ [ " $response " = ~ ^( [ yY] [ eE] [ sS] | [ yY] ) +$ ] ] ; then
docker rmi ${ IMGS_TO_DELETE [*] }
else
echo "OK, skipped."
fi
2018-07-25 01:08:12 +02:00
else
2021-06-17 06:26:59 +02:00
echo "Running image removal without extra confirmation due to force mode."
docker rmi ${ IMGS_TO_DELETE [*] }
2018-07-25 01:08:12 +02:00
fi
fi
echo -e "\e[32mFurther cleanup...\e[0m"
echo "If you want to cleanup further garbage collected by Docker, please make sure all containers are up and running before cleaning your system by executing \"docker system prune\""
}
2021-06-21 22:04:32 +02:00
in_array( ) {
local e match = " $1 "
shift
for e; do [ [ " $e " = = " $match " ] ] && return 0; done
return 1
}
migrate_docker_nat( ) {
NAT_CONFIG = '{"ipv6":true,"fixed-cidr-v6":"fd00:dead:beef:c0::/80","experimental":true,"ip6tables":true}'
# Min Docker version
DOCKERV_REQ = 20.10.2
# Current Docker version
DOCKERV_CUR = $( docker version -f '{{.Server.Version}}' )
if grep -qi "ipv6nat-mailcow" docker-compose.yml; then
echo -e "\e[32mNative IPv6 implementation available.\e[0m"
2021-08-02 19:19:07 +02:00
echo "This will enable experimental features in the Docker daemon and configure Docker to do the IPv6 NATing instead of ipv6nat-mailcow."
echo '!!! This step is recommended !!!'
2021-06-21 22:04:32 +02:00
echo "mailcow will try to roll back the changes if starting Docker fails after modifying the daemon.json configuration file."
read -r -p "Should we try to enable the native IPv6 implementation in Docker now (recommended)? [y/N] " dockernatresponse
if [ [ ! " ${ dockernatresponse } " = ~ ^( [ yY] [ eE] [ sS] | [ yY] ) +$ ] ] ; then
echo "OK, skipping this step."
return 0
fi
fi
# Sort versions and check if we are running a newer or equal version to req
if [ $( printf " ${ DOCKERV_REQ } \n ${ DOCKERV_CUR } " | sort -V | tail -n1) = = " ${ DOCKERV_CUR } " ] ; then
# If Dockerd daemon json exists
if [ -s /etc/docker/daemon.json ] ; then
IFS = ',' read -r -a dockerconfig <<< $( cat /etc/docker/daemon.json | tr -cd '[:alnum:],' )
if ! in_array ipv6true " ${ dockerconfig [@] } " || \
! in_array experimentaltrue " ${ dockerconfig [@] } " || \
! in_array ip6tablestrue " ${ dockerconfig [@] } " || \
! grep -qi "fixed-cidr-v6" /etc/docker/daemon.json; then
echo -e "\e[33mWarning:\e[0m You seem to have modified the /etc/docker/daemon.json configuration by yourself and not fully/correctly activated the native IPv6 NAT implementation."
echo "You will need to merge your existing configuration manually or fix/delete the existing daemon.json configuration before trying the update process again."
echo -e "Please merge the following content and restart the Docker daemon:\n"
echo ${ NAT_CONFIG }
return 1
fi
else
echo "Working on IPv6 NAT, please wait..."
echo ${ NAT_CONFIG } > /etc/docker/daemon.json
ip6tables -F -t nat
if ! systemctl restart docker.service; then
echo -e "\e[31mError:\e[0m Failed to activate IPv6 NAT! Reverting and exiting."
rm /etc/docker/daemon.json
systemctl reset-failed docker.service
systemctl restart docker.service
return 1
fi
fi
# Removing legacy container
sed -i '/ipv6nat-mailcow:$/,/^$/d' docker-compose.yml
echo -e "\e[32mGreat! \e[0mNative IPv6 NAT is active.\e[0m"
else
echo -e " \e[31mPlease upgrade Docker to version ${ DOCKERV_REQ } or above.\e[0m "
return 0
fi
}
2018-02-01 10:40:08 +02:00
while ( ( $# ) ) ; do
case " ${ 1 } " in
--check| -c)
echo "Checking remote code for updates..."
2018-11-16 13:09:55 +02:00
LATEST_REV = $( git ls-remote --exit-code --refs --quiet https://github.com/mailcow/mailcow-dockerized ${ BRANCH } | cut -f1)
if [ $? -ne 0 ] ; then
echo "A problem occurred while trying to fetch the latest revision from github."
exit 99
2019-03-12 18:21:45 +02:00
fi
2018-11-16 13:09:55 +02:00
if [ [ -z $( git log HEAD --pretty= format:"%H" | grep " ${ LATEST_REV } " ) ] ] ; then
2021-06-01 12:09:34 +02:00
echo -e "Updated code is available.\nThe changes can be found here: https://github.com/mailcow/mailcow-dockerized/commits/master"
2020-10-09 11:04:42 +02:00
git log --date= short --pretty= format:"%ad - %s" $( git rev-parse --short HEAD) ..origin/master
2018-02-01 10:40:08 +02:00
exit 0
else
echo "No updates available."
exit 3
fi
; ;
--ours)
MERGE_STRATEGY = ours
; ;
2020-02-11 12:25:38 +02:00
--skip-start)
SKIP_START = y
; ;
2018-07-25 01:08:12 +02:00
--gc)
2018-10-03 12:34:10 +02:00
echo -e "\e[32mCollecting garbage...\e[0m"
2018-07-25 01:08:12 +02:00
docker_garbage
exit 0
; ;
2019-07-08 18:42:51 +02:00
--prefetch)
echo -e "\e[32mPrefetching images...\e[0m"
prefetch_images
exit 0
; ;
2020-04-07 13:28:51 +02:00
-f| --force)
echo -e "\e[32mForcing Update...\e[0m"
FORCE = y
; ;
2020-05-29 19:47:44 +02:00
--no-update-compose)
NO_UPDATE_COMPOSE = y
; ;
2018-07-25 01:08:12 +02:00
--help| -h)
2020-10-02 22:27:26 +02:00
echo ' ./update.sh [ -c| --check, --ours, --gc, --no-update-compose, --prefetch, --skip-start, -f| --force, -h| --help]
2018-07-25 01:08:12 +02:00
2020-05-29 19:47:44 +02:00
-c| --check - Check for updates and exit ( exit codes = > 0: update available, 3: no updates)
2020-05-30 22:28:17 +02:00
--ours - Use merge strategy option "ours" to solve conflicts in favor of non-mailcow code ( local changes over remote changes) , not recommended!
2020-05-29 19:47:44 +02:00
--gc - Run garbage collector to delete old image tags
--no-update-compose - Do not update docker-compose
--prefetch - Only prefetch new images and exit ( useful to prepare updates)
--skip-start - Do not start mailcow after update
-f| --force - Force update, do not ask questions
2018-07-25 01:08:12 +02:00
'
exit 1
2018-02-01 10:40:08 +02:00
esac
2018-07-04 15:10:30 +02:00
shift
2018-02-01 10:40:08 +02:00
done
2018-01-08 23:00:54 +02:00
[ [ ! -f mailcow.conf ] ] && { echo "mailcow.conf is missing" ; exit 1; }
2019-03-13 00:23:38 +02:00
chmod 600 mailcow.conf
2018-07-11 19:59:21 +02:00
source mailcow.conf
DOTS = ${ MAILCOW_HOSTNAME //[^.] } ;
if [ ${# DOTS } -lt 2 ] ; then
echo " MAILCOW_HOSTNAME ( ${ MAILCOW_HOSTNAME } ) is not a FQDN! "
echo "Please change it to a FQDN and run docker-compose down followed by docker-compose up -d"
exit 1
fi
2018-01-08 23:00:54 +02:00
2020-11-22 00:28:53 +02:00
if grep --help 2>& 1 | head -n 1 | grep -q -i "busybox" ; then echo "BusyBox grep detected, please install gnu grep, \"apk add --no-cache --upgrade grep\"" ; exit 1; fi
2021-06-21 22:04:32 +02:00
# This will also cover sort
2020-11-22 00:28:53 +02:00
if cp --help 2>& 1 | head -n 1 | grep -q -i "busybox" ; then echo "BusyBox cp detected, please install coreutils, \"apk add --no-cache --upgrade coreutils\"" ; exit 1; fi
if sed --help 2>& 1 | head -n 1 | grep -q -i "busybox" ; then echo "BusyBox sed detected, please install gnu sed, \"apk add --no-cache --upgrade sed\"" ; exit 1; fi
2018-02-20 10:31:01 +02:00
2018-02-01 10:40:08 +02:00
CONFIG_ARRAY = (
"SKIP_LETS_ENCRYPT"
2020-04-27 17:27:47 +02:00
"SKIP_SOGO"
2018-02-01 10:40:08 +02:00
"USE_WATCHDOG"
"WATCHDOG_NOTIFY_EMAIL"
2019-06-15 21:55:23 +02:00
"WATCHDOG_NOTIFY_BAN"
2020-01-25 21:41:22 +02:00
"WATCHDOG_EXTERNAL_CHECKS"
2021-03-13 13:36:29 +02:00
"WATCHDOG_SUBJECT"
2018-02-01 10:40:08 +02:00
"SKIP_CLAMD"
"SKIP_IP_CHECK"
"ADDITIONAL_SAN"
"DOVEADM_PORT"
"IPV4_NETWORK"
"IPV6_NETWORK"
"LOG_LINES"
"SNAT_TO_SOURCE"
2018-07-11 19:41:04 +02:00
"SNAT6_TO_SOURCE"
2018-04-27 21:00:06 +02:00
"COMPOSE_PROJECT_NAME"
2018-04-29 09:27:29 +02:00
"SQL_PORT"
2018-06-08 09:11:03 +02:00
"API_KEY"
2020-04-11 20:57:35 +02:00
"API_KEY_READ_ONLY"
2018-06-08 09:11:03 +02:00
"API_ALLOW_FROM"
2018-10-02 21:24:22 +02:00
"MAILDIR_GC_TIME"
2019-03-18 20:49:05 +02:00
"MAILDIR_SUB"
2018-11-18 14:31:09 +02:00
"ACL_ANYONE"
2019-01-16 11:50:34 +02:00
"SOLR_HEAP"
"SKIP_SOLR"
2019-10-19 13:00:01 +02:00
"ENABLE_SSL_SNI"
2019-02-23 18:59:18 +02:00
"ALLOW_ADMIN_EMAIL_LOGIN"
2019-03-29 08:48:31 +02:00
"SKIP_HTTP_VERIFICATION"
2019-07-21 13:07:48 +02:00
"SOGO_EXPIRE_SESSION"
2020-03-19 13:19:17 +02:00
"REDIS_PORT"
2020-10-20 15:43:02 +02:00
"DOVECOT_MASTER_USER"
"DOVECOT_MASTER_PASS"
2020-11-15 21:22:35 +02:00
"MAILCOW_PASS_SCHEME"
2021-02-16 17:38:28 +02:00
"ADDITIONAL_SERVER_NAMES"
2021-04-29 23:32:42 +02:00
"ACME_CONTACT"
2018-02-01 10:40:08 +02:00
)
2020-09-20 22:07:37 +02:00
sed -i --follow-symlinks '$a\' mailcow.conf
2017-07-04 21:28:27 +02:00
for option in ${ CONFIG_ARRAY [@] } ; do
2018-01-24 10:24:40 +02:00
if [ [ ${ option } = = "ADDITIONAL_SAN" ] ] ; then
if ! grep -q ${ option } mailcow.conf; then
echo " Adding new option \" ${ option } \" to mailcow.conf "
echo " ${ option } = " >> mailcow.conf
fi
elif [ [ ${ option } = = "COMPOSE_PROJECT_NAME" ] ] ; then
if ! grep -q ${ option } mailcow.conf; then
echo " Adding new option \" ${ option } \" to mailcow.conf "
2018-04-13 14:13:24 +02:00
echo "COMPOSE_PROJECT_NAME=mailcowdockerized" >> mailcow.conf
2018-01-24 10:24:40 +02:00
fi
elif [ [ ${ option } = = "DOVEADM_PORT" ] ] ; then
if ! grep -q ${ option } mailcow.conf; then
echo " Adding new option \" ${ option } \" to mailcow.conf "
echo "DOVEADM_PORT=127.0.0.1:19991" >> mailcow.conf
fi
elif [ [ ${ option } = = "WATCHDOG_NOTIFY_EMAIL" ] ] ; then
if ! grep -q ${ option } mailcow.conf; then
echo " Adding new option \" ${ option } \" to mailcow.conf "
echo "WATCHDOG_NOTIFY_EMAIL=" >> mailcow.conf
fi
2018-01-08 23:00:54 +02:00
elif [ [ ${ option } = = "LOG_LINES" ] ] ; then
if ! grep -q ${ option } mailcow.conf; then
echo " Adding new option \" ${ option } \" to mailcow.conf "
2018-01-24 10:24:40 +02:00
echo '# Max log lines per service to keep in Redis logs' >> mailcow.conf
2018-01-08 23:00:54 +02:00
echo "LOG_LINES=9999" >> mailcow.conf
fi
2018-01-24 10:24:40 +02:00
elif [ [ ${ option } = = "IPV4_NETWORK" ] ] ; then
if ! grep -q ${ option } mailcow.conf; then
echo " Adding new option \" ${ option } \" to mailcow.conf "
echo '# Internal IPv4 /24 subnet, format n.n.n. (expands to n.n.n.0/24)' >> mailcow.conf
echo "IPV4_NETWORK=172.22.1" >> mailcow.conf
fi
elif [ [ ${ option } = = "IPV6_NETWORK" ] ] ; then
if ! grep -q ${ option } mailcow.conf; then
echo " Adding new option \" ${ option } \" to mailcow.conf "
2018-02-01 10:40:08 +02:00
echo '# Internal IPv6 subnet in fc00::/7' >> mailcow.conf
2018-01-24 10:24:40 +02:00
echo "IPV6_NETWORK=fd4d:6169:6c63:6f77::/64" >> mailcow.conf
fi
2018-02-05 22:42:13 +02:00
elif [ [ ${ option } = = "SQL_PORT" ] ] ; then
if ! grep -q ${ option } mailcow.conf; then
echo " Adding new option \" ${ option } \" to mailcow.conf "
echo '# Bind SQL to 127.0.0.1 on port 13306' >> mailcow.conf
echo "SQL_PORT=127.0.0.1:13306" >> mailcow.conf
fi
2018-06-08 09:11:03 +02:00
elif [ [ ${ option } = = "API_KEY" ] ] ; then
if ! grep -q ${ option } mailcow.conf; then
echo " Adding new option \" ${ option } \" to mailcow.conf "
echo '# Create or override API key for web UI' >> mailcow.conf
echo "#API_KEY=" >> mailcow.conf
fi
2020-04-11 20:57:35 +02:00
elif [ [ ${ option } = = "API_KEY_READ_ONLY" ] ] ; then
if ! grep -q ${ option } mailcow.conf; then
echo " Adding new option \" ${ option } \" to mailcow.conf "
echo '# Create or override read-only API key for web UI' >> mailcow.conf
echo "#API_KEY_READ_ONLY=" >> mailcow.conf
fi
2018-06-08 09:11:03 +02:00
elif [ [ ${ option } = = "API_ALLOW_FROM" ] ] ; then
if ! grep -q ${ option } mailcow.conf; then
echo " Adding new option \" ${ option } \" to mailcow.conf "
echo '# Must be set for API_KEY to be active' >> mailcow.conf
2020-05-04 07:50:59 +02:00
echo '# IPs only, no networks (networks can be set via UI)' >> mailcow.conf
2018-06-08 09:11:03 +02:00
echo "#API_ALLOW_FROM=" >> mailcow.conf
fi
2018-02-01 10:40:08 +02:00
elif [ [ ${ option } = = "SNAT_TO_SOURCE" ] ] ; then
if ! grep -q ${ option } mailcow.conf; then
echo " Adding new option \" ${ option } \" to mailcow.conf "
2018-07-11 19:41:04 +02:00
echo '# Use this IPv4 for outgoing connections (SNAT)' >> mailcow.conf
2018-02-01 10:40:08 +02:00
echo "#SNAT_TO_SOURCE=" >> mailcow.conf
fi
2018-07-11 19:41:04 +02:00
elif [ [ ${ option } = = "SNAT6_TO_SOURCE" ] ] ; then
if ! grep -q ${ option } mailcow.conf; then
echo " Adding new option \" ${ option } \" to mailcow.conf "
echo '# Use this IPv6 for outgoing connections (SNAT)' >> mailcow.conf
echo "#SNAT6_TO_SOURCE=" >> mailcow.conf
fi
2018-09-30 14:49:19 +02:00
elif [ [ ${ option } = = "MAILDIR_GC_TIME" ] ] ; then
if ! grep -q ${ option } mailcow.conf; then
echo " Adding new option \" ${ option } \" to mailcow.conf "
echo '# Garbage collector cleanup' >> mailcow.conf
echo '# Deleted domains and mailboxes are moved to /var/vmail/_garbage/timestamp_sanitizedstring' >> mailcow.conf
echo '# How long should objects remain in the garbage until they are being deleted? (value in minutes)' >> mailcow.conf
2018-10-02 09:32:51 +02:00
echo '# Check interval is hourly' >> mailcow.conf
2018-09-30 14:49:19 +02:00
echo 'MAILDIR_GC_TIME=1440' >> mailcow.conf
fi
2018-11-18 14:31:09 +02:00
elif [ [ ${ option } = = "ACL_ANYONE" ] ] ; then
if ! grep -q ${ option } mailcow.conf; then
echo " Adding new option \" ${ option } \" to mailcow.conf "
2019-01-17 20:44:52 +02:00
echo '# Set this to "allow" to enable the anyone pseudo user. Disabled by default.' >> mailcow.conf
echo '# When enabled, ACL can be created, that apply to "All authenticated users"' >> mailcow.conf
echo '# This should probably only be activated on mail hosts, that are used exclusivly by one organisation.' >> mailcow.conf
echo '# Otherwise a user might share data with too many other users.' >> mailcow.conf
2018-11-18 14:31:09 +02:00
echo 'ACL_ANYONE=disallow' >> mailcow.conf
fi
2019-01-16 11:50:34 +02:00
elif [ [ ${ option } = = "SOLR_HEAP" ] ] ; then
if ! grep -q ${ option } mailcow.conf; then
echo " Adding new option \" ${ option } \" to mailcow.conf "
echo '# Solr heap size, there is no recommendation, please see Solr docs.' >> mailcow.conf
2019-01-17 20:44:52 +02:00
echo '# Solr is a prone to run OOM on large systems and should be monitored. Unmonitored Solr setups are not recommended.' >> mailcow.conf
2019-01-17 21:25:38 +02:00
echo '# Solr will refuse to start with total system memory below or equal to 2 GB.' >> mailcow.conf
2019-01-16 11:50:34 +02:00
echo "SOLR_HEAP=1024" >> mailcow.conf
2021-02-16 17:51:07 +02:00
fi
2019-01-19 23:00:18 +02:00
elif [ [ ${ option } = = "SKIP_SOLR" ] ] ; then
if ! grep -q ${ option } mailcow.conf; then
echo " Adding new option \" ${ option } \" to mailcow.conf "
echo '# Solr is disabled by default after upgrading from non-Solr to Solr-enabled mailcows.' >> mailcow.conf
2019-01-29 14:29:30 +02:00
echo '# Disable Solr or if you do not want to store a readable index of your mails in solr-vol-1.' >> mailcow.conf
2019-01-19 23:00:18 +02:00
echo "SKIP_SOLR=y" >> mailcow.conf
2019-10-19 13:00:01 +02:00
fi
elif [ [ ${ option } = = "ENABLE_SSL_SNI" ] ] ; then
if ! grep -q ${ option } mailcow.conf; then
echo " Adding new option \" ${ option } \" to mailcow.conf "
echo '# Create seperate certificates for all domains - y/n' >> mailcow.conf
echo '# this will allow adding more than 100 domains, but some email clients will not be able to connect with alternative hostnames' >> mailcow.conf
echo '# see https://wiki.dovecot.org/SSL/SNIClientSupport' >> mailcow.conf
echo "ENABLE_SSL_SNI=n" >> mailcow.conf
fi
2020-04-29 10:11:22 +02:00
elif [ [ ${ option } = = "SKIP_SOGO" ] ] ; then
if ! grep -q ${ option } mailcow.conf; then
echo " Adding new option \" ${ option } \" to mailcow.conf "
echo '# Skip SOGo: Will disable SOGo integration and therefore webmail, DAV protocols and ActiveSync support (experimental, unsupported, not fully implemented) - y/n' >> mailcow.conf
echo "SKIP_SOGO=n" >> mailcow.conf
fi
2019-03-18 15:09:32 +02:00
elif [ [ ${ option } = = "MAILDIR_SUB" ] ] ; then
if ! grep -q ${ option } mailcow.conf; then
echo " Adding new option \" ${ option } \" to mailcow.conf "
echo '# MAILDIR_SUB defines a path in a users virtual home to keep the maildir in. Leave empty for updated setups.' >> mailcow.conf
2019-03-18 20:49:05 +02:00
echo "#MAILDIR_SUB=Maildir" >> mailcow.conf
2019-03-18 15:09:32 +02:00
echo "MAILDIR_SUB=" >> mailcow.conf
2021-02-16 17:51:07 +02:00
fi
2019-06-13 19:38:53 +02:00
elif [ [ ${ option } = = "WATCHDOG_NOTIFY_BAN" ] ] ; then
if ! grep -q ${ option } mailcow.conf; then
echo " Adding new option \" ${ option } \" to mailcow.conf "
echo '# Notify about banned IP. Includes whois lookup.' >> mailcow.conf
echo "WATCHDOG_NOTIFY_BAN=y" >> mailcow.conf
2021-02-16 17:51:07 +02:00
fi
2021-03-13 13:36:29 +02:00
elif [ [ ${ option } = = "WATCHDOG_SUBJECT" ] ] ; then
if ! grep -q ${ option } mailcow.conf; then
echo " Adding new option \" ${ option } \" to mailcow.conf "
echo '# Subject for watchdog mails. Defaults to "Watchdog ALERT" followed by the error message.' >> mailcow.conf
echo "#WATCHDOG_SUBJECT=" >> mailcow.conf
fi
2020-01-25 19:26:56 +02:00
elif [ [ ${ option } = = "WATCHDOG_EXTERNAL_CHECKS" ] ] ; then
if ! grep -q ${ option } mailcow.conf; then
echo " Adding new option \" ${ option } \" to mailcow.conf "
echo '# Checks if mailcow is an open relay. Requires a SAL. More checks will follow.' >> mailcow.conf
echo '# No data is collected. Opt-in and anonymous.' >> mailcow.conf
echo '# Will only work with unmodified mailcow setups.' >> mailcow.conf
echo "WATCHDOG_EXTERNAL_CHECKS=n" >> mailcow.conf
2021-02-16 17:51:07 +02:00
fi
2019-07-21 13:07:48 +02:00
elif [ [ ${ option } = = "SOGO_EXPIRE_SESSION" ] ] ; then
if ! grep -q ${ option } mailcow.conf; then
echo " Adding new option \" ${ option } \" to mailcow.conf "
echo '# SOGo session timeout in minutes' >> mailcow.conf
echo "SOGO_EXPIRE_SESSION=480" >> mailcow.conf
2021-02-16 17:51:07 +02:00
fi
2020-03-19 13:19:17 +02:00
elif [ [ ${ option } = = "REDIS_PORT" ] ] ; then
if ! grep -q ${ option } mailcow.conf; then
echo " Adding new option \" ${ option } \" to mailcow.conf "
echo "REDIS_PORT=127.0.0.1:7654" >> mailcow.conf
2021-02-16 17:51:07 +02:00
fi
2020-10-20 15:43:02 +02:00
elif [ [ ${ option } = = "DOVECOT_MASTER_USER" ] ] ; then
if ! grep -q ${ option } mailcow.conf; then
echo " Adding new option \" ${ option } \" to mailcow.conf "
2020-10-21 08:42:35 +02:00
echo '# DOVECOT_MASTER_USER and _PASS must _both_ be provided. No special chars.' >> mailcow.conf
2020-10-20 15:43:02 +02:00
echo '# Empty by default to auto-generate master user and password on start.' >> mailcow.conf
echo '# User expands to DOVECOT_MASTER_USER@mailcow.local' >> mailcow.conf
echo '# LEAVE EMPTY IF UNSURE' >> mailcow.conf
echo "DOVECOT_MASTER_USER=" >> mailcow.conf
2021-02-16 17:51:07 +02:00
fi
2020-10-20 15:43:02 +02:00
elif [ [ ${ option } = = "DOVECOT_MASTER_PASS" ] ] ; then
if ! grep -q ${ option } mailcow.conf; then
echo " Adding new option \" ${ option } \" to mailcow.conf "
echo '# LEAVE EMPTY IF UNSURE' >> mailcow.conf
echo "DOVECOT_MASTER_PASS=" >> mailcow.conf
2021-02-16 17:51:07 +02:00
fi
2020-11-15 21:22:35 +02:00
elif [ [ ${ option } = = "MAILCOW_PASS_SCHEME" ] ] ; then
if ! grep -q ${ option } mailcow.conf; then
echo " Adding new option \" ${ option } \" to mailcow.conf "
echo '# Password hash algorithm' >> mailcow.conf
echo '# Only certain password hash algorithm are supported. For a fully list of supported schemes,' >> mailcow.conf
echo '# see https://mailcow.github.io/mailcow-dockerized-docs/model-passwd/' >> mailcow.conf
echo "MAILCOW_PASS_SCHEME=BLF-CRYPT" >> mailcow.conf
2021-02-16 17:51:07 +02:00
fi
2021-02-16 17:38:28 +02:00
elif [ [ ${ option } = = "ADDITIONAL_SERVER_NAMES" ] ] ; then
if ! grep -q ${ option } mailcow.conf; then
echo '# Additional server names for mailcow UI' >> mailcow.conf
echo '#' >> mailcow.conf
echo '# Specify alternative addresses for the mailcow UI to respond to' >> mailcow.conf
echo '# This is useful when you set mail.* as ADDITIONAL_SAN and want to make sure mail.maildomain.com will always point to the mailcow UI.' >> mailcow.conf
echo '# If the server name does not match a known site, Nginx decides by best-guess and may redirect users to the wrong web root.' >> mailcow.conf
echo '# You can understand this as server_name directive in Nginx.' >> mailcow.conf
echo '# Comma separated list without spaces! Example: ADDITIONAL_SERVER_NAMES=a.b.c,d.e.f' >> mailcow.conf
echo 'ADDITIONAL_SERVER_NAMES=' >> mailcow.conf
2021-02-16 17:49:43 +02:00
fi
2021-04-29 23:32:42 +02:00
elif [ [ ${ option } = = "ACME_CONTACT" ] ] ; then
if ! grep -q ${ option } mailcow.conf; then
2021-05-04 21:29:37 +02:00
echo '# Lets Encrypt registration contact information' >> mailcow.conf
2021-04-29 23:32:42 +02:00
echo '# Optional: Leave empty for none' >> mailcow.conf
echo '# This value is only used on first order!' >> mailcow.conf
echo '# Setting it at a later point will require the following steps:' >> mailcow.conf
echo '# https://mailcow.github.io/mailcow-dockerized-docs/debug-reset-tls/' >> mailcow.conf
echo 'ACME_CONTACT=' >> mailcow.conf
fi
2018-01-24 10:24:40 +02:00
elif ! grep -q ${ option } mailcow.conf; then
echo " Adding new option \" ${ option } \" to mailcow.conf "
echo " ${ option } =n " >> mailcow.conf
fi
2017-07-04 21:28:27 +02:00
done
2017-06-20 22:17:41 +02:00
echo -en "Checking internet connection... "
2020-05-16 08:37:07 +02:00
if ! check_online_status; then
2018-01-24 10:24:40 +02:00
echo -e "\e[31mfailed\e[0m"
exit 1
2018-02-20 10:31:01 +02:00
else
2018-01-24 10:24:40 +02:00
echo -e "\e[32mOK\e[0m"
2017-06-20 22:17:41 +02:00
fi
2017-06-21 11:48:03 +02:00
echo -e "\e[32mChecking for newer update script...\e[0m"
2017-06-21 16:44:57 +02:00
SHA1_1 = $( sha1sum update.sh)
2018-04-25 21:58:50 +02:00
git fetch origin #${BRANCH}
2017-06-21 16:44:57 +02:00
git checkout origin/${ BRANCH } update.sh
SHA1_2 = $( sha1sum update.sh)
if [ [ ${ SHA1_1 } != ${ SHA1_2 } ] ] ; then
2018-01-24 10:24:40 +02:00
echo "update.sh changed, please run this script again, exiting."
chmod +x update.sh
2020-04-07 13:28:51 +02:00
exit 2
2017-06-20 23:41:25 +02:00
fi
2017-06-20 22:17:41 +02:00
2017-06-20 21:40:15 +02:00
if [ [ -f mailcow.conf ] ] ; then
2018-01-24 10:24:40 +02:00
source mailcow.conf
2018-02-20 10:31:01 +02:00
else
2018-01-24 10:24:40 +02:00
echo -e "\e[31mNo mailcow.conf - is mailcow installed?\e[0m"
exit 1
2017-06-20 21:40:15 +02:00
fi
2017-06-19 23:31:43 +02:00
2020-04-07 13:28:51 +02:00
if [ ! $FORCE ] ; then
read -r -p "Are you sure you want to update mailcow: dockerized? All containers will be stopped. [y/N] " response
2021-06-21 22:04:32 +02:00
if [ [ ! " ${ response } " = ~ ^( [ yY] [ eE] [ sS] | [ yY] ) +$ ] ] ; then
2020-04-07 13:28:51 +02:00
echo "OK, exiting."
exit 0
fi
2021-08-02 19:19:07 +02:00
migrate_docker_nat
2017-06-20 23:05:43 +02:00
fi
2020-03-22 19:15:07 +02:00
echo -e "\e[32mValidating docker-compose stack configuration...\e[0m"
if ! docker-compose config -q; then
echo -e "\e[31m\nOh no, something went wrong. Please check the error message above.\e[0m"
exit 1
fi
2020-07-15 15:29:09 +02:00
echo -e "\e[32mChecking for conflicting bridges...\e[0m"
MAILCOW_BRIDGE = $( docker-compose config | grep -i com.docker.network.bridge.name | cut -d':' -f2)
while read NAT_ID; do
iptables -t nat -D POSTROUTING $NAT_ID
done < <( iptables -L -vn -t nat --line-numbers | grep $IPV4_NETWORK | grep -E 'MASQUERADE.*all' | grep -v ${ MAILCOW_BRIDGE } | cut -d' ' -f1)
2019-08-25 16:41:52 +02:00
DIFF_DIRECTORY = update_diffs
DIFF_FILE = ${ DIFF_DIRECTORY } /diff_before_update_$( date +"%Y-%m-%d-%H-%M-%S" )
mv diff_before_update* ${ DIFF_DIRECTORY } / 2> /dev/null
2020-02-22 11:37:30 +02:00
if ! git diff-index --quiet HEAD; then
2020-02-22 12:15:47 +02:00
echo -e " \e[32mSaving diff to ${ DIFF_FILE } ...\e[0m "
mkdir -p ${ DIFF_DIRECTORY }
2020-02-22 11:37:30 +02:00
git diff --stat > ${ DIFF_FILE }
git diff >> ${ DIFF_FILE }
fi
2019-08-09 14:09:30 +02:00
2019-05-25 22:29:25 +02:00
echo -e "\e[32mPrefetching images...\e[0m"
2019-07-08 18:42:51 +02:00
prefetch_images
2019-05-25 22:29:25 +02:00
2020-02-21 09:52:46 +02:00
echo -e "\e[32mStopping mailcow...\e[0m"
2017-09-16 23:24:30 +02:00
sleep 2
2020-02-21 09:52:46 +02:00
MAILCOW_CONTAINERS = ( $( docker-compose ps -q) )
2017-09-16 23:24:30 +02:00
docker-compose down
2020-02-21 09:52:46 +02:00
echo -e "\e[32mChecking for remaining containers...\e[0m"
sleep 2
for container in " ${ MAILCOW_CONTAINERS [@] } " ; do
docker rm -f " $container " 2> /dev/null
done
2017-06-20 21:21:21 +02:00
2021-06-30 12:01:31 +02:00
[ [ -f data/conf/nginx/ZZZ-ejabberd.conf ] ] && rm data/conf/nginx/ZZZ-ejabberd.conf
2017-06-19 23:31:43 +02:00
# Silently fixing remote url from andryyy to mailcow
git remote set-url origin https://github.com/mailcow/mailcow-dockerized
2017-06-21 11:48:03 +02:00
echo -e "\e[32mCommitting current status...\e[0m"
2018-12-22 17:56:50 +02:00
[ [ -z " $( git config user.name) " ] ] && git config user.name moo
[ [ -z " $( git config user.email) " ] ] && git config user.email moo@cow.moo
2019-06-10 22:44:10 +02:00
[ [ ! -z $( git ls-files data/conf/rspamd/override.d/worker-controller-password.inc) ] ] && git rm data/conf/rspamd/override.d/worker-controller-password.inc
2017-06-19 23:31:43 +02:00
git add -u
git commit -am " Before update on ${ DATE } " > /dev/null
2017-06-21 11:48:03 +02:00
echo -e "\e[32mFetching updated code from remote...\e[0m"
2018-04-25 21:58:50 +02:00
git fetch origin #${BRANCH}
2018-02-01 10:40:08 +02:00
echo -e " \e[32mMerging local with remote code (recursive, strategy: \" ${ MERGE_STRATEGY :- theirs } \", options: \"patience\"...\e[0m "
2017-09-13 19:25:54 +02:00
git config merge.defaultToUpstream true
2018-02-01 10:40:08 +02:00
git merge -X${ MERGE_STRATEGY :- theirs } -Xpatience -m " After update on ${ DATE } "
2017-06-21 11:57:32 +02:00
# Need to use a variable to not pass return codes of if checks
MERGE_RETURN = $?
if [ [ ${ MERGE_RETURN } = = 128 ] ] ; then
2018-01-24 10:24:40 +02:00
echo -e "\e[31m\nOh no, what happened?\n=> You most likely added files to your local mailcow instance that were now added to the official mailcow repository. Please move them to another location before updating mailcow.\e[0m"
exit 1
2017-06-21 11:57:32 +02:00
elif [ [ ${ MERGE_RETURN } = = 1 ] ] ; then
2018-01-24 10:24:40 +02:00
echo -e "\e[93mPotenial conflict, trying to fix...\e[0m"
git status --porcelain | grep -E "UD|DU" | awk '{print $2}' | xargs rm -v
git add -A
git commit -m " After update on ${ DATE } " > /dev/null
git checkout .
echo -e "\e[32mRemoved and recreated files if necessary.\e[0m"
2017-06-21 11:57:32 +02:00
elif [ [ ${ MERGE_RETURN } != 0 ] ] ; then
2018-01-24 10:24:40 +02:00
echo -e "\e[31m\nOh no, something went wrong. Please check the error message above.\e[0m"
echo
echo "Run docker-compose up -d to restart your stack without updates or try again after fixing the mentioned errors."
exit 1
2017-06-19 23:31:43 +02:00
fi
2017-07-08 16:22:48 +02:00
2020-05-29 19:47:44 +02:00
if [ [ ${ NO_UPDATE_COMPOSE } = = "y" ] ] ; then
echo -e "\e[33mNot fetching latest docker-compose, please check for updates manually!\e[0m"
2020-10-18 12:31:01 +02:00
elif [ [ -e /etc/alpine-release ] ] ; then
echo -e "\e[33mNot fetching latest docker-compose, because you are using Alpine Linux without glibc support. Please update docker-compose via apk!\e[0m"
2020-05-29 19:47:44 +02:00
else
echo -e "\e[32mFetching new docker-compose version...\e[0m"
2021-01-21 20:15:24 +02:00
echo -e "\e[32mTrying to determine GLIBC version...\e[0m"
if ldd --version > /dev/null; then
2021-01-22 08:31:09 +02:00
GLIBC_V = $( ldd --version | grep -E '(GLIBC|GNU libc)' | rev | cut -d ' ' -f1 | rev | cut -d '.' -f2)
if [ ! -z " ${ GLIBC_V } " ] && [ ${ GLIBC_V } -gt 27 ] ; then
2021-01-21 20:15:24 +02:00
DC_DL_SUFFIX =
else
DC_DL_SUFFIX = legacy
fi
else
DC_DL_SUFFIX = legacy
fi
2020-05-29 19:47:44 +02:00
sleep 1
if [ [ ! -z $( which pip) && $( pip list --local 2>& 1 | grep -v DEPRECATION | grep -c docker-compose) = = 1 ] ] ; then
true
#prevent breaking a working docker-compose installed with pip
2021-01-21 20:15:24 +02:00
elif [ [ $( curl -sL -w "%{http_code}" https://www.servercow.de/docker-compose/latest.php?vers= ${ DC_DL_SUFFIX } -o /dev/null) = = "200" ] ] ; then
2020-05-29 19:47:44 +02:00
LATEST_COMPOSE = $( curl -#L https://www.servercow.de/docker-compose/latest.php)
COMPOSE_VERSION = $( docker-compose version --short)
if [ [ " $LATEST_COMPOSE " != " $COMPOSE_VERSION " ] ] ; then
COMPOSE_PATH = $( which docker-compose)
if [ [ -w ${ COMPOSE_PATH } ] ] ; then
curl -#L https://github.com/docker/compose/releases/download/${ LATEST_COMPOSE } /docker-compose-$( uname -s) -$( uname -m) > $COMPOSE_PATH
chmod +x $COMPOSE_PATH
else
echo -e " \e[33mWARNING: $COMPOSE_PATH is not writable, but new version $LATEST_COMPOSE is available (installed: $COMPOSE_VERSION )\e[0m "
fi
2018-04-29 09:22:00 +02:00
fi
2020-05-29 19:47:44 +02:00
else
echo -e "\e[33mCannot determine latest docker-compose version, skipping...\e[0m"
2018-04-29 09:22:00 +02:00
fi
2017-07-08 16:22:48 +02:00
fi
2017-06-20 21:21:21 +02:00
echo -e "\e[32mFetching new images, if any...\e[0m"
2017-06-21 16:53:36 +02:00
sleep 2
2018-04-29 09:22:00 +02:00
docker-compose pull
2017-06-20 23:22:39 +02:00
2017-06-20 21:40:15 +02:00
# Fix missing SSL, does not overwrite existing files
[ [ ! -d data/assets/ssl ] ] && mkdir -p data/assets/ssl
2019-10-19 13:00:01 +02:00
cp -n -d data/assets/ssl-example/*.pem data/assets/ssl/
2017-06-20 22:17:41 +02:00
2018-07-25 01:08:12 +02:00
echo -e "Checking IPv6 settings... "
if grep -q 'SYSCTL_IPV6_DISABLED=1' mailcow.conf; then
echo
echo '!! IMPORTANT !!'
echo
2019-06-02 20:56:08 +02:00
echo 'SYSCTL_IPV6_DISABLED was removed due to complications. IPv6 can be disabled by editing "docker-compose.yml" and setting "enable_ipv6: true" to "enable_ipv6: false".'
2018-07-25 01:08:12 +02:00
echo 'This setting will only be active after a complete shutdown of mailcow by running "docker-compose down" followed by "docker-compose up -d".'
echo
echo '!! IMPORTANT !!'
echo
read -p "Press any key to continue..." < /dev/tty
fi
2019-03-14 02:46:15 +02:00
# Checking for old project name bug
2020-09-20 22:07:37 +02:00
sed -i --follow-symlinks 's#COMPOSEPROJECT_NAME#COMPOSE_PROJECT_NAME#g' mailcow.conf
2021-01-07 17:48:08 +02:00
# Checking old, wrong bindings
sed -i --follow-symlinks 's/HTTP_BIND=0.0.0.0/HTTP_BIND=/g' mailcow.conf
sed -i --follow-symlinks 's/HTTPS_BIND=0.0.0.0/HTTPS_BIND=/g' mailcow.conf
2018-04-12 07:56:54 +02:00
2019-01-31 00:03:58 +02:00
# Fix Rspamd maps
if [ -f data/conf/rspamd/custom/global_from_blacklist.map ] ; then
mv data/conf/rspamd/custom/global_from_blacklist.map data/conf/rspamd/custom/global_smtp_from_blacklist.map
fi
if [ -f data/conf/rspamd/custom/global_from_whitelist.map ] ; then
mv data/conf/rspamd/custom/global_from_whitelist.map data/conf/rspamd/custom/global_smtp_from_whitelist.map
fi
2020-01-05 12:22:02 +02:00
# Fix deprecated metrics.conf
if [ -f "data/conf/rspamd/local.d/metrics.conf" ] ; then
if [ ! -z " $( git diff --name-only origin/master data/conf/rspamd/local.d/metrics.conf) " ] ; then
echo -e "\e[33mWARNING\e[0m - Please migrate your customizations of data/conf/rspamd/local.d/metrics.conf to actions.conf and groups.conf after this update."
echo "The deprecated configuration file metrics.conf will be moved to metrics.conf_deprecated after updating mailcow."
fi
mv data/conf/rspamd/local.d/metrics.conf data/conf/rspamd/local.d/metrics.conf_deprecated
fi
2020-02-11 12:25:38 +02:00
if [ [ ${ SKIP_START } = = "y" ] ] ; then
echo -e "\e[33mNot starting mailcow, please run \"docker-compose up -d --remove-orphans\" to start mailcow.\e[0m"
else
echo -e "\e[32mStarting mailcow...\e[0m"
sleep 2
docker-compose up -d --remove-orphans
fi
2017-07-08 16:22:48 +02:00
2017-07-08 16:31:08 +02:00
echo -e "\e[32mCollecting garbage...\e[0m"
2018-07-25 01:08:12 +02:00
docker_garbage
2017-07-08 16:22:48 +02:00
2021-07-31 00:21:15 +02:00
# Run post-update-hook
if [ -f " ${ SCRIPT_DIR } /post_update_hook.sh " ] ; then
bash " ${ SCRIPT_DIR } /post_update_hook.sh "
fi
2017-07-04 21:28:27 +02:00
#echo "In case you encounter any problem, hard-reset to a state before updating mailcow:"
#echo
#git reflog --color=always | grep "Before update on "
#echo
#echo "Use \"git reset --hard hash-on-the-left\" and run docker-compose up -d afterwards."