blob: 20e9fd10c295f891459c8bb374310e896054f4a0 [file] [log] [blame]
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01001#!/usr/bin/env bash
2
3# Check permissions
4if [ "$(id -u)" -ne "0" ]; then
5 echo "You need to be root"
6 exit 1
7fi
8
9if [[ "$(uname -r)" =~ ^4\.15\.0-60 ]]; then
10 echo "DO NOT RUN mailcow ON THIS UBUNTU KERNEL!";
11 echo "Please update to 5.x or use another distribution."
12 exit 1
13fi
14
15if [[ "$(uname -r)" =~ ^4\.4\. ]]; then
16 if grep -q Ubuntu <<< $(uname -a); then
17 echo "DO NOT RUN mailcow ON THIS UBUNTU KERNEL!"
18 echo "Please update to linux-generic-hwe-16.04 by running \"apt-get install --install-recommends linux-generic-hwe-16.04\""
19 exit 1
20 fi
21 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."
22 read -p "Press any key to continue..." < /dev/tty
23fi
24
25# Exit on error and pipefail
26set -o pipefail
27
28# Setting high dc timeout
29export COMPOSE_HTTP_TIMEOUT=600
30
31# Add /opt/bin to PATH
32PATH=$PATH:/opt/bin
33
34umask 0022
35
36for bin in curl docker-compose docker git awk sha1sum; do
37 if [[ -z $(which ${bin}) ]]; then echo "Cannot find ${bin}, exiting..."; exit 1; fi
38done
39
40export LC_ALL=C
41DATE=$(date +%Y-%m-%d_%H_%M_%S)
42BRANCH=$(git rev-parse --abbrev-ref HEAD)
43
44check_online_status() {
45 CHECK_ONLINE_IPS=(1.1.1.1 9.9.9.9 8.8.8.8)
46 for ip in "${CHECK_ONLINE_IPS[@]}"; do
47 if timeout 3 ping -c 1 ${ip} > /dev/null; then
48 return 0
49 fi
50 done
51 return 1
52}
53
54prefetch_images() {
55 [[ -z ${BRANCH} ]] && { echo -e "\e[33m\nUnknown branch...\e[0m"; exit 1; }
56 git fetch origin #${BRANCH}
57 while read image; do
58 RET_C=0
59 until docker pull ${image}; do
60 RET_C=$((RET_C + 1))
61 echo -e "\e[33m\nError pulling $image, retrying...\e[0m"
62 [ ${RET_C} -gt 3 ] && { echo -e "\e[31m\nToo many failed retries, exiting\e[0m"; exit 1; }
63 sleep 1
64 done
65 done < <(git show origin/${BRANCH}:docker-compose.yml | grep "image:" | awk '{ gsub("image:","", $3); print $2 }')
66}
67
68docker_garbage() {
69 IMGS_TO_DELETE=()
70 for container in $(grep -oP "image: \Kmailcow.+" docker-compose.yml); do
71 REPOSITORY=${container/:*}
72 TAG=${container/*:}
73 V_MAIN=${container/*.}
74 V_SUB=${container/*.}
75 EXISTING_TAGS=$(docker images | grep ${REPOSITORY} | awk '{ print $2 }')
76 for existing_tag in ${EXISTING_TAGS[@]}; do
77 V_MAIN_EXISTING=${existing_tag/*.}
78 V_SUB_EXISTING=${existing_tag/*.}
79 # Not an integer
80 [[ ! $V_MAIN_EXISTING =~ ^[0-9]+$ ]] && continue
81 [[ ! $V_SUB_EXISTING =~ ^[0-9]+$ ]] && continue
82
83 if [[ $V_MAIN_EXISTING == "latest" ]]; then
84 echo "Found deprecated label \"latest\" for repository $REPOSITORY, it should be deleted."
85 IMGS_TO_DELETE+=($REPOSITORY:$existing_tag)
86 elif [[ $V_MAIN_EXISTING -lt $V_MAIN ]]; then
87 echo "Found tag $existing_tag for $REPOSITORY, which is older than the current tag $TAG and should be deleted."
88 IMGS_TO_DELETE+=($REPOSITORY:$existing_tag)
89 elif [[ $V_SUB_EXISTING -lt $V_SUB ]]; then
90 echo "Found tag $existing_tag for $REPOSITORY, which is older than the current tag $TAG and should be deleted."
91 IMGS_TO_DELETE+=($REPOSITORY:$existing_tag)
92 fi
93 done
94 done
95
96 if [[ ! -z ${IMGS_TO_DELETE[*]} ]]; then
97 echo "Run the following command to delete unused image tags:"
98 echo
99 echo " docker rmi ${IMGS_TO_DELETE[*]}"
100 echo
101 if [ ! $FORCE ]; then
102 read -r -p "Do you want to delete old image tags right now? [y/N] " response
103 if [[ "$response" =~ ^([yY][eE][sS]|[yY])+$ ]]; then
104 docker rmi ${IMGS_TO_DELETE[*]}
105 else
106 echo "OK, skipped."
107 fi
108 else
109 echo "Skipped image removal because of force mode."
110 fi
111 fi
112 echo -e "\e[32mFurther cleanup...\e[0m"
113 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\""
114}
115
116while (($#)); do
117 case "${1}" in
118 --check|-c)
119 echo "Checking remote code for updates..."
120 LATEST_REV=$(git ls-remote --exit-code --refs --quiet https://github.com/mailcow/mailcow-dockerized ${BRANCH} | cut -f1)
121 if [ $? -ne 0 ]; then
122 echo "A problem occurred while trying to fetch the latest revision from github."
123 exit 99
124 fi
125 if [[ -z $(git log HEAD --pretty=format:"%H" | grep "${LATEST_REV}") ]]; then
126 echo "Updated code is available."
127 git log --date=short --pretty=format:"%ad - %s" $(git rev-parse --short HEAD)..origin/master
128 exit 0
129 else
130 echo "No updates available."
131 exit 3
132 fi
133 ;;
134 --ours)
135 MERGE_STRATEGY=ours
136 ;;
137 --skip-start)
138 SKIP_START=y
139 ;;
140 --gc)
141 echo -e "\e[32mCollecting garbage...\e[0m"
142 docker_garbage
143 exit 0
144 ;;
145 --prefetch)
146 echo -e "\e[32mPrefetching images...\e[0m"
147 prefetch_images
148 exit 0
149 ;;
150 -f|--force)
151 echo -e "\e[32mForcing Update...\e[0m"
152 FORCE=y
153 ;;
154 --no-update-compose)
155 NO_UPDATE_COMPOSE=y
156 ;;
157 --help|-h)
158 echo './update.sh [-c|--check, --ours, --gc, --no-update-compose, --prefetch, --skip-start, -f|--force, -h|--help]
159
160 -c|--check - Check for updates and exit (exit codes => 0: update available, 3: no updates)
161 --ours - Use merge strategy option "ours" to solve conflicts in favor of non-mailcow code (local changes over remote changes), not recommended!
162 --gc - Run garbage collector to delete old image tags
163 --no-update-compose - Do not update docker-compose
164 --prefetch - Only prefetch new images and exit (useful to prepare updates)
165 --skip-start - Do not start mailcow after update
166 -f|--force - Force update, do not ask questions
167'
168 exit 1
169 esac
170 shift
171done
172
173[[ ! -f mailcow.conf ]] && { echo "mailcow.conf is missing"; exit 1;}
174chmod 600 mailcow.conf
175source mailcow.conf
176DOTS=${MAILCOW_HOSTNAME//[^.]};
177if [ ${#DOTS} -lt 2 ]; then
178 echo "MAILCOW_HOSTNAME (${MAILCOW_HOSTNAME}) is not a FQDN!"
179 echo "Please change it to a FQDN and run docker-compose down followed by docker-compose up -d"
180 exit 1
181fi
182
183if 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
184if 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
185if 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
186
187CONFIG_ARRAY=(
188 "SKIP_LETS_ENCRYPT"
189 "SKIP_SOGO"
190 "USE_WATCHDOG"
191 "WATCHDOG_NOTIFY_EMAIL"
192 "WATCHDOG_NOTIFY_BAN"
193 "WATCHDOG_EXTERNAL_CHECKS"
194 "SKIP_CLAMD"
195 "SKIP_IP_CHECK"
196 "ADDITIONAL_SAN"
197 "DOVEADM_PORT"
198 "IPV4_NETWORK"
199 "IPV6_NETWORK"
200 "LOG_LINES"
201 "SNAT_TO_SOURCE"
202 "SNAT6_TO_SOURCE"
203 "COMPOSE_PROJECT_NAME"
204 "SQL_PORT"
205 "API_KEY"
206 "API_KEY_READ_ONLY"
207 "API_ALLOW_FROM"
208 "MAILDIR_GC_TIME"
209 "MAILDIR_SUB"
210 "ACL_ANYONE"
211 "SOLR_HEAP"
212 "SKIP_SOLR"
213 "ENABLE_SSL_SNI"
214 "ALLOW_ADMIN_EMAIL_LOGIN"
215 "SKIP_HTTP_VERIFICATION"
216 "SOGO_EXPIRE_SESSION"
217 "REDIS_PORT"
218 "DOVECOT_MASTER_USER"
219 "DOVECOT_MASTER_PASS"
220 "MAILCOW_PASS_SCHEME"
221)
222
223sed -i --follow-symlinks '$a\' mailcow.conf
224for option in ${CONFIG_ARRAY[@]}; do
225 if [[ ${option} == "ADDITIONAL_SAN" ]]; then
226 if ! grep -q ${option} mailcow.conf; then
227 echo "Adding new option \"${option}\" to mailcow.conf"
228 echo "${option}=" >> mailcow.conf
229 fi
230 elif [[ ${option} == "COMPOSE_PROJECT_NAME" ]]; then
231 if ! grep -q ${option} mailcow.conf; then
232 echo "Adding new option \"${option}\" to mailcow.conf"
233 echo "COMPOSE_PROJECT_NAME=mailcowdockerized" >> mailcow.conf
234 fi
235 elif [[ ${option} == "DOVEADM_PORT" ]]; then
236 if ! grep -q ${option} mailcow.conf; then
237 echo "Adding new option \"${option}\" to mailcow.conf"
238 echo "DOVEADM_PORT=127.0.0.1:19991" >> mailcow.conf
239 fi
240 elif [[ ${option} == "WATCHDOG_NOTIFY_EMAIL" ]]; then
241 if ! grep -q ${option} mailcow.conf; then
242 echo "Adding new option \"${option}\" to mailcow.conf"
243 echo "WATCHDOG_NOTIFY_EMAIL=" >> mailcow.conf
244 fi
245 elif [[ ${option} == "LOG_LINES" ]]; then
246 if ! grep -q ${option} mailcow.conf; then
247 echo "Adding new option \"${option}\" to mailcow.conf"
248 echo '# Max log lines per service to keep in Redis logs' >> mailcow.conf
249 echo "LOG_LINES=9999" >> mailcow.conf
250 fi
251 elif [[ ${option} == "IPV4_NETWORK" ]]; then
252 if ! grep -q ${option} mailcow.conf; then
253 echo "Adding new option \"${option}\" to mailcow.conf"
254 echo '# Internal IPv4 /24 subnet, format n.n.n. (expands to n.n.n.0/24)' >> mailcow.conf
255 echo "IPV4_NETWORK=172.22.1" >> mailcow.conf
256 fi
257 elif [[ ${option} == "IPV6_NETWORK" ]]; then
258 if ! grep -q ${option} mailcow.conf; then
259 echo "Adding new option \"${option}\" to mailcow.conf"
260 echo '# Internal IPv6 subnet in fc00::/7' >> mailcow.conf
261 echo "IPV6_NETWORK=fd4d:6169:6c63:6f77::/64" >> mailcow.conf
262 fi
263 elif [[ ${option} == "SQL_PORT" ]]; then
264 if ! grep -q ${option} mailcow.conf; then
265 echo "Adding new option \"${option}\" to mailcow.conf"
266 echo '# Bind SQL to 127.0.0.1 on port 13306' >> mailcow.conf
267 echo "SQL_PORT=127.0.0.1:13306" >> mailcow.conf
268 fi
269 elif [[ ${option} == "API_KEY" ]]; then
270 if ! grep -q ${option} mailcow.conf; then
271 echo "Adding new option \"${option}\" to mailcow.conf"
272 echo '# Create or override API key for web UI' >> mailcow.conf
273 echo "#API_KEY=" >> mailcow.conf
274 fi
275 elif [[ ${option} == "API_KEY_READ_ONLY" ]]; then
276 if ! grep -q ${option} mailcow.conf; then
277 echo "Adding new option \"${option}\" to mailcow.conf"
278 echo '# Create or override read-only API key for web UI' >> mailcow.conf
279 echo "#API_KEY_READ_ONLY=" >> mailcow.conf
280 fi
281 elif [[ ${option} == "API_ALLOW_FROM" ]]; then
282 if ! grep -q ${option} mailcow.conf; then
283 echo "Adding new option \"${option}\" to mailcow.conf"
284 echo '# Must be set for API_KEY to be active' >> mailcow.conf
285 echo '# IPs only, no networks (networks can be set via UI)' >> mailcow.conf
286 echo "#API_ALLOW_FROM=" >> mailcow.conf
287 fi
288 elif [[ ${option} == "SNAT_TO_SOURCE" ]]; then
289 if ! grep -q ${option} mailcow.conf; then
290 echo "Adding new option \"${option}\" to mailcow.conf"
291 echo '# Use this IPv4 for outgoing connections (SNAT)' >> mailcow.conf
292 echo "#SNAT_TO_SOURCE=" >> mailcow.conf
293 fi
294 elif [[ ${option} == "SNAT6_TO_SOURCE" ]]; then
295 if ! grep -q ${option} mailcow.conf; then
296 echo "Adding new option \"${option}\" to mailcow.conf"
297 echo '# Use this IPv6 for outgoing connections (SNAT)' >> mailcow.conf
298 echo "#SNAT6_TO_SOURCE=" >> mailcow.conf
299 fi
300 elif [[ ${option} == "MAILDIR_GC_TIME" ]]; then
301 if ! grep -q ${option} mailcow.conf; then
302 echo "Adding new option \"${option}\" to mailcow.conf"
303 echo '# Garbage collector cleanup' >> mailcow.conf
304 echo '# Deleted domains and mailboxes are moved to /var/vmail/_garbage/timestamp_sanitizedstring' >> mailcow.conf
305 echo '# How long should objects remain in the garbage until they are being deleted? (value in minutes)' >> mailcow.conf
306 echo '# Check interval is hourly' >> mailcow.conf
307 echo 'MAILDIR_GC_TIME=1440' >> mailcow.conf
308 fi
309 elif [[ ${option} == "ACL_ANYONE" ]]; then
310 if ! grep -q ${option} mailcow.conf; then
311 echo "Adding new option \"${option}\" to mailcow.conf"
312 echo '# Set this to "allow" to enable the anyone pseudo user. Disabled by default.' >> mailcow.conf
313 echo '# When enabled, ACL can be created, that apply to "All authenticated users"' >> mailcow.conf
314 echo '# This should probably only be activated on mail hosts, that are used exclusivly by one organisation.' >> mailcow.conf
315 echo '# Otherwise a user might share data with too many other users.' >> mailcow.conf
316 echo 'ACL_ANYONE=disallow' >> mailcow.conf
317 fi
318 elif [[ ${option} == "SOLR_HEAP" ]]; then
319 if ! grep -q ${option} mailcow.conf; then
320 echo "Adding new option \"${option}\" to mailcow.conf"
321 echo '# Solr heap size, there is no recommendation, please see Solr docs.' >> mailcow.conf
322 echo '# Solr is a prone to run OOM on large systems and should be monitored. Unmonitored Solr setups are not recommended.' >> mailcow.conf
323 echo '# Solr will refuse to start with total system memory below or equal to 2 GB.' >> mailcow.conf
324 echo "SOLR_HEAP=1024" >> mailcow.conf
325 fi
326 elif [[ ${option} == "SKIP_SOLR" ]]; then
327 if ! grep -q ${option} mailcow.conf; then
328 echo "Adding new option \"${option}\" to mailcow.conf"
329 echo '# Solr is disabled by default after upgrading from non-Solr to Solr-enabled mailcows.' >> mailcow.conf
330 echo '# Disable Solr or if you do not want to store a readable index of your mails in solr-vol-1.' >> mailcow.conf
331 echo "SKIP_SOLR=y" >> mailcow.conf
332 fi
333 elif [[ ${option} == "ENABLE_SSL_SNI" ]]; then
334 if ! grep -q ${option} mailcow.conf; then
335 echo "Adding new option \"${option}\" to mailcow.conf"
336 echo '# Create seperate certificates for all domains - y/n' >> mailcow.conf
337 echo '# this will allow adding more than 100 domains, but some email clients will not be able to connect with alternative hostnames' >> mailcow.conf
338 echo '# see https://wiki.dovecot.org/SSL/SNIClientSupport' >> mailcow.conf
339 echo "ENABLE_SSL_SNI=n" >> mailcow.conf
340 fi
341 elif [[ ${option} == "SKIP_SOGO" ]]; then
342 if ! grep -q ${option} mailcow.conf; then
343 echo "Adding new option \"${option}\" to mailcow.conf"
344 echo '# Skip SOGo: Will disable SOGo integration and therefore webmail, DAV protocols and ActiveSync support (experimental, unsupported, not fully implemented) - y/n' >> mailcow.conf
345 echo "SKIP_SOGO=n" >> mailcow.conf
346 fi
347 elif [[ ${option} == "MAILDIR_SUB" ]]; then
348 if ! grep -q ${option} mailcow.conf; then
349 echo "Adding new option \"${option}\" to mailcow.conf"
350 echo '# MAILDIR_SUB defines a path in a users virtual home to keep the maildir in. Leave empty for updated setups.' >> mailcow.conf
351 echo "#MAILDIR_SUB=Maildir" >> mailcow.conf
352 echo "MAILDIR_SUB=" >> mailcow.conf
353 fi
354 elif [[ ${option} == "WATCHDOG_NOTIFY_BAN" ]]; then
355 if ! grep -q ${option} mailcow.conf; then
356 echo "Adding new option \"${option}\" to mailcow.conf"
357 echo '# Notify about banned IP. Includes whois lookup.' >> mailcow.conf
358 echo "WATCHDOG_NOTIFY_BAN=y" >> mailcow.conf
359 fi
360 elif [[ ${option} == "WATCHDOG_EXTERNAL_CHECKS" ]]; then
361 if ! grep -q ${option} mailcow.conf; then
362 echo "Adding new option \"${option}\" to mailcow.conf"
363 echo '# Checks if mailcow is an open relay. Requires a SAL. More checks will follow.' >> mailcow.conf
364 echo '# No data is collected. Opt-in and anonymous.' >> mailcow.conf
365 echo '# Will only work with unmodified mailcow setups.' >> mailcow.conf
366 echo "WATCHDOG_EXTERNAL_CHECKS=n" >> mailcow.conf
367 fi
368 elif [[ ${option} == "SOGO_EXPIRE_SESSION" ]]; then
369 if ! grep -q ${option} mailcow.conf; then
370 echo "Adding new option \"${option}\" to mailcow.conf"
371 echo '# SOGo session timeout in minutes' >> mailcow.conf
372 echo "SOGO_EXPIRE_SESSION=480" >> mailcow.conf
373 fi
374 elif [[ ${option} == "REDIS_PORT" ]]; then
375 if ! grep -q ${option} mailcow.conf; then
376 echo "Adding new option \"${option}\" to mailcow.conf"
377 echo "REDIS_PORT=127.0.0.1:7654" >> mailcow.conf
378 fi
379 elif [[ ${option} == "DOVECOT_MASTER_USER" ]]; then
380 if ! grep -q ${option} mailcow.conf; then
381 echo "Adding new option \"${option}\" to mailcow.conf"
382 echo '# DOVECOT_MASTER_USER and _PASS must _both_ be provided. No special chars.' >> mailcow.conf
383 echo '# Empty by default to auto-generate master user and password on start.' >> mailcow.conf
384 echo '# User expands to DOVECOT_MASTER_USER@mailcow.local' >> mailcow.conf
385 echo '# LEAVE EMPTY IF UNSURE' >> mailcow.conf
386 echo "DOVECOT_MASTER_USER=" >> mailcow.conf
387 fi
388 elif [[ ${option} == "DOVECOT_MASTER_PASS" ]]; then
389 if ! grep -q ${option} mailcow.conf; then
390 echo "Adding new option \"${option}\" to mailcow.conf"
391 echo '# LEAVE EMPTY IF UNSURE' >> mailcow.conf
392 echo "DOVECOT_MASTER_PASS=" >> mailcow.conf
393 fi
394 elif [[ ${option} == "MAILCOW_PASS_SCHEME" ]]; then
395 if ! grep -q ${option} mailcow.conf; then
396 echo "Adding new option \"${option}\" to mailcow.conf"
397 echo '# Password hash algorithm' >> mailcow.conf
398 echo '# Only certain password hash algorithm are supported. For a fully list of supported schemes,' >> mailcow.conf
399 echo '# see https://mailcow.github.io/mailcow-dockerized-docs/model-passwd/' >> mailcow.conf
400 echo "MAILCOW_PASS_SCHEME=BLF-CRYPT" >> mailcow.conf
401 fi
402 elif ! grep -q ${option} mailcow.conf; then
403 echo "Adding new option \"${option}\" to mailcow.conf"
404 echo "${option}=n" >> mailcow.conf
405 fi
406done
407
408echo -en "Checking internet connection... "
409if ! check_online_status; then
410 echo -e "\e[31mfailed\e[0m"
411 exit 1
412else
413 echo -e "\e[32mOK\e[0m"
414fi
415
416echo -e "\e[32mChecking for newer update script...\e[0m"
417SHA1_1=$(sha1sum update.sh)
418git fetch origin #${BRANCH}
419git checkout origin/${BRANCH} update.sh
420SHA1_2=$(sha1sum update.sh)
421if [[ ${SHA1_1} != ${SHA1_2} ]]; then
422 echo "update.sh changed, please run this script again, exiting."
423 chmod +x update.sh
424 exit 2
425fi
426
427if [[ -f mailcow.conf ]]; then
428 source mailcow.conf
429else
430 echo -e "\e[31mNo mailcow.conf - is mailcow installed?\e[0m"
431 exit 1
432fi
433
434if [ ! $FORCE ]; then
435 read -r -p "Are you sure you want to update mailcow: dockerized? All containers will be stopped. [y/N] " response
436 if [[ ! "$response" =~ ^([yY][eE][sS]|[yY])+$ ]]; then
437 echo "OK, exiting."
438 exit 0
439 fi
440fi
441
442echo -e "\e[32mValidating docker-compose stack configuration...\e[0m"
443if ! docker-compose config -q; then
444 echo -e "\e[31m\nOh no, something went wrong. Please check the error message above.\e[0m"
445 exit 1
446fi
447
448echo -e "\e[32mChecking for conflicting bridges...\e[0m"
449MAILCOW_BRIDGE=$(docker-compose config | grep -i com.docker.network.bridge.name | cut -d':' -f2)
450while read NAT_ID; do
451 iptables -t nat -D POSTROUTING $NAT_ID
452done < <(iptables -L -vn -t nat --line-numbers | grep $IPV4_NETWORK | grep -E 'MASQUERADE.*all' | grep -v ${MAILCOW_BRIDGE} | cut -d' ' -f1)
453
454DIFF_DIRECTORY=update_diffs
455DIFF_FILE=${DIFF_DIRECTORY}/diff_before_update_$(date +"%Y-%m-%d-%H-%M-%S")
456mv diff_before_update* ${DIFF_DIRECTORY}/ 2> /dev/null
457if ! git diff-index --quiet HEAD; then
458 echo -e "\e[32mSaving diff to ${DIFF_FILE}...\e[0m"
459 mkdir -p ${DIFF_DIRECTORY}
460 git diff --stat > ${DIFF_FILE}
461 git diff >> ${DIFF_FILE}
462fi
463
464echo -e "\e[32mPrefetching images...\e[0m"
465prefetch_images
466
467echo -e "\e[32mStopping mailcow...\e[0m"
468sleep 2
469MAILCOW_CONTAINERS=($(docker-compose ps -q))
470docker-compose down
471echo -e "\e[32mChecking for remaining containers...\e[0m"
472sleep 2
473for container in "${MAILCOW_CONTAINERS[@]}"; do
474 docker rm -f "$container" 2> /dev/null
475done
476
477# Silently fixing remote url from andryyy to mailcow
478git remote set-url origin https://github.com/mailcow/mailcow-dockerized
479echo -e "\e[32mCommitting current status...\e[0m"
480[[ -z "$(git config user.name)" ]] && git config user.name moo
481[[ -z "$(git config user.email)" ]] && git config user.email moo@cow.moo
482[[ ! -z $(git ls-files data/conf/rspamd/override.d/worker-controller-password.inc) ]] && git rm data/conf/rspamd/override.d/worker-controller-password.inc
483git add -u
484git commit -am "Before update on ${DATE}" > /dev/null
485echo -e "\e[32mFetching updated code from remote...\e[0m"
486git fetch origin #${BRANCH}
487echo -e "\e[32mMerging local with remote code (recursive, strategy: \"${MERGE_STRATEGY:-theirs}\", options: \"patience\"...\e[0m"
488git config merge.defaultToUpstream true
489git merge -X${MERGE_STRATEGY:-theirs} -Xpatience -m "After update on ${DATE}"
490# Need to use a variable to not pass return codes of if checks
491MERGE_RETURN=$?
492if [[ ${MERGE_RETURN} == 128 ]]; then
493 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"
494 exit 1
495elif [[ ${MERGE_RETURN} == 1 ]]; then
496 echo -e "\e[93mPotenial conflict, trying to fix...\e[0m"
497 git status --porcelain | grep -E "UD|DU" | awk '{print $2}' | xargs rm -v
498 git add -A
499 git commit -m "After update on ${DATE}" > /dev/null
500 git checkout .
501 echo -e "\e[32mRemoved and recreated files if necessary.\e[0m"
502elif [[ ${MERGE_RETURN} != 0 ]]; then
503 echo -e "\e[31m\nOh no, something went wrong. Please check the error message above.\e[0m"
504 echo
505 echo "Run docker-compose up -d to restart your stack without updates or try again after fixing the mentioned errors."
506 exit 1
507fi
508
509if [[ ${NO_UPDATE_COMPOSE} == "y" ]]; then
510 echo -e "\e[33mNot fetching latest docker-compose, please check for updates manually!\e[0m"
511elif [[ -e /etc/alpine-release ]]; then
512 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"
513else
514 echo -e "\e[32mFetching new docker-compose version...\e[0m"
515 sleep 1
516 if [[ ! -z $(which pip) && $(pip list --local 2>&1 | grep -v DEPRECATION | grep -c docker-compose) == 1 ]]; then
517 true
518 #prevent breaking a working docker-compose installed with pip
519 elif [[ $(curl -sL -w "%{http_code}" https://www.servercow.de/docker-compose/latest.php -o /dev/null) == "200" ]]; then
520 LATEST_COMPOSE=$(curl -#L https://www.servercow.de/docker-compose/latest.php)
521 COMPOSE_VERSION=$(docker-compose version --short)
522 if [[ "$LATEST_COMPOSE" != "$COMPOSE_VERSION" ]]; then
523 COMPOSE_PATH=$(which docker-compose)
524 if [[ -w ${COMPOSE_PATH} ]]; then
525 curl -#L https://github.com/docker/compose/releases/download/${LATEST_COMPOSE}/docker-compose-$(uname -s)-$(uname -m) > $COMPOSE_PATH
526 chmod +x $COMPOSE_PATH
527 else
528 echo -e "\e[33mWARNING: $COMPOSE_PATH is not writable, but new version $LATEST_COMPOSE is available (installed: $COMPOSE_VERSION)\e[0m"
529 fi
530 fi
531 else
532 echo -e "\e[33mCannot determine latest docker-compose version, skipping...\e[0m"
533 fi
534fi
535
536echo -e "\e[32mFetching new images, if any...\e[0m"
537sleep 2
538docker-compose pull
539
540# Fix missing SSL, does not overwrite existing files
541[[ ! -d data/assets/ssl ]] && mkdir -p data/assets/ssl
542cp -n -d data/assets/ssl-example/*.pem data/assets/ssl/
543
544echo -e "Checking IPv6 settings... "
545if grep -q 'SYSCTL_IPV6_DISABLED=1' mailcow.conf; then
546 echo
547 echo '!! IMPORTANT !!'
548 echo
549 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".'
550 echo 'This setting will only be active after a complete shutdown of mailcow by running "docker-compose down" followed by "docker-compose up -d".'
551 echo
552 echo '!! IMPORTANT !!'
553 echo
554 read -p "Press any key to continue..." < /dev/tty
555fi
556
557# Checking for old project name bug
558sed -i --follow-symlinks 's#COMPOSEPROJECT_NAME#COMPOSE_PROJECT_NAME#g' mailcow.conf
559
560# Fix Rspamd maps
561if [ -f data/conf/rspamd/custom/global_from_blacklist.map ]; then
562 mv data/conf/rspamd/custom/global_from_blacklist.map data/conf/rspamd/custom/global_smtp_from_blacklist.map
563fi
564if [ -f data/conf/rspamd/custom/global_from_whitelist.map ]; then
565 mv data/conf/rspamd/custom/global_from_whitelist.map data/conf/rspamd/custom/global_smtp_from_whitelist.map
566fi
567
568# Fix deprecated metrics.conf
569if [ -f "data/conf/rspamd/local.d/metrics.conf" ]; then
570 if [ ! -z "$(git diff --name-only origin/master data/conf/rspamd/local.d/metrics.conf)" ]; then
571 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."
572 echo "The deprecated configuration file metrics.conf will be moved to metrics.conf_deprecated after updating mailcow."
573 fi
574 mv data/conf/rspamd/local.d/metrics.conf data/conf/rspamd/local.d/metrics.conf_deprecated
575fi
576
577if [[ ${SKIP_START} == "y" ]]; then
578 echo -e "\e[33mNot starting mailcow, please run \"docker-compose up -d --remove-orphans\" to start mailcow.\e[0m"
579else
580 echo -e "\e[32mStarting mailcow...\e[0m"
581 sleep 2
582 docker-compose up -d --remove-orphans
583fi
584
585echo -e "\e[32mCollecting garbage...\e[0m"
586docker_garbage
587
588#echo "In case you encounter any problem, hard-reset to a state before updating mailcow:"
589#echo
590#git reflog --color=always | grep "Before update on "
591#echo
592#echo "Use \"git reset --hard hash-on-the-left\" and run docker-compose up -d afterwards."