blob: 5204659e192837c92999557fd221a5da82ecbcde [file] [log] [blame]
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01001#!/usr/bin/env bash
2
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +01003############## Begin Function Section ##############
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01004
5check_online_status() {
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +01006 CHECK_ONLINE_DOMAINS=('https://github.com' 'https://hub.docker.com')
7 for domain in "${CHECK_ONLINE_DOMAINS[@]}"; do
8 if timeout 6 curl --head --silent --output /dev/null ${domain}; then
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01009 return 0
10 fi
11 done
12 return 1
13}
14
15prefetch_images() {
16 [[ -z ${BRANCH} ]] && { echo -e "\e[33m\nUnknown branch...\e[0m"; exit 1; }
17 git fetch origin #${BRANCH}
18 while read image; do
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +020019 if [[ "${image}" == "robbertkl/ipv6nat" ]]; then
20 if ! grep -qi "ipv6nat-mailcow" docker-compose.yml || grep -qi "enable_ipv6: false" docker-compose.yml; then
21 continue
22 fi
23 fi
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +010024 RET_C=0
25 until docker pull ${image}; do
26 RET_C=$((RET_C + 1))
27 echo -e "\e[33m\nError pulling $image, retrying...\e[0m"
28 [ ${RET_C} -gt 3 ] && { echo -e "\e[31m\nToo many failed retries, exiting\e[0m"; exit 1; }
29 sleep 1
30 done
31 done < <(git show origin/${BRANCH}:docker-compose.yml | grep "image:" | awk '{ gsub("image:","", $3); print $2 }')
32}
33
34docker_garbage() {
35 IMGS_TO_DELETE=()
Matthias Andreas Benkard12a57352021-12-28 18:02:04 +010036 for container in $(grep -oP "image: \Kmailcow.+" "${SCRIPT_DIR}/docker-compose.yml"); do
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +010037 REPOSITORY=${container/:*}
38 TAG=${container/*:}
39 V_MAIN=${container/*.}
40 V_SUB=${container/*.}
41 EXISTING_TAGS=$(docker images | grep ${REPOSITORY} | awk '{ print $2 }')
42 for existing_tag in ${EXISTING_TAGS[@]}; do
43 V_MAIN_EXISTING=${existing_tag/*.}
44 V_SUB_EXISTING=${existing_tag/*.}
45 # Not an integer
46 [[ ! $V_MAIN_EXISTING =~ ^[0-9]+$ ]] && continue
47 [[ ! $V_SUB_EXISTING =~ ^[0-9]+$ ]] && continue
48
49 if [[ $V_MAIN_EXISTING == "latest" ]]; then
50 echo "Found deprecated label \"latest\" for repository $REPOSITORY, it should be deleted."
51 IMGS_TO_DELETE+=($REPOSITORY:$existing_tag)
52 elif [[ $V_MAIN_EXISTING -lt $V_MAIN ]]; then
53 echo "Found tag $existing_tag for $REPOSITORY, which is older than the current tag $TAG and should be deleted."
54 IMGS_TO_DELETE+=($REPOSITORY:$existing_tag)
55 elif [[ $V_SUB_EXISTING -lt $V_SUB ]]; then
56 echo "Found tag $existing_tag for $REPOSITORY, which is older than the current tag $TAG and should be deleted."
57 IMGS_TO_DELETE+=($REPOSITORY:$existing_tag)
58 fi
59 done
60 done
61
62 if [[ ! -z ${IMGS_TO_DELETE[*]} ]]; then
63 echo "Run the following command to delete unused image tags:"
64 echo
65 echo " docker rmi ${IMGS_TO_DELETE[*]}"
66 echo
67 if [ ! $FORCE ]; then
68 read -r -p "Do you want to delete old image tags right now? [y/N] " response
69 if [[ "$response" =~ ^([yY][eE][sS]|[yY])+$ ]]; then
70 docker rmi ${IMGS_TO_DELETE[*]}
71 else
72 echo "OK, skipped."
73 fi
74 else
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +020075 echo "Running image removal without extra confirmation due to force mode."
76 docker rmi ${IMGS_TO_DELETE[*]}
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +010077 fi
Matthias Andreas Benkard12a57352021-12-28 18:02:04 +010078 echo -e "\e[32mFurther cleanup...\e[0m"
79 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\""
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +010080 fi
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +010081}
82
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +020083in_array() {
84 local e match="$1"
85 shift
86 for e; do [[ "$e" == "$match" ]] && return 0; done
87 return 1
88}
89
90migrate_docker_nat() {
91 NAT_CONFIG='{"ipv6":true,"fixed-cidr-v6":"fd00:dead:beef:c0::/80","experimental":true,"ip6tables":true}'
92 # Min Docker version
93 DOCKERV_REQ=20.10.2
94 # Current Docker version
95 DOCKERV_CUR=$(docker version -f '{{.Server.Version}}')
96 if grep -qi "ipv6nat-mailcow" docker-compose.yml && grep -qi "enable_ipv6: true" docker-compose.yml; then
97 echo -e "\e[32mNative IPv6 implementation available.\e[0m"
98 echo "This will enable experimental features in the Docker daemon and configure Docker to do the IPv6 NATing instead of ipv6nat-mailcow."
99 echo '!!! This step is recommended !!!'
100 echo "mailcow will try to roll back the changes if starting Docker fails after modifying the daemon.json configuration file."
101 read -r -p "Should we try to enable the native IPv6 implementation in Docker now (recommended)? [y/N] " dockernatresponse
102 if [[ ! "${dockernatresponse}" =~ ^([yY][eE][sS]|[yY])+$ ]]; then
103 echo "OK, skipping this step."
104 return 0
105 fi
106 fi
107 # Sort versions and check if we are running a newer or equal version to req
108 if [ $(printf "${DOCKERV_REQ}\n${DOCKERV_CUR}" | sort -V | tail -n1) == "${DOCKERV_CUR}" ]; then
109 # If Dockerd daemon json exists
110 if [ -s /etc/docker/daemon.json ]; then
111 IFS=',' read -r -a dockerconfig <<< $(cat /etc/docker/daemon.json | tr -cd '[:alnum:],')
112 if ! in_array ipv6true "${dockerconfig[@]}" || \
113 ! in_array experimentaltrue "${dockerconfig[@]}" || \
114 ! in_array ip6tablestrue "${dockerconfig[@]}" || \
115 ! grep -qi "fixed-cidr-v6" /etc/docker/daemon.json; then
116 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."
117 echo "You will need to merge your existing configuration manually or fix/delete the existing daemon.json configuration before trying the update process again."
118 echo -e "Please merge the following content and restart the Docker daemon:\n"
119 echo ${NAT_CONFIG}
120 return 1
121 fi
122 else
123 echo "Working on IPv6 NAT, please wait..."
124 echo ${NAT_CONFIG} > /etc/docker/daemon.json
125 ip6tables -F -t nat
Matthias Andreas Benkard12a57352021-12-28 18:02:04 +0100126 [[ -e /etc/alpine-release ]] && rc-service docker restart || systemctl restart docker.service
127 if [[ $? -ne 0 ]]; then
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +0200128 echo -e "\e[31mError:\e[0m Failed to activate IPv6 NAT! Reverting and exiting."
129 rm /etc/docker/daemon.json
Matthias Andreas Benkard12a57352021-12-28 18:02:04 +0100130 if [[ -e /etc/alpine-release ]]; then
131 rc-service docker restart
132 else
133 systemctl reset-failed docker.service
134 systemctl restart docker.service
135 fi
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +0200136 return 1
137 fi
138 fi
139 # Removing legacy container
140 sed -i '/ipv6nat-mailcow:$/,/^$/d' docker-compose.yml
Matthias Andreas Benkard12a57352021-12-28 18:02:04 +0100141 if [ -s docker-compose.override.yml ]; then
142 sed -i '/ipv6nat-mailcow:$/,/^$/d' docker-compose.override.yml
143 if [[ "$(cat docker-compose.override.yml | sed '/^\s*$/d' | wc -l)" == "2" ]]; then
144 mv docker-compose.override.yml docker-compose.override.yml_backup
145 fi
146 fi
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +0200147 echo -e "\e[32mGreat! \e[0mNative IPv6 NAT is active.\e[0m"
148 else
149 echo -e "\e[31mPlease upgrade Docker to version ${DOCKERV_REQ} or above.\e[0m"
150 return 0
151 fi
152}
153
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +0100154remove_obsolete_nginx_ports() {
155 # Removing obsolete docker-compose.override.yml
156 for override in docker-compose.override.yml docker-compose.override.yaml; do
157 if [ -s $override ] ; then
158 if cat $override | grep nginx-mailcow > /dev/null 2>&1; then
159 if cat $override | grep -E '(\[::])' > /dev/null 2>&1; then
160 if cat $override | grep -w 80:80 > /dev/null 2>&1 && cat $override | grep -w 443:443 > /dev/null 2>&1 ; then
161 echo -e "\e[33mBacking up ${override} to preserve custom changes...\e[0m"
162 echo -e "\e[33m!!! Manual Merge needed (if other overrides are set) !!!\e[0m"
163 sleep 3
164 cp $override ${override}_backup
165 sed -i '/nginx-mailcow:$/,/^$/d' $override
166 echo -e "\e[33mRemoved obsolete NGINX IPv6 Bind from original override File.\e[0m"
167 if [[ "$(cat $override | sed '/^\s*$/d' | wc -l)" == "2" ]]; then
168 mv $override ${override}_empty
169 echo -e "\e[31m${override} is empty. Renamed it to ensure mailcow is startable.\e[0m"
170 fi
171 fi
172 fi
173 fi
174 fi
175 done
176}
177
178detect_docker_compose_command(){
Matthias Andreas Benkardd1f5b682023-11-18 13:18:30 +0100179if ! [[ "${DOCKER_COMPOSE_VERSION}" =~ ^(native|standalone)$ ]]; then
180 if docker compose > /dev/null 2>&1; then
181 if docker compose version --short | grep "2." > /dev/null 2>&1; then
182 DOCKER_COMPOSE_VERSION=native
183 COMPOSE_COMMAND="docker compose"
184 echo -e "\e[31mFound Docker Compose Plugin (native).\e[0m"
185 echo -e "\e[31mSetting the DOCKER_COMPOSE_VERSION Variable to native\e[0m"
186 sed -i 's/^DOCKER_COMPOSE_VERSION=.*/DOCKER_COMPOSE_VERSION=native/' $SCRIPT_DIR/mailcow.conf
187 sleep 2
188 echo -e "\e[33mNotice: You'll have to update this Compose Version via your Package Manager manually!\e[0m"
189 else
190 echo -e "\e[31mCannot find Docker Compose with a Version Higher than 2.X.X.\e[0m"
191 echo -e "\e[31mPlease update/install it manually regarding to this doc site: https://docs.mailcow.email/i_u_m/i_u_m_install/\e[0m"
192 exit 1
193 fi
194 elif docker-compose > /dev/null 2>&1; then
195 if ! [[ $(alias docker-compose 2> /dev/null) ]] ; then
196 if docker-compose version --short | grep "^2." > /dev/null 2>&1; then
197 DOCKER_COMPOSE_VERSION=standalone
198 COMPOSE_COMMAND="docker-compose"
199 echo -e "\e[31mFound Docker Compose Standalone.\e[0m"
200 echo -e "\e[31mSetting the DOCKER_COMPOSE_VERSION Variable to standalone\e[0m"
201 sed -i 's/^DOCKER_COMPOSE_VERSION=.*/DOCKER_COMPOSE_VERSION=standalone/' $SCRIPT_DIR/mailcow.conf
202 sleep 2
203 echo -e "\e[33mNotice: For an automatic update of docker-compose please use the update_compose.sh scripts located at the helper-scripts folder.\e[0m"
204 else
205 echo -e "\e[31mCannot find Docker Compose with a Version Higher than 2.X.X.\e[0m"
206 echo -e "\e[31mPlease update/install regarding to this doc site: https://docs.mailcow.email/i_u_m/i_u_m_install/\e[0m"
207 exit 1
208 fi
209 fi
210
211 else
212 echo -e "\e[31mCannot find Docker Compose.\e[0m"
213 echo -e "\e[31mPlease install it regarding to this doc site: https://docs.mailcow.email/i_u_m/i_u_m_install/\e[0m"
214 exit 1
215 fi
216
217elif [ "${DOCKER_COMPOSE_VERSION}" == "native" ]; then
218 COMPOSE_COMMAND="docker compose"
219 # Check if Native Compose works and has not been deleted
220 if ! $COMPOSE_COMMAND > /dev/null 2>&1; then
221 # IF it not exists/work anymore try the other command
222 COMPOSE_COMMAND="docker-compose"
223 if ! $COMPOSE_COMMAND > /dev/null 2>&1 || ! $COMPOSE_COMMAND --version | grep "^2." > /dev/null 2>&1; then
224 # IF it cannot find Standalone in > 2.X, then script stops
225 echo -e "\e[31mCannot find Docker Compose or the Version is lower then 2.X.X.\e[0m"
226 echo -e "\e[31mPlease install it regarding to this doc site: https://docs.mailcow.email/i_u_m/i_u_m_install/\e[0m"
227 exit 1
228 fi
229 # If it finds the standalone Plugin it will use this instead and change the mailcow.conf Variable accordingly
230 echo -e "\e[31mFound different Docker Compose Version then declared in mailcow.conf!\e[0m"
231 echo -e "\e[31mSetting the DOCKER_COMPOSE_VERSION Variable from native to standalone\e[0m"
232 sed -i 's/^DOCKER_COMPOSE_VERSION=.*/DOCKER_COMPOSE_VERSION=standalone/' $SCRIPT_DIR/mailcow.conf
233 sleep 2
234 fi
235
236
237elif [ "${DOCKER_COMPOSE_VERSION}" == "standalone" ]; then
238 COMPOSE_COMMAND="docker-compose"
239 # Check if Standalone Compose works and has not been deleted
240 if ! $COMPOSE_COMMAND > /dev/null 2>&1 && ! $COMPOSE_COMMAND --version > /dev/null 2>&1 | grep "^2." > /dev/null 2>&1; then
241 # IF it not exists/work anymore try the other command
242 COMPOSE_COMMAND="docker compose"
243 if ! $COMPOSE_COMMAND > /dev/null 2>&1; then
244 # IF it cannot find Native in > 2.X, then script stops
245 echo -e "\e[31mCannot find Docker Compose.\e[0m"
246 echo -e "\e[31mPlease install it regarding to this doc site: https://docs.mailcow.email/i_u_m/i_u_m_install/\e[0m"
247 exit 1
248 fi
249 # If it finds the native Plugin it will use this instead and change the mailcow.conf Variable accordingly
250 echo -e "\e[31mFound different Docker Compose Version then declared in mailcow.conf!\e[0m"
251 echo -e "\e[31mSetting the DOCKER_COMPOSE_VERSION Variable from standalone to native\e[0m"
252 sed -i 's/^DOCKER_COMPOSE_VERSION=.*/DOCKER_COMPOSE_VERSION=native/' $SCRIPT_DIR/mailcow.conf
253 sleep 2
254 fi
255fi
256}
257
258detect_bad_asn() {
259 echo -e "\e[33mDetecting if your IP is listed on Spamhaus Bad ASN List...\e[0m"
260 response=$(curl --connect-timeout 15 --max-time 30 -s -o /dev/null -w "%{http_code}" "https://asn-check.mailcow.email")
261 if [ "$response" -eq 503 ]; then
262 if [ -z "$SPAMHAUS_DQS_KEY" ]; then
263 echo -e "\e[33mYour server's public IP uses an AS that is blocked by Spamhaus to use their DNS public blocklists for Postfix.\e[0m"
264 echo -e "\e[33mmailcow did not detected a value for the variable SPAMHAUS_DQS_KEY inside mailcow.conf!\e[0m"
265 sleep 2
266 echo ""
267 echo -e "\e[33mTo use the Spamhaus DNS Blocklists again, you will need to create a FREE account for their Data Query Service (DQS) at: https://www.spamhaus.com/free-trial/sign-up-for-a-free-data-query-service-account\e[0m"
268 echo -e "\e[33mOnce done, enter your DQS API key in mailcow.conf and mailcow will do the rest for you!\e[0m"
269 echo ""
270 sleep 2
271
272 else
273 echo -e "\e[33mYour server's public IP uses an AS that is blocked by Spamhaus to use their DNS public blocklists for Postfix.\e[0m"
274 echo -e "\e[32mmailcow detected a Value for the variable SPAMHAUS_DQS_KEY inside mailcow.conf. Postfix will use DQS with the given API key...\e[0m"
275 fi
276 elif [ "$response" -eq 200 ]; then
277 echo -e "\e[33mCheck completed! Your IP is \e[32mclean\e[0m"
278 elif [ "$response" -eq 429 ]; then
279 echo -e "\e[33mCheck completed! \e[31mYour IP seems to be rate limited on the ASN Check service... please try again later!\e[0m"
280 else
281 echo -e "\e[31mCheck failed! \e[0mMaybe a DNS or Network problem?\e[0m"
282 fi
283}
284
285############## End Function Section ##############
286
287# Check permissions
288if [ "$(id -u)" -ne "0" ]; then
289 echo "You need to be root"
290 exit 1
291fi
292
293SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
294
295# Run pre-update-hook
296if [ -f "${SCRIPT_DIR}/pre_update_hook.sh" ]; then
297 bash "${SCRIPT_DIR}/pre_update_hook.sh"
298fi
299
300if [[ "$(uname -r)" =~ ^4\.15\.0-60 ]]; then
301 echo "DO NOT RUN mailcow ON THIS UBUNTU KERNEL!";
302 echo "Please update to 5.x or use another distribution."
303 exit 1
304fi
305
306if [[ "$(uname -r)" =~ ^4\.4\. ]]; then
307 if grep -q Ubuntu <<< $(uname -a); then
308 echo "DO NOT RUN mailcow ON THIS UBUNTU KERNEL!"
309 echo "Please update to linux-generic-hwe-16.04 by running \"apt-get install --install-recommends linux-generic-hwe-16.04\""
310 exit 1
311 fi
312 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."
313 read -p "Press any key to continue..." < /dev/tty
314fi
315
316# Exit on error and pipefail
317set -o pipefail
318
319# Setting high dc timeout
320export COMPOSE_HTTP_TIMEOUT=600
321
322# Add /opt/bin to PATH
323PATH=$PATH:/opt/bin
324
325umask 0022
326
327# Unset COMPOSE_COMMAND and DOCKER_COMPOSE_VERSION Variable to be on the newest state.
328unset COMPOSE_COMMAND
329unset DOCKER_COMPOSE_VERSION
330
331for bin in curl docker git awk sha1sum grep cut; do
332 if [[ -z $(command -v ${bin}) ]]; then
333 echo "Cannot find ${bin}, exiting..."
334 exit 1;
335 fi
336done
337
338export LC_ALL=C
339DATE=$(date +%Y-%m-%d_%H_%M_%S)
340BRANCH=$(cd ${SCRIPT_DIR}; git rev-parse --abbrev-ref HEAD)
341
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100342while (($#)); do
343 case "${1}" in
344 --check|-c)
345 echo "Checking remote code for updates..."
346 LATEST_REV=$(git ls-remote --exit-code --refs --quiet https://github.com/mailcow/mailcow-dockerized ${BRANCH} | cut -f1)
347 if [ $? -ne 0 ]; then
348 echo "A problem occurred while trying to fetch the latest revision from github."
349 exit 99
350 fi
351 if [[ -z $(git log HEAD --pretty=format:"%H" | grep "${LATEST_REV}") ]]; then
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +0200352 echo -e "Updated code is available.\nThe changes can be found here: https://github.com/mailcow/mailcow-dockerized/commits/master"
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100353 git log --date=short --pretty=format:"%ad - %s" $(git rev-parse --short HEAD)..origin/master
354 exit 0
355 else
356 echo "No updates available."
357 exit 3
358 fi
359 ;;
360 --ours)
361 MERGE_STRATEGY=ours
362 ;;
363 --skip-start)
364 SKIP_START=y
365 ;;
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +0100366 --skip-ping-check)
367 SKIP_PING_CHECK=y
368 ;;
369 --stable)
370 CURRENT_BRANCH="$(cd ${SCRIPT_DIR}; git rev-parse --abbrev-ref HEAD)"
371 NEW_BRANCH="master"
372 ;;
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100373 --gc)
374 echo -e "\e[32mCollecting garbage...\e[0m"
375 docker_garbage
376 exit 0
377 ;;
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +0100378 --nightly)
379 CURRENT_BRANCH="$(cd ${SCRIPT_DIR}; git rev-parse --abbrev-ref HEAD)"
380 NEW_BRANCH="nightly"
381 ;;
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100382 --prefetch)
383 echo -e "\e[32mPrefetching images...\e[0m"
384 prefetch_images
385 exit 0
386 ;;
387 -f|--force)
Matthias Andreas Benkard12a57352021-12-28 18:02:04 +0100388 echo -e "\e[32mRunning in forced mode...\e[0m"
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100389 FORCE=y
390 ;;
Matthias Andreas Benkardd1f5b682023-11-18 13:18:30 +0100391 -d|--dev)
392 echo -e "\e[32mRunning in Developer mode...\e[0m"
393 DEV=y
Matthias Andreas Benkarda515bc62023-11-18 16:44:25 +0100394 ;;
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100395 --help|-h)
Matthias Andreas Benkardd1f5b682023-11-18 13:18:30 +0100396 echo './update.sh [-c|--check, --ours, --gc, --nightly, --prefetch, --skip-start, --skip-ping-check, --stable, -f|--force, -d|--dev, -h|--help]
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100397
398 -c|--check - Check for updates and exit (exit codes => 0: update available, 3: no updates)
399 --ours - Use merge strategy option "ours" to solve conflicts in favor of non-mailcow code (local changes over remote changes), not recommended!
400 --gc - Run garbage collector to delete old image tags
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +0100401 --nightly - Switch your mailcow updates to the unstable (nightly) branch. FOR TESTING PURPOSES ONLY!!!!
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100402 --prefetch - Only prefetch new images and exit (useful to prepare updates)
403 --skip-start - Do not start mailcow after update
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +0100404 --skip-ping-check - Skip ICMP Check to public DNS resolvers (Use it only if you´ve blocked any ICMP Connections to your mailcow machine)
405 --stable - Switch your mailcow updates to the stable (master) branch. Default unless you changed it with --nightly.
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100406 -f|--force - Force update, do not ask questions
Matthias Andreas Benkardd1f5b682023-11-18 13:18:30 +0100407 -d|--dev - Enables Developer Mode (No Checkout of update.sh for tests)
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100408'
409 exit 1
410 esac
411 shift
412done
413
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100414chmod 600 mailcow.conf
415source mailcow.conf
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +0100416
417detect_docker_compose_command
418
419[[ ! -f mailcow.conf ]] && { echo "mailcow.conf is missing! Is mailcow installed?"; exit 1;}
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100420DOTS=${MAILCOW_HOSTNAME//[^.]};
Matthias Andreas Benkardd1f5b682023-11-18 13:18:30 +0100421if [ ${#DOTS} -lt 1 ]; then
422 echo -e "\e[31mMAILCOW_HOSTNAME (${MAILCOW_HOSTNAME}) is not a FQDN!\e[0m"
423 sleep 1
424 echo "Please change it to a FQDN and redeploy the stack with $COMPOSE_COMMAND up -d"
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100425 exit 1
Matthias Andreas Benkardd1f5b682023-11-18 13:18:30 +0100426elif [[ "${MAILCOW_HOSTNAME: -1}" == "." ]]; then
427 echo "MAILCOW_HOSTNAME (${MAILCOW_HOSTNAME}) is ending with a dot. This is not a valid FQDN!"
428 exit 1
429elif [ ${#DOTS} -eq 1 ]; then
430 echo -e "\e[33mMAILCOW_HOSTNAME (${MAILCOW_HOSTNAME}) does not contain a Subdomain. This is not fully tested and may cause issues.\e[0m"
431 echo "Find more information about why this message exists here: https://github.com/mailcow/mailcow-dockerized/issues/1572"
432 read -r -p "Do you want to proceed anyway? [y/N] " response
433 if [[ "$response" =~ ^([yY][eE][sS]|[yY])+$ ]]; then
434 echo "OK. Procceding."
435 else
436 echo "OK. Exiting."
437 exit 1
438 fi
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100439fi
440
441if 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
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +0200442# This will also cover sort
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100443if 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
444if 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
445
446CONFIG_ARRAY=(
447 "SKIP_LETS_ENCRYPT"
448 "SKIP_SOGO"
449 "USE_WATCHDOG"
450 "WATCHDOG_NOTIFY_EMAIL"
451 "WATCHDOG_NOTIFY_BAN"
452 "WATCHDOG_EXTERNAL_CHECKS"
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +0200453 "WATCHDOG_SUBJECT"
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100454 "SKIP_CLAMD"
455 "SKIP_IP_CHECK"
456 "ADDITIONAL_SAN"
457 "DOVEADM_PORT"
458 "IPV4_NETWORK"
459 "IPV6_NETWORK"
460 "LOG_LINES"
461 "SNAT_TO_SOURCE"
462 "SNAT6_TO_SOURCE"
463 "COMPOSE_PROJECT_NAME"
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +0100464 "DOCKER_COMPOSE_VERSION"
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100465 "SQL_PORT"
466 "API_KEY"
467 "API_KEY_READ_ONLY"
468 "API_ALLOW_FROM"
469 "MAILDIR_GC_TIME"
470 "MAILDIR_SUB"
471 "ACL_ANYONE"
472 "SOLR_HEAP"
473 "SKIP_SOLR"
474 "ENABLE_SSL_SNI"
475 "ALLOW_ADMIN_EMAIL_LOGIN"
476 "SKIP_HTTP_VERIFICATION"
477 "SOGO_EXPIRE_SESSION"
478 "REDIS_PORT"
479 "DOVECOT_MASTER_USER"
480 "DOVECOT_MASTER_PASS"
481 "MAILCOW_PASS_SCHEME"
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +0200482 "ADDITIONAL_SERVER_NAMES"
483 "ACME_CONTACT"
Matthias Andreas Benkard12a57352021-12-28 18:02:04 +0100484 "WATCHDOG_VERBOSE"
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +0100485 "WEBAUTHN_ONLY_TRUSTED_VENDORS"
Matthias Andreas Benkardd1f5b682023-11-18 13:18:30 +0100486 "SPAMHAUS_DQS_KEY"
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100487)
488
Matthias Andreas Benkardd1f5b682023-11-18 13:18:30 +0100489detect_bad_asn
490
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100491sed -i --follow-symlinks '$a\' mailcow.conf
492for option in ${CONFIG_ARRAY[@]}; do
493 if [[ ${option} == "ADDITIONAL_SAN" ]]; then
494 if ! grep -q ${option} mailcow.conf; then
495 echo "Adding new option \"${option}\" to mailcow.conf"
496 echo "${option}=" >> mailcow.conf
497 fi
498 elif [[ ${option} == "COMPOSE_PROJECT_NAME" ]]; then
499 if ! grep -q ${option} mailcow.conf; then
500 echo "Adding new option \"${option}\" to mailcow.conf"
501 echo "COMPOSE_PROJECT_NAME=mailcowdockerized" >> mailcow.conf
502 fi
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +0100503 elif [[ ${option} == "DOCKER_COMPOSE_VERSION" ]]; then
504 if ! grep -q ${option} mailcow.conf; then
505 echo "Adding new option \"${option}\" to mailcow.conf"
506 echo "# Used Docker Compose version" >> mailcow.conf
507 echo "# Switch here between native (compose plugin) and standalone" >> mailcow.conf
508 echo "# For more informations take a look at the mailcow docs regarding the configuration options." >> mailcow.conf
509 echo "# Normally this should be untouched but if you decided to use either of those you can switch it manually here." >> mailcow.conf
510 echo "# Please be aware that at least one of those variants should be installed on your maschine or mailcow will fail." >> mailcow.conf
511 echo "" >> mailcow.conf
512 echo "DOCKER_COMPOSE_VERSION=${DOCKER_COMPOSE_VERSION}" >> mailcow.conf
513 fi
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100514 elif [[ ${option} == "DOVEADM_PORT" ]]; then
515 if ! grep -q ${option} mailcow.conf; then
516 echo "Adding new option \"${option}\" to mailcow.conf"
517 echo "DOVEADM_PORT=127.0.0.1:19991" >> mailcow.conf
518 fi
519 elif [[ ${option} == "WATCHDOG_NOTIFY_EMAIL" ]]; then
520 if ! grep -q ${option} mailcow.conf; then
521 echo "Adding new option \"${option}\" to mailcow.conf"
522 echo "WATCHDOG_NOTIFY_EMAIL=" >> mailcow.conf
523 fi
524 elif [[ ${option} == "LOG_LINES" ]]; then
525 if ! grep -q ${option} mailcow.conf; then
526 echo "Adding new option \"${option}\" to mailcow.conf"
527 echo '# Max log lines per service to keep in Redis logs' >> mailcow.conf
528 echo "LOG_LINES=9999" >> mailcow.conf
529 fi
530 elif [[ ${option} == "IPV4_NETWORK" ]]; then
531 if ! grep -q ${option} mailcow.conf; then
532 echo "Adding new option \"${option}\" to mailcow.conf"
533 echo '# Internal IPv4 /24 subnet, format n.n.n. (expands to n.n.n.0/24)' >> mailcow.conf
534 echo "IPV4_NETWORK=172.22.1" >> mailcow.conf
535 fi
536 elif [[ ${option} == "IPV6_NETWORK" ]]; then
537 if ! grep -q ${option} mailcow.conf; then
538 echo "Adding new option \"${option}\" to mailcow.conf"
539 echo '# Internal IPv6 subnet in fc00::/7' >> mailcow.conf
540 echo "IPV6_NETWORK=fd4d:6169:6c63:6f77::/64" >> mailcow.conf
541 fi
542 elif [[ ${option} == "SQL_PORT" ]]; then
543 if ! grep -q ${option} mailcow.conf; then
544 echo "Adding new option \"${option}\" to mailcow.conf"
545 echo '# Bind SQL to 127.0.0.1 on port 13306' >> mailcow.conf
546 echo "SQL_PORT=127.0.0.1:13306" >> mailcow.conf
547 fi
548 elif [[ ${option} == "API_KEY" ]]; then
549 if ! grep -q ${option} mailcow.conf; then
550 echo "Adding new option \"${option}\" to mailcow.conf"
551 echo '# Create or override API key for web UI' >> mailcow.conf
552 echo "#API_KEY=" >> mailcow.conf
553 fi
554 elif [[ ${option} == "API_KEY_READ_ONLY" ]]; then
555 if ! grep -q ${option} mailcow.conf; then
556 echo "Adding new option \"${option}\" to mailcow.conf"
557 echo '# Create or override read-only API key for web UI' >> mailcow.conf
558 echo "#API_KEY_READ_ONLY=" >> mailcow.conf
559 fi
560 elif [[ ${option} == "API_ALLOW_FROM" ]]; then
561 if ! grep -q ${option} mailcow.conf; then
562 echo "Adding new option \"${option}\" to mailcow.conf"
563 echo '# Must be set for API_KEY to be active' >> mailcow.conf
564 echo '# IPs only, no networks (networks can be set via UI)' >> mailcow.conf
565 echo "#API_ALLOW_FROM=" >> mailcow.conf
566 fi
567 elif [[ ${option} == "SNAT_TO_SOURCE" ]]; then
568 if ! grep -q ${option} mailcow.conf; then
569 echo "Adding new option \"${option}\" to mailcow.conf"
570 echo '# Use this IPv4 for outgoing connections (SNAT)' >> mailcow.conf
571 echo "#SNAT_TO_SOURCE=" >> mailcow.conf
572 fi
573 elif [[ ${option} == "SNAT6_TO_SOURCE" ]]; then
574 if ! grep -q ${option} mailcow.conf; then
575 echo "Adding new option \"${option}\" to mailcow.conf"
576 echo '# Use this IPv6 for outgoing connections (SNAT)' >> mailcow.conf
577 echo "#SNAT6_TO_SOURCE=" >> mailcow.conf
578 fi
579 elif [[ ${option} == "MAILDIR_GC_TIME" ]]; then
580 if ! grep -q ${option} mailcow.conf; then
581 echo "Adding new option \"${option}\" to mailcow.conf"
582 echo '# Garbage collector cleanup' >> mailcow.conf
583 echo '# Deleted domains and mailboxes are moved to /var/vmail/_garbage/timestamp_sanitizedstring' >> mailcow.conf
584 echo '# How long should objects remain in the garbage until they are being deleted? (value in minutes)' >> mailcow.conf
585 echo '# Check interval is hourly' >> mailcow.conf
586 echo 'MAILDIR_GC_TIME=1440' >> mailcow.conf
587 fi
588 elif [[ ${option} == "ACL_ANYONE" ]]; then
589 if ! grep -q ${option} mailcow.conf; then
590 echo "Adding new option \"${option}\" to mailcow.conf"
591 echo '# Set this to "allow" to enable the anyone pseudo user. Disabled by default.' >> mailcow.conf
592 echo '# When enabled, ACL can be created, that apply to "All authenticated users"' >> mailcow.conf
593 echo '# This should probably only be activated on mail hosts, that are used exclusivly by one organisation.' >> mailcow.conf
594 echo '# Otherwise a user might share data with too many other users.' >> mailcow.conf
595 echo 'ACL_ANYONE=disallow' >> mailcow.conf
596 fi
597 elif [[ ${option} == "SOLR_HEAP" ]]; then
598 if ! grep -q ${option} mailcow.conf; then
599 echo "Adding new option \"${option}\" to mailcow.conf"
600 echo '# Solr heap size, there is no recommendation, please see Solr docs.' >> mailcow.conf
601 echo '# Solr is a prone to run OOM on large systems and should be monitored. Unmonitored Solr setups are not recommended.' >> mailcow.conf
602 echo '# Solr will refuse to start with total system memory below or equal to 2 GB.' >> mailcow.conf
603 echo "SOLR_HEAP=1024" >> mailcow.conf
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +0200604 fi
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100605 elif [[ ${option} == "SKIP_SOLR" ]]; then
606 if ! grep -q ${option} mailcow.conf; then
607 echo "Adding new option \"${option}\" to mailcow.conf"
608 echo '# Solr is disabled by default after upgrading from non-Solr to Solr-enabled mailcows.' >> mailcow.conf
609 echo '# Disable Solr or if you do not want to store a readable index of your mails in solr-vol-1.' >> mailcow.conf
610 echo "SKIP_SOLR=y" >> mailcow.conf
611 fi
612 elif [[ ${option} == "ENABLE_SSL_SNI" ]]; then
613 if ! grep -q ${option} mailcow.conf; then
614 echo "Adding new option \"${option}\" to mailcow.conf"
615 echo '# Create seperate certificates for all domains - y/n' >> mailcow.conf
616 echo '# this will allow adding more than 100 domains, but some email clients will not be able to connect with alternative hostnames' >> mailcow.conf
617 echo '# see https://wiki.dovecot.org/SSL/SNIClientSupport' >> mailcow.conf
618 echo "ENABLE_SSL_SNI=n" >> mailcow.conf
619 fi
620 elif [[ ${option} == "SKIP_SOGO" ]]; then
621 if ! grep -q ${option} mailcow.conf; then
622 echo "Adding new option \"${option}\" to mailcow.conf"
623 echo '# Skip SOGo: Will disable SOGo integration and therefore webmail, DAV protocols and ActiveSync support (experimental, unsupported, not fully implemented) - y/n' >> mailcow.conf
624 echo "SKIP_SOGO=n" >> mailcow.conf
625 fi
626 elif [[ ${option} == "MAILDIR_SUB" ]]; then
627 if ! grep -q ${option} mailcow.conf; then
628 echo "Adding new option \"${option}\" to mailcow.conf"
629 echo '# MAILDIR_SUB defines a path in a users virtual home to keep the maildir in. Leave empty for updated setups.' >> mailcow.conf
630 echo "#MAILDIR_SUB=Maildir" >> mailcow.conf
631 echo "MAILDIR_SUB=" >> mailcow.conf
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +0200632 fi
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100633 elif [[ ${option} == "WATCHDOG_NOTIFY_BAN" ]]; then
634 if ! grep -q ${option} mailcow.conf; then
635 echo "Adding new option \"${option}\" to mailcow.conf"
636 echo '# Notify about banned IP. Includes whois lookup.' >> mailcow.conf
637 echo "WATCHDOG_NOTIFY_BAN=y" >> mailcow.conf
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +0200638 fi
639 elif [[ ${option} == "WATCHDOG_SUBJECT" ]]; then
640 if ! grep -q ${option} mailcow.conf; then
641 echo "Adding new option \"${option}\" to mailcow.conf"
642 echo '# Subject for watchdog mails. Defaults to "Watchdog ALERT" followed by the error message.' >> mailcow.conf
643 echo "#WATCHDOG_SUBJECT=" >> mailcow.conf
644 fi
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100645 elif [[ ${option} == "WATCHDOG_EXTERNAL_CHECKS" ]]; then
646 if ! grep -q ${option} mailcow.conf; then
647 echo "Adding new option \"${option}\" to mailcow.conf"
648 echo '# Checks if mailcow is an open relay. Requires a SAL. More checks will follow.' >> mailcow.conf
649 echo '# No data is collected. Opt-in and anonymous.' >> mailcow.conf
650 echo '# Will only work with unmodified mailcow setups.' >> mailcow.conf
651 echo "WATCHDOG_EXTERNAL_CHECKS=n" >> mailcow.conf
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +0200652 fi
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100653 elif [[ ${option} == "SOGO_EXPIRE_SESSION" ]]; then
654 if ! grep -q ${option} mailcow.conf; then
655 echo "Adding new option \"${option}\" to mailcow.conf"
656 echo '# SOGo session timeout in minutes' >> mailcow.conf
657 echo "SOGO_EXPIRE_SESSION=480" >> mailcow.conf
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +0200658 fi
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100659 elif [[ ${option} == "REDIS_PORT" ]]; then
660 if ! grep -q ${option} mailcow.conf; then
661 echo "Adding new option \"${option}\" to mailcow.conf"
662 echo "REDIS_PORT=127.0.0.1:7654" >> mailcow.conf
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +0200663 fi
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100664 elif [[ ${option} == "DOVECOT_MASTER_USER" ]]; then
665 if ! grep -q ${option} mailcow.conf; then
666 echo "Adding new option \"${option}\" to mailcow.conf"
667 echo '# DOVECOT_MASTER_USER and _PASS must _both_ be provided. No special chars.' >> mailcow.conf
668 echo '# Empty by default to auto-generate master user and password on start.' >> mailcow.conf
669 echo '# User expands to DOVECOT_MASTER_USER@mailcow.local' >> mailcow.conf
670 echo '# LEAVE EMPTY IF UNSURE' >> mailcow.conf
671 echo "DOVECOT_MASTER_USER=" >> mailcow.conf
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +0200672 fi
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100673 elif [[ ${option} == "DOVECOT_MASTER_PASS" ]]; then
674 if ! grep -q ${option} mailcow.conf; then
675 echo "Adding new option \"${option}\" to mailcow.conf"
676 echo '# LEAVE EMPTY IF UNSURE' >> mailcow.conf
677 echo "DOVECOT_MASTER_PASS=" >> mailcow.conf
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +0200678 fi
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100679 elif [[ ${option} == "MAILCOW_PASS_SCHEME" ]]; then
680 if ! grep -q ${option} mailcow.conf; then
681 echo "Adding new option \"${option}\" to mailcow.conf"
682 echo '# Password hash algorithm' >> mailcow.conf
683 echo '# Only certain password hash algorithm are supported. For a fully list of supported schemes,' >> mailcow.conf
Matthias Andreas Benkardd1f5b682023-11-18 13:18:30 +0100684 echo '# see https://docs.mailcow.email/models/model-passwd/' >> mailcow.conf
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100685 echo "MAILCOW_PASS_SCHEME=BLF-CRYPT" >> mailcow.conf
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +0200686 fi
687 elif [[ ${option} == "ADDITIONAL_SERVER_NAMES" ]]; then
688 if ! grep -q ${option} mailcow.conf; then
Matthias Andreas Benkardd1f5b682023-11-18 13:18:30 +0100689 echo "Adding new option \"${option}\" to mailcow.conf"
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +0200690 echo '# Additional server names for mailcow UI' >> mailcow.conf
691 echo '#' >> mailcow.conf
692 echo '# Specify alternative addresses for the mailcow UI to respond to' >> mailcow.conf
693 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
694 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
695 echo '# You can understand this as server_name directive in Nginx.' >> mailcow.conf
696 echo '# Comma separated list without spaces! Example: ADDITIONAL_SERVER_NAMES=a.b.c,d.e.f' >> mailcow.conf
697 echo 'ADDITIONAL_SERVER_NAMES=' >> mailcow.conf
698 fi
699 elif [[ ${option} == "ACME_CONTACT" ]]; then
700 if ! grep -q ${option} mailcow.conf; then
Matthias Andreas Benkardd1f5b682023-11-18 13:18:30 +0100701 echo "Adding new option \"${option}\" to mailcow.conf"
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +0200702 echo '# Lets Encrypt registration contact information' >> mailcow.conf
703 echo '# Optional: Leave empty for none' >> mailcow.conf
704 echo '# This value is only used on first order!' >> mailcow.conf
705 echo '# Setting it at a later point will require the following steps:' >> mailcow.conf
Matthias Andreas Benkardd1f5b682023-11-18 13:18:30 +0100706 echo '# https://docs.mailcow.email/troubleshooting/debug-reset_tls/' >> mailcow.conf
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +0200707 echo 'ACME_CONTACT=' >> mailcow.conf
Matthias Andreas Benkardd1f5b682023-11-18 13:18:30 +0100708 fi
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +0100709 elif [[ ${option} == "WEBAUTHN_ONLY_TRUSTED_VENDORS" ]]; then
710 if ! grep -q ${option} mailcow.conf; then
Matthias Andreas Benkardd1f5b682023-11-18 13:18:30 +0100711 echo "Adding new option \"${option}\" to mailcow.conf"
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +0100712 echo "# WebAuthn device manufacturer verification" >> mailcow.conf
713 echo '# After setting WEBAUTHN_ONLY_TRUSTED_VENDORS=y only devices from trusted manufacturers are allowed' >> mailcow.conf
714 echo '# root certificates can be placed for validation under mailcow-dockerized/data/web/inc/lib/WebAuthn/rootCertificates' >> mailcow.conf
715 echo 'WEBAUTHN_ONLY_TRUSTED_VENDORS=n' >> mailcow.conf
716 fi
Matthias Andreas Benkardd1f5b682023-11-18 13:18:30 +0100717 elif [[ ${option} == "SPAMHAUS_DQS_KEY" ]]; then
Matthias Andreas Benkard12a57352021-12-28 18:02:04 +0100718 if ! grep -q ${option} mailcow.conf; then
Matthias Andreas Benkardd1f5b682023-11-18 13:18:30 +0100719 echo "Adding new option \"${option}\" to mailcow.conf"
720 echo "# Spamhaus Data Query Service Key" >> mailcow.conf
721 echo '# Optional: Leave empty for none' >> mailcow.conf
722 echo '# Enter your key here if you are using a blocked ASN (OVH, AWS, Cloudflare e.g) for the unregistered Spamhaus Blocklist.' >> mailcow.conf
723 echo '# If empty, it will completely disable Spamhaus blocklists if it detects that you are running on a server using a blocked AS.' >> mailcow.conf
724 echo '# Otherwise it will work as usual.' >> mailcow.conf
725 echo 'SPAMHAUS_DQS_KEY=' >> mailcow.conf
726 fi
727 elif [[ ${option} == "WATCHDOG_VERBOSE" ]]; then
728 if ! grep -q ${option} mailcow.conf; then
729 echo "Adding new option \"${option}\" to mailcow.conf"
Matthias Andreas Benkard12a57352021-12-28 18:02:04 +0100730 echo '# Enable watchdog verbose logging' >> mailcow.conf
731 echo 'WATCHDOG_VERBOSE=n' >> mailcow.conf
Matthias Andreas Benkardd1f5b682023-11-18 13:18:30 +0100732 fi
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100733 elif ! grep -q ${option} mailcow.conf; then
734 echo "Adding new option \"${option}\" to mailcow.conf"
735 echo "${option}=n" >> mailcow.conf
736 fi
737done
738
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +0100739if [[( ${SKIP_PING_CHECK} == "y")]]; then
740echo -e "\e[32mSkipping Ping Check...\e[0m"
741
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100742else
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +0100743 echo -en "Checking internet connection... "
744 if ! check_online_status; then
745 echo -e "\e[31mfailed\e[0m"
746 exit 1
747 else
748 echo -e "\e[32mOK\e[0m"
749 fi
750fi
751
752if ! [ $NEW_BRANCH ]; then
753 echo -e "\e[33mDetecting which build your mailcow runs on...\e[0m"
754 sleep 1
755 if [ ${BRANCH} == "master" ]; then
756 echo -e "\e[32mYou are receiving stable updates (master).\e[0m"
757 echo -e "\e[33mTo change that run the update.sh Script one time with the --nightly parameter to switch to nightly builds.\e[0m"
758
759 elif [ ${BRANCH} == "nightly" ]; then
760 echo -e "\e[31mYou are receiving unstable updates (nightly). These are for testing purposes only!!!\e[0m"
761 sleep 1
762 echo -e "\e[33mTo change that run the update.sh Script one time with the --stable parameter to switch to stable builds.\e[0m"
763
764 else
765 echo -e "\e[33mYou are receiving updates from a unsupported branch.\e[0m"
766 sleep 1
767 echo -e "\e[33mThe mailcow stack might still work but it is recommended to switch to the master branch (stable builds).\e[0m"
768 echo -e "\e[33mTo change that run the update.sh Script one time with the --stable parameter to switch to stable builds.\e[0m"
769 fi
770elif [ $FORCE ]; then
771 echo -e "\e[31mYou are running in forced mode!\e[0m"
772 echo -e "\e[31mA Branch Switch can only be performed manually (monitored).\e[0m"
773 echo -e "\e[31mPlease rerun the update.sh Script without the --force/-f parameter.\e[0m"
774 sleep 1
775elif [ $NEW_BRANCH == "master" ] && [ $CURRENT_BRANCH != "master" ]; then
776 echo -e "\e[33mYou are about to switch your mailcow Updates to the stable (master) branch.\e[0m"
777 sleep 1
778 echo -e "\e[33mBefore you do: Please take a backup of all components to ensure that no Data is lost...\e[0m"
779 sleep 1
780 echo -e "\e[31mWARNING: Please see on GitHub or ask in the communitys if a switch to master is stable or not.
781 In some rear cases a Update back to master can destroy your mailcow configuration in case of Database Upgrades etc.
782 Normally a upgrade back to master should be safe during each full release.
783 Check GitHub for Database Changes and Update only if there similar to the full release!\e[0m"
784 read -r -p "Are you sure you that want to continue upgrading to the stable (master) branch? [y/N] " response
785 if [[ ! "${response}" =~ ^([yY][eE][sS]|[yY])+$ ]]; then
786 echo "OK. If you prepared yourself for that please run the update.sh Script with the --stable parameter again to trigger this process here."
787 exit 0
788 fi
789 BRANCH=$NEW_BRANCH
790 DIFF_DIRECTORY=update_diffs
791 DIFF_FILE=${DIFF_DIRECTORY}/diff_before_upgrade_to_master_$(date +"%Y-%m-%d-%H-%M-%S")
792 mv diff_before_upgrade* ${DIFF_DIRECTORY}/ 2> /dev/null
793 if ! git diff-index --quiet HEAD; then
794 echo -e "\e[32mSaving diff to ${DIFF_FILE}...\e[0m"
795 mkdir -p ${DIFF_DIRECTORY}
796 git diff ${BRANCH} --stat > ${DIFF_FILE}
797 git diff ${BRANCH} >> ${DIFF_FILE}
798 fi
799 echo -e "\e[32mSwitching Branch to ${BRANCH}...\e[0m"
800 git fetch origin
801 git checkout -f ${BRANCH}
802
803elif [ $NEW_BRANCH == "nightly" ] && [ $CURRENT_BRANCH != "nightly" ]; then
804 echo -e "\e[33mYou are about to switch your mailcow Updates to the unstable (nightly) branch.\e[0m"
805 sleep 1
806 echo -e "\e[33mBefore you do: Please take a backup of all components to ensure that no Data is lost...\e[0m"
807 sleep 1
808 echo -e "\e[31mWARNING: A switch to nightly is possible any time. But a switch back (to master) isn't.\e[0m"
809 read -r -p "Are you sure you that want to continue upgrading to the unstable (nightly) branch? [y/N] " response
810 if [[ ! "${response}" =~ ^([yY][eE][sS]|[yY])+$ ]]; then
811 echo "OK. If you prepared yourself for that please run the update.sh Script with the --nightly parameter again to trigger this process here."
812 exit 0
813 fi
814 BRANCH=$NEW_BRANCH
815 DIFF_DIRECTORY=update_diffs
816 DIFF_FILE=${DIFF_DIRECTORY}/diff_before_upgrade_to_nightly_$(date +"%Y-%m-%d-%H-%M-%S")
817 mv diff_before_upgrade* ${DIFF_DIRECTORY}/ 2> /dev/null
818 if ! git diff-index --quiet HEAD; then
819 echo -e "\e[32mSaving diff to ${DIFF_FILE}...\e[0m"
820 mkdir -p ${DIFF_DIRECTORY}
821 git diff ${BRANCH} --stat > ${DIFF_FILE}
822 git diff ${BRANCH} >> ${DIFF_FILE}
823 fi
824 git fetch origin
825 git checkout -f ${BRANCH}
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100826fi
827
Matthias Andreas Benkardd1f5b682023-11-18 13:18:30 +0100828if [ ! $DEV ]; then
829 echo -e "\e[32mChecking for newer update script...\e[0m"
830 SHA1_1=$(sha1sum update.sh)
831 git fetch origin #${BRANCH}
832 git checkout origin/${BRANCH} update.sh
833 SHA1_2=$(sha1sum update.sh)
834 if [[ ${SHA1_1} != ${SHA1_2} ]]; then
835 echo "update.sh changed, please run this script again, exiting."
836 chmod +x update.sh
837 exit 2
838 fi
Matthias Andreas Benkarda515bc62023-11-18 16:44:25 +0100839fi
840
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100841if [ ! $FORCE ]; then
842 read -r -p "Are you sure you want to update mailcow: dockerized? All containers will be stopped. [y/N] " response
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +0200843 if [[ ! "${response}" =~ ^([yY][eE][sS]|[yY])+$ ]]; then
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100844 echo "OK, exiting."
845 exit 0
846 fi
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +0200847 migrate_docker_nat
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100848fi
849
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +0100850remove_obsolete_nginx_ports
851
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100852echo -e "\e[32mValidating docker-compose stack configuration...\e[0m"
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +0100853sed -i 's/HTTPS_BIND:-:/HTTPS_BIND:-/g' docker-compose.yml
854sed -i 's/HTTP_BIND:-:/HTTP_BIND:-/g' docker-compose.yml
855if ! $COMPOSE_COMMAND config -q; then
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100856 echo -e "\e[31m\nOh no, something went wrong. Please check the error message above.\e[0m"
857 exit 1
858fi
859
860echo -e "\e[32mChecking for conflicting bridges...\e[0m"
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +0100861MAILCOW_BRIDGE=$($COMPOSE_COMMAND config | grep -i com.docker.network.bridge.name | cut -d':' -f2)
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100862while read NAT_ID; do
863 iptables -t nat -D POSTROUTING $NAT_ID
864done < <(iptables -L -vn -t nat --line-numbers | grep $IPV4_NETWORK | grep -E 'MASQUERADE.*all' | grep -v ${MAILCOW_BRIDGE} | cut -d' ' -f1)
865
866DIFF_DIRECTORY=update_diffs
867DIFF_FILE=${DIFF_DIRECTORY}/diff_before_update_$(date +"%Y-%m-%d-%H-%M-%S")
868mv diff_before_update* ${DIFF_DIRECTORY}/ 2> /dev/null
869if ! git diff-index --quiet HEAD; then
870 echo -e "\e[32mSaving diff to ${DIFF_FILE}...\e[0m"
871 mkdir -p ${DIFF_DIRECTORY}
872 git diff --stat > ${DIFF_FILE}
873 git diff >> ${DIFF_FILE}
874fi
875
876echo -e "\e[32mPrefetching images...\e[0m"
877prefetch_images
878
879echo -e "\e[32mStopping mailcow...\e[0m"
880sleep 2
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +0100881MAILCOW_CONTAINERS=($($COMPOSE_COMMAND ps -q))
882$COMPOSE_COMMAND down
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100883echo -e "\e[32mChecking for remaining containers...\e[0m"
884sleep 2
885for container in "${MAILCOW_CONTAINERS[@]}"; do
886 docker rm -f "$container" 2> /dev/null
887done
888
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +0200889[[ -f data/conf/nginx/ZZZ-ejabberd.conf ]] && rm data/conf/nginx/ZZZ-ejabberd.conf
890
Matthias Andreas Benkardd1f5b682023-11-18 13:18:30 +0100891
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100892# Silently fixing remote url from andryyy to mailcow
Matthias Andreas Benkardd1f5b682023-11-18 13:18:30 +0100893# git remote set-url origin https://github.com/mailcow/mailcow-dockerized
894
895DEFAULT_REPO=https://github.com/mailcow/mailcow-dockerized
896CURRENT_REPO=$(git remote get-url origin)
897if [ "$CURRENT_REPO" != "$DEFAULT_REPO" ]; then
898 echo "The Repository currently used is not the default Mailcow Repository."
899 echo "Currently Repository: $CURRENT_REPO"
900 echo "Default Repository: $DEFAULT_REPO"
901 read -r -p "Should it be changed back to default? [y/N] " repo_response
902 if [[ "$repo_response" =~ ^([yY][eE][sS]|[yY])+$ ]]; then
903 git remote set-url origin $DEFAULT_REPO
904 fi
905fi
906
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100907echo -e "\e[32mCommitting current status...\e[0m"
908[[ -z "$(git config user.name)" ]] && git config user.name moo
909[[ -z "$(git config user.email)" ]] && git config user.email moo@cow.moo
910[[ ! -z $(git ls-files data/conf/rspamd/override.d/worker-controller-password.inc) ]] && git rm data/conf/rspamd/override.d/worker-controller-password.inc
911git add -u
912git commit -am "Before update on ${DATE}" > /dev/null
913echo -e "\e[32mFetching updated code from remote...\e[0m"
914git fetch origin #${BRANCH}
915echo -e "\e[32mMerging local with remote code (recursive, strategy: \"${MERGE_STRATEGY:-theirs}\", options: \"patience\"...\e[0m"
916git config merge.defaultToUpstream true
917git merge -X${MERGE_STRATEGY:-theirs} -Xpatience -m "After update on ${DATE}"
918# Need to use a variable to not pass return codes of if checks
919MERGE_RETURN=$?
920if [[ ${MERGE_RETURN} == 128 ]]; then
921 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"
922 exit 1
923elif [[ ${MERGE_RETURN} == 1 ]]; then
924 echo -e "\e[93mPotenial conflict, trying to fix...\e[0m"
925 git status --porcelain | grep -E "UD|DU" | awk '{print $2}' | xargs rm -v
926 git add -A
927 git commit -m "After update on ${DATE}" > /dev/null
928 git checkout .
929 echo -e "\e[32mRemoved and recreated files if necessary.\e[0m"
930elif [[ ${MERGE_RETURN} != 0 ]]; then
931 echo -e "\e[31m\nOh no, something went wrong. Please check the error message above.\e[0m"
932 echo
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +0100933 echo "Run $COMPOSE_COMMAND up -d to restart your stack without updates or try again after fixing the mentioned errors."
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100934 exit 1
935fi
936
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100937echo -e "\e[32mFetching new images, if any...\e[0m"
938sleep 2
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +0100939$COMPOSE_COMMAND pull
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100940
941# Fix missing SSL, does not overwrite existing files
942[[ ! -d data/assets/ssl ]] && mkdir -p data/assets/ssl
943cp -n -d data/assets/ssl-example/*.pem data/assets/ssl/
944
945echo -e "Checking IPv6 settings... "
946if grep -q 'SYSCTL_IPV6_DISABLED=1' mailcow.conf; then
947 echo
948 echo '!! IMPORTANT !!'
949 echo
950 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".'
Matthias Andreas Benkardd1f5b682023-11-18 13:18:30 +0100951 echo "This setting will only be active after a complete shutdown of mailcow by running $COMPOSE_COMMAND down followed by $COMPOSE_COMMAND up -d."
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100952 echo
953 echo '!! IMPORTANT !!'
954 echo
955 read -p "Press any key to continue..." < /dev/tty
956fi
957
958# Checking for old project name bug
959sed -i --follow-symlinks 's#COMPOSEPROJECT_NAME#COMPOSE_PROJECT_NAME#g' mailcow.conf
960
961# Fix Rspamd maps
962if [ -f data/conf/rspamd/custom/global_from_blacklist.map ]; then
963 mv data/conf/rspamd/custom/global_from_blacklist.map data/conf/rspamd/custom/global_smtp_from_blacklist.map
964fi
965if [ -f data/conf/rspamd/custom/global_from_whitelist.map ]; then
966 mv data/conf/rspamd/custom/global_from_whitelist.map data/conf/rspamd/custom/global_smtp_from_whitelist.map
967fi
968
969# Fix deprecated metrics.conf
970if [ -f "data/conf/rspamd/local.d/metrics.conf" ]; then
971 if [ ! -z "$(git diff --name-only origin/master data/conf/rspamd/local.d/metrics.conf)" ]; then
972 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."
973 echo "The deprecated configuration file metrics.conf will be moved to metrics.conf_deprecated after updating mailcow."
974 fi
975 mv data/conf/rspamd/local.d/metrics.conf data/conf/rspamd/local.d/metrics.conf_deprecated
976fi
977
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +0100978# Set app_info.inc.php
979if [ ${BRANCH} == "master" ]; then
980 mailcow_git_version=$(git describe --tags `git rev-list --tags --max-count=1`)
981elif [ ${BRANCH} == "nightly" ]; then
982 mailcow_git_version=$(git rev-parse --short $(git rev-parse @{upstream}))
983 mailcow_last_git_version=""
984else
985 mailcow_git_version=$(git rev-parse --short HEAD)
986 mailcow_last_git_version=""
987fi
988
989mailcow_git_commit=$(git rev-parse origin/${BRANCH})
990mailcow_git_commit_date=$(git log -1 --format=%ci @{upstream} )
991
992if [ $? -eq 0 ]; then
993 echo '<?php' > data/web/inc/app_info.inc.php
994 echo ' $MAILCOW_GIT_VERSION="'$mailcow_git_version'";' >> data/web/inc/app_info.inc.php
995 echo ' $MAILCOW_LAST_GIT_VERSION="";' >> data/web/inc/app_info.inc.php
996 echo ' $MAILCOW_GIT_OWNER="mailcow";' >> data/web/inc/app_info.inc.php
997 echo ' $MAILCOW_GIT_REPO="mailcow-dockerized";' >> data/web/inc/app_info.inc.php
998 echo ' $MAILCOW_GIT_URL="https://github.com/mailcow/mailcow-dockerized";' >> data/web/inc/app_info.inc.php
999 echo ' $MAILCOW_GIT_COMMIT="'$mailcow_git_commit'";' >> data/web/inc/app_info.inc.php
1000 echo ' $MAILCOW_GIT_COMMIT_DATE="'$mailcow_git_commit_date'";' >> data/web/inc/app_info.inc.php
1001 echo ' $MAILCOW_BRANCH="'$BRANCH'";' >> data/web/inc/app_info.inc.php
1002 echo ' $MAILCOW_UPDATEDAT='$(date +%s)';' >> data/web/inc/app_info.inc.php
1003 echo '?>' >> data/web/inc/app_info.inc.php
1004else
1005 echo '<?php' > data/web/inc/app_info.inc.php
1006 echo ' $MAILCOW_GIT_VERSION="'$mailcow_git_version'";' >> data/web/inc/app_info.inc.php
1007 echo ' $MAILCOW_LAST_GIT_VERSION="";' >> data/web/inc/app_info.inc.php
1008 echo ' $MAILCOW_GIT_OWNER="mailcow";' >> data/web/inc/app_info.inc.php
1009 echo ' $MAILCOW_GIT_REPO="mailcow-dockerized";' >> data/web/inc/app_info.inc.php
1010 echo ' $MAILCOW_GIT_URL="https://github.com/mailcow/mailcow-dockerized";' >> data/web/inc/app_info.inc.php
1011 echo ' $MAILCOW_GIT_COMMIT="";' >> data/web/inc/app_info.inc.php
1012 echo ' $MAILCOW_GIT_COMMIT_DATE="";' >> data/web/inc/app_info.inc.php
1013 echo ' $MAILCOW_BRANCH="'$BRANCH'";' >> data/web/inc/app_info.inc.php
1014 echo ' $MAILCOW_UPDATEDAT='$(date +%s)';' >> data/web/inc/app_info.inc.php
1015 echo '?>' >> data/web/inc/app_info.inc.php
1016 echo -e "\e[33mCannot determine current git repository version...\e[0m"
1017fi
1018
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01001019if [[ ${SKIP_START} == "y" ]]; then
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +01001020 echo -e "\e[33mNot starting mailcow, please run \"$COMPOSE_COMMAND up -d --remove-orphans\" to start mailcow.\e[0m"
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01001021else
1022 echo -e "\e[32mStarting mailcow...\e[0m"
1023 sleep 2
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +01001024 $COMPOSE_COMMAND up -d --remove-orphans
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01001025fi
1026
1027echo -e "\e[32mCollecting garbage...\e[0m"
1028docker_garbage
1029
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02001030# Run post-update-hook
1031if [ -f "${SCRIPT_DIR}/post_update_hook.sh" ]; then
1032 bash "${SCRIPT_DIR}/post_update_hook.sh"
1033fi
1034
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +01001035# echo "In case you encounter any problem, hard-reset to a state before updating mailcow:"
1036# echo
1037# git reflog --color=always | grep "Before update on "
1038# echo
Matthias Andreas Benkarda515bc62023-11-18 16:44:25 +01001039# echo "Use \"git reset --hard hash-on-the-left\" and run $COMPOSE_COMMAND up -d afterwards."