This commit is contained in:
Roy Lenferink 2023-03-03 16:13:09 +01:00 committed by GitHub
commit f5eaa62dc7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 771 additions and 248 deletions

2
.gitignore vendored
View File

@ -59,7 +59,9 @@ data/web/inc/vars.local.inc.php
data/web/inc/app_info.inc.php data/web/inc/app_info.inc.php
data/web/nextcloud*/ data/web/nextcloud*/
data/web/rc*/ data/web/rc*/
docker-compose.yml**.bak
docker-compose.override.yml docker-compose.override.yml
!helper-scripts/docker-compose.override.yml.d/**/docker-compose.override.yml
mailcow.conf mailcow.conf
mailcow.conf_backup mailcow.conf_backup
rebuild-images.sh rebuild-images.sh

View File

@ -6,8 +6,10 @@ services:
environment: environment:
- TZ=${TZ} - TZ=${TZ}
volumes: volumes:
- ./data/hooks/unbound:/hooks:Z - ./data/hooks/unbound:/hooks
- ./data/conf/unbound/unbound.conf:/etc/unbound/unbound.conf:ro,Z - ./data/conf/unbound/unbound.conf:/etc/unbound/unbound.conf:ro
security_opt:
- label=disable
restart: always restart: always
tty: true tty: true
networks: networks:
@ -24,7 +26,9 @@ services:
volumes: volumes:
- mysql-vol-1:/var/lib/mysql/ - mysql-vol-1:/var/lib/mysql/
- mysql-socket-vol-1:/var/run/mysqld/ - mysql-socket-vol-1:/var/run/mysqld/
- ./data/conf/mysql/:/etc/mysql/conf.d/:ro,Z - ./data/conf/mysql/:/etc/mysql/conf.d/:ro
security_opt:
- label=disable
environment: environment:
- TZ=${TZ} - TZ=${TZ}
- MYSQL_ROOT_PASSWORD=${DBROOT} - MYSQL_ROOT_PASSWORD=${DBROOT}
@ -44,6 +48,8 @@ services:
image: redis:7-alpine image: redis:7-alpine
volumes: volumes:
- redis-vol-1:/data/ - redis-vol-1:/data/
security_opt:
- label=disable
restart: always restart: always
ports: ports:
- "${REDIS_PORT:-127.0.0.1:7654}:6379" - "${REDIS_PORT:-127.0.0.1:7654}:6379"
@ -68,8 +74,10 @@ services:
- TZ=${TZ} - TZ=${TZ}
- SKIP_CLAMD=${SKIP_CLAMD:-n} - SKIP_CLAMD=${SKIP_CLAMD:-n}
volumes: volumes:
- ./data/conf/clamav/:/etc/clamav/:Z - ./data/conf/clamav/:/etc/clamav/
- clamd-db-vol-1:/var/lib/clamav - clamd-db-vol-1:/var/lib/clamav
security_opt:
- label=disable
networks: networks:
mailcow-network: mailcow-network:
aliases: aliases:
@ -87,15 +95,17 @@ services:
- REDIS_SLAVEOF_IP=${REDIS_SLAVEOF_IP:-} - REDIS_SLAVEOF_IP=${REDIS_SLAVEOF_IP:-}
- REDIS_SLAVEOF_PORT=${REDIS_SLAVEOF_PORT:-} - REDIS_SLAVEOF_PORT=${REDIS_SLAVEOF_PORT:-}
volumes: volumes:
- ./data/hooks/rspamd:/hooks:Z - ./data/hooks/rspamd:/hooks
- ./data/conf/rspamd/custom/:/etc/rspamd/custom:z - ./data/conf/rspamd/custom/:/etc/rspamd/custom
- ./data/conf/rspamd/override.d/:/etc/rspamd/override.d:Z - ./data/conf/rspamd/override.d/:/etc/rspamd/override.d
- ./data/conf/rspamd/local.d/:/etc/rspamd/local.d:Z - ./data/conf/rspamd/local.d/:/etc/rspamd/local.d
- ./data/conf/rspamd/plugins.d/:/etc/rspamd/plugins.d:Z - ./data/conf/rspamd/plugins.d/:/etc/rspamd/plugins.d
- ./data/conf/rspamd/lua/:/etc/rspamd/lua/:ro,Z - ./data/conf/rspamd/lua/:/etc/rspamd/lua/:ro
- ./data/conf/rspamd/rspamd.conf.local:/etc/rspamd/rspamd.conf.local:Z - ./data/conf/rspamd/rspamd.conf.local:/etc/rspamd/rspamd.conf.local
- ./data/conf/rspamd/rspamd.conf.override:/etc/rspamd/rspamd.conf.override:Z - ./data/conf/rspamd/rspamd.conf.override:/etc/rspamd/rspamd.conf.override
- rspamd-vol-1:/var/lib/rspamd - rspamd-vol-1:/var/lib/rspamd
security_opt:
- label=disable
restart: always restart: always
hostname: rspamd hostname: rspamd
dns: dns:
@ -111,23 +121,25 @@ services:
depends_on: depends_on:
- redis-mailcow - redis-mailcow
volumes: volumes:
- ./data/hooks/phpfpm:/hooks:Z - ./data/hooks/phpfpm:/hooks
- ./data/web:/web:z - ./data/web:/web
- ./data/conf/rspamd/dynmaps:/dynmaps:ro,z - ./data/conf/rspamd/dynmaps:/dynmaps:ro
- ./data/conf/rspamd/custom/:/rspamd_custom_maps:z - ./data/conf/rspamd/custom/:/rspamd_custom_maps
- rspamd-vol-1:/var/lib/rspamd - rspamd-vol-1:/var/lib/rspamd
- mysql-socket-vol-1:/var/run/mysqld/ - mysql-socket-vol-1:/var/run/mysqld/
- ./data/conf/sogo/:/etc/sogo/:z - ./data/conf/sogo/:/etc/sogo/
- ./data/conf/rspamd/meta_exporter:/meta_exporter:ro,z - ./data/conf/rspamd/meta_exporter:/meta_exporter:ro
- ./data/conf/phpfpm/sogo-sso/:/etc/sogo-sso/:z - ./data/conf/phpfpm/sogo-sso/:/etc/sogo-sso/
- ./data/conf/phpfpm/php-fpm.d/pools.conf:/usr/local/etc/php-fpm.d/z-pools.conf:Z - ./data/conf/phpfpm/php-fpm.d/pools.conf:/usr/local/etc/php-fpm.d/z-pools.conf
- ./data/conf/phpfpm/php-conf.d/opcache-recommended.ini:/usr/local/etc/php/conf.d/opcache-recommended.ini:Z - ./data/conf/phpfpm/php-conf.d/opcache-recommended.ini:/usr/local/etc/php/conf.d/opcache-recommended.ini
- ./data/conf/phpfpm/php-conf.d/upload.ini:/usr/local/etc/php/conf.d/upload.ini:Z - ./data/conf/phpfpm/php-conf.d/upload.ini:/usr/local/etc/php/conf.d/upload.ini
- ./data/conf/phpfpm/php-conf.d/other.ini:/usr/local/etc/php/conf.d/zzz-other.ini:Z - ./data/conf/phpfpm/php-conf.d/other.ini:/usr/local/etc/php/conf.d/zzz-other.ini
- ./data/conf/dovecot/global_sieve_before:/global_sieve/before:z - ./data/conf/dovecot/global_sieve_before:/global_sieve/before
- ./data/conf/dovecot/global_sieve_after:/global_sieve/after:z - ./data/conf/dovecot/global_sieve_after:/global_sieve/after
- ./data/assets/templates:/tpls:z - ./data/assets/templates:/tpls
- ./data/conf/nginx/:/etc/nginx/conf.d/:z - ./data/conf/nginx/:/etc/nginx/conf.d/
security_opt:
- label=disable
dns: dns:
- ${IPV4_NETWORK:-172.22.1}.254 - ${IPV4_NETWORK:-172.22.1}.254
environment: environment:
@ -189,15 +201,17 @@ services:
dns: dns:
- ${IPV4_NETWORK:-172.22.1}.254 - ${IPV4_NETWORK:-172.22.1}.254
volumes: volumes:
- ./data/hooks/sogo:/hooks:Z - ./data/hooks/sogo:/hooks
- ./data/conf/sogo/:/etc/sogo/:z - ./data/conf/sogo/:/etc/sogo/
- ./data/web/inc/init_db.inc.php:/init_db.inc.php:Z - ./data/web/inc/init_db.inc.php:/init_db.inc.php
- ./data/conf/sogo/custom-favicon.ico:/usr/lib/GNUstep/SOGo/WebServerResources/img/sogo.ico:z - ./data/conf/sogo/custom-favicon.ico:/usr/lib/GNUstep/SOGo/WebServerResources/img/sogo.ico
- ./data/conf/sogo/custom-theme.js:/usr/lib/GNUstep/SOGo/WebServerResources/js/theme.js:z - ./data/conf/sogo/custom-theme.js:/usr/lib/GNUstep/SOGo/WebServerResources/js/theme.js
- ./data/conf/sogo/custom-sogo.js:/usr/lib/GNUstep/SOGo/WebServerResources/js/custom-sogo.js:z - ./data/conf/sogo/custom-sogo.js:/usr/lib/GNUstep/SOGo/WebServerResources/js/custom-sogo.js
- mysql-socket-vol-1:/var/run/mysqld/ - mysql-socket-vol-1:/var/run/mysqld/
- sogo-web-vol-1:/sogo_web - sogo-web-vol-1:/sogo_web
- sogo-userdata-backup-vol-1:/sogo_backup - sogo-userdata-backup-vol-1:/sogo_backup
security_opt:
- label=disable
labels: labels:
ofelia.enabled: "true" ofelia.enabled: "true"
ofelia.job-exec.sogo_sessions.schedule: "@every 1m" ofelia.job-exec.sogo_sessions.schedule: "@every 1m"
@ -224,18 +238,20 @@ services:
cap_add: cap_add:
- NET_BIND_SERVICE - NET_BIND_SERVICE
volumes: volumes:
- ./data/hooks/dovecot:/hooks:Z - ./data/hooks/dovecot:/hooks
- ./data/conf/dovecot:/etc/dovecot:z - ./data/conf/dovecot:/etc/dovecot
- ./data/assets/ssl:/etc/ssl/mail/:ro,z - ./data/assets/ssl:/etc/ssl/mail/:ro
- ./data/conf/sogo/:/etc/sogo/:z - ./data/conf/sogo/:/etc/sogo/
- ./data/conf/phpfpm/sogo-sso/:/etc/phpfpm/:z - ./data/conf/phpfpm/sogo-sso/:/etc/phpfpm/
- vmail-vol-1:/var/vmail - vmail-vol-1:/var/vmail
- vmail-index-vol-1:/var/vmail_index - vmail-index-vol-1:/var/vmail_index
- crypt-vol-1:/mail_crypt/ - crypt-vol-1:/mail_crypt/
- ./data/conf/rspamd/custom/:/etc/rspamd/custom:z - ./data/conf/rspamd/custom/:/etc/rspamd/custom
- ./data/assets/templates:/templates:z - ./data/assets/templates:/templates
- rspamd-vol-1:/var/lib/rspamd - rspamd-vol-1:/var/lib/rspamd
- mysql-socket-vol-1:/var/run/mysqld/ - mysql-socket-vol-1:/var/run/mysqld/
security_opt:
- label=disable
environment: environment:
- DOVECOT_MASTER_USER=${DOVECOT_MASTER_USER:-} - DOVECOT_MASTER_USER=${DOVECOT_MASTER_USER:-}
- DOVECOT_MASTER_PASS=${DOVECOT_MASTER_PASS:-} - DOVECOT_MASTER_PASS=${DOVECOT_MASTER_PASS:-}
@ -300,13 +316,15 @@ services:
depends_on: depends_on:
- mysql-mailcow - mysql-mailcow
volumes: volumes:
- ./data/hooks/postfix:/hooks:Z - ./data/hooks/postfix:/hooks
- ./data/conf/postfix:/opt/postfix/conf:z - ./data/conf/postfix:/opt/postfix/conf
- ./data/assets/ssl:/etc/ssl/mail/:ro,z - ./data/assets/ssl:/etc/ssl/mail/:ro
- postfix-vol-1:/var/spool/postfix - postfix-vol-1:/var/spool/postfix
- crypt-vol-1:/var/lib/zeyple - crypt-vol-1:/var/lib/zeyple
- rspamd-vol-1:/var/lib/rspamd - rspamd-vol-1:/var/lib/rspamd
- mysql-socket-vol-1:/var/run/mysqld/ - mysql-socket-vol-1:/var/run/mysqld/
security_opt:
- label=disable
environment: environment:
- LOG_LINES=${LOG_LINES:-9999} - LOG_LINES=${LOG_LINES:-9999}
- TZ=${TZ} - TZ=${TZ}
@ -334,6 +352,8 @@ services:
memcached-mailcow: memcached-mailcow:
image: memcached:alpine image: memcached:alpine
restart: always restart: always
security_opt:
- label=disable
environment: environment:
- TZ=${TZ} - TZ=${TZ}
networks: networks:
@ -371,12 +391,14 @@ services:
- ALLOW_ADMIN_EMAIL_LOGIN=${ALLOW_ADMIN_EMAIL_LOGIN:-n} - ALLOW_ADMIN_EMAIL_LOGIN=${ALLOW_ADMIN_EMAIL_LOGIN:-n}
- ADDITIONAL_SERVER_NAMES=${ADDITIONAL_SERVER_NAMES:-} - ADDITIONAL_SERVER_NAMES=${ADDITIONAL_SERVER_NAMES:-}
volumes: volumes:
- ./data/web:/web:ro,z - ./data/web:/web:ro
- ./data/conf/rspamd/dynmaps:/dynmaps:ro,z - ./data/conf/rspamd/dynmaps:/dynmaps:ro
- ./data/assets/ssl/:/etc/ssl/mail/:ro,z - ./data/assets/ssl/:/etc/ssl/mail/:ro
- ./data/conf/nginx/:/etc/nginx/conf.d/:z - ./data/conf/nginx/:/etc/nginx/conf.d/
- ./data/conf/rspamd/meta_exporter:/meta_exporter:ro,z - ./data/conf/rspamd/meta_exporter:/meta_exporter:ro
- sogo-web-vol-1:/usr/lib/GNUstep/SOGo/ - sogo-web-vol-1:/usr/lib/GNUstep/SOGo/
security_opt:
- label=disable
ports: ports:
- "${HTTPS_BIND:-}:${HTTPS_PORT:-443}:${HTTPS_PORT:-443}" - "${HTTPS_BIND:-}:${HTTPS_PORT:-443}:${HTTPS_PORT:-443}"
- "${HTTP_BIND:-}:${HTTP_PORT:-80}:${HTTP_PORT:-80}" - "${HTTP_BIND:-}:${HTTP_PORT:-80}:${HTTP_PORT:-80}"
@ -414,10 +436,12 @@ services:
- SNAT_TO_SOURCE=${SNAT_TO_SOURCE:-n} - SNAT_TO_SOURCE=${SNAT_TO_SOURCE:-n}
- SNAT6_TO_SOURCE=${SNAT6_TO_SOURCE:-n} - SNAT6_TO_SOURCE=${SNAT6_TO_SOURCE:-n}
volumes: volumes:
- ./data/web/.well-known/acme-challenge:/var/www/acme:z - ./data/web/.well-known/acme-challenge:/var/www/acme
- ./data/assets/ssl:/var/lib/acme/:z - ./data/assets/ssl:/var/lib/acme/
- ./data/assets/ssl-example:/var/lib/ssl-example/:ro,Z - ./data/assets/ssl-example:/var/lib/ssl-example/:ro
- mysql-socket-vol-1:/var/run/mysqld/ - mysql-socket-vol-1:/var/run/mysqld/
security_opt:
- label=disable
restart: always restart: always
networks: networks:
mailcow-network: mailcow-network:
@ -446,6 +470,8 @@ services:
network_mode: "host" network_mode: "host"
volumes: volumes:
- /lib/modules:/lib/modules:ro - /lib/modules:/lib/modules:ro
security_opt:
- label=disable
watchdog-mailcow: watchdog-mailcow:
image: mailcow/watchdog:1.97 image: mailcow/watchdog:1.97
@ -457,7 +483,9 @@ services:
- rspamd-vol-1:/var/lib/rspamd - rspamd-vol-1:/var/lib/rspamd
- mysql-socket-vol-1:/var/run/mysqld/ - mysql-socket-vol-1:/var/run/mysqld/
- postfix-vol-1:/var/spool/postfix - postfix-vol-1:/var/spool/postfix
- ./data/assets/ssl:/etc/ssl/mail/:ro,z - ./data/assets/ssl:/etc/ssl/mail/:ro
security_opt:
- label=disable
restart: always restart: always
environment: environment:
- IPV6_NETWORK=${IPV6_NETWORK:-fd4d:6169:6c63:6f77::/64} - IPV6_NETWORK=${IPV6_NETWORK:-fd4d:6169:6c63:6f77::/64}
@ -533,6 +561,8 @@ services:
restart: always restart: always
volumes: volumes:
- solr-vol-1:/opt/solr/server/solr/dovecot-fts/data - solr-vol-1:/opt/solr/server/solr/dovecot-fts/data
security_opt:
- label=disable
ports: ports:
- "${SOLR_PORT:-127.0.0.1:18983}:8983" - "${SOLR_PORT:-127.0.0.1:18983}:8983"
environment: environment:
@ -547,6 +577,8 @@ services:
olefy-mailcow: olefy-mailcow:
image: mailcow/olefy:1.11 image: mailcow/olefy:1.11
restart: always restart: always
security_opt:
- label=disable
environment: environment:
- TZ=${TZ} - TZ=${TZ}
- OLEFY_BINDADDRESS=0.0.0.0 - OLEFY_BINDADDRESS=0.0.0.0

View File

@ -21,39 +21,70 @@ if grep --help 2>&1 | head -n 1 | grep -q -i "busybox"; then echo "BusyBox grep
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 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 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
for bin in openssl curl docker git awk sha1sum; do # Check which container engine is available.
if [[ -z $(which ${bin}) ]]; then echo "Cannot find ${bin}, exiting..."; exit 1; fi # Check for podman first, because the 'podman-docker' package might be installed providing a dummy 'docker' command.
if command -v podman > /dev/null 2>&1; then
CONTAINER_ENGINE="podman"
echo -e "\e[32mFound Podman container engine.\e[0m"
echo -e "\e[31mNOTE: Support for Podman is experimental, consider this before deploying to production! \e[0m"
if [[ -n "${DOCKER_HOST}" ]] && [[ "${DOCKER_HOST}" == "unix://"* ]]; then
CONTAINER_SOCKET="${DOCKER_HOST/"unix://"/}"
else
CONTAINER_SOCKET="/run/user/${UID}/podman/podman.sock"
fi
# To patch the docker-compose file for use with podman
EXTRA_REQUIRED_PACKAGES="patch"
elif command -v docker > /dev/null 2>&1; then
CONTAINER_ENGINE="docker"
echo -e "\e[32mFound Docker container engine.\e[0m"
CONTAINER_SOCKET="/var/run/docker.sock"
EXTRA_REQUIRED_PACKAGES=""
else
echo "Cannot find container engine (Docker or Podman), exiting..."
exit 1
fi
for bin in openssl curl git awk sha1sum ${EXTRA_REQUIRED_PACKAGES}; do
if [[ -z $(which ${bin}) ]]; then
echo "Cannot find ${bin}, exiting..."
exit 1
fi
done done
if docker compose > /dev/null 2>&1; then MAILCOW_DOCKER_COMPOSE=${MAILCOW_DOCKER_COMPOSE:-"docker-compose"}
if [[ "${CONTAINER_ENGINE}" == "docker" ]] && docker compose > /dev/null 2>&1; then
if docker compose version --short | grep "^2." > /dev/null 2>&1; then if docker compose version --short | grep "^2." > /dev/null 2>&1; then
COMPOSE_VERSION=native COMPOSE_VERSION=native
echo -e "\e[31mFound Docker Compose Plugin (native).\e[0m" echo -e "\e[31mFound Docker Compose Plugin (native).\e[0m"
echo -e "\e[31mSetting the DOCKER_COMPOSE_VERSION Variable to native\e[0m" echo -e "\e[31mSetting the DOCKER_COMPOSE_VERSION Variable to native\e[0m"
sleep 2 sleep 2
echo -e "\e[33mNotice: You´ll have to update this Compose Version via your Package Manager manually!\e[0m" echo -e "\e[33mNotice: You'll have to update this Compose Version via your Package Manager manually! \e[0m"
else else
echo -e "\e[31mCannot find Docker Compose with a Version Higher than 2.X.X.\e[0m" echo -e "\e[31mCannot find Docker Compose with a Version Higher than 2.X.X.\e[0m"
echo -e "\e[31mPlease update/install it manually regarding to this doc site: https://mailcow.github.io/mailcow-dockerized-docs/i_u_m/i_u_m_install/\e[0m" echo -e "\e[31mPlease update/install it manually regarding to this doc site: https://mailcow.github.io/mailcow-dockerized-docs/i_u_m/i_u_m_install/\e[0m"
exit 1 exit 1
fi fi
elif docker-compose > /dev/null 2>&1; then elif $MAILCOW_DOCKER_COMPOSE > /dev/null 2>&1; then
if ! [[ $(alias docker-compose 2> /dev/null) ]] ; then if ! [[ $(alias $MAILCOW_DOCKER_COMPOSE 2> /dev/null) ]] ; then
if docker-compose version --short | grep "^2." > /dev/null 2>&1; then if $MAILCOW_DOCKER_COMPOSE version --short | grep "^2." > /dev/null 2>&1; then
COMPOSE_VERSION=standalone COMPOSE_VERSION=standalone
echo -e "\e[31mFound Docker Compose Standalone.\e[0m" echo -e "\e[31mFound Docker Compose Standalone.\e[0m"
echo -e "\e[31mSetting the DOCKER_COMPOSE_VERSION Variable to standalone\e[0m" echo -e "\e[31mSetting the DOCKER_COMPOSE_VERSION Variable to standalone\e[0m"
sleep 2 sleep 2
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" echo -e "\e[33mNotice: For an automatic update of ${MAILCOW_DOCKER_COMPOSE} please use the update_compose.sh scripts located at the helper-scripts folder.\e[0m"
else else
echo -e "\e[31mCannot find Docker Compose with a Version Higher than 2.X.X.\e[0m" echo -e "\e[31mCannot find Docker Compose with a Version Higher than 2.X.X.\e[0m"
echo -e "\e[31mPlease update/install manually regarding to this doc site: https://mailcow.github.io/mailcow-dockerized-docs/i_u_m/i_u_m_install/\e[0m" echo -e "\e[31mPlease update/install manually regarding to this doc site: https://mailcow.github.io/mailcow-dockerized-docs/i_u_m/i_u_m_install/\e[0m"
exit 1 exit 1
fi fi
fi fi
else else
echo -e "\e[31mCannot find Docker Compose.\e[0m" echo -e "\e[31mCannot find Docker Compose.\e[0m"
echo -e "\e[31mPlease install it regarding to this doc site: https://mailcow.github.io/mailcow-dockerized-docs/i_u_m/i_u_m_install/\e[0m" echo -e "\e[31mPlease install it regarding to this doc site: https://mailcow.github.io/mailcow-dockerized-docs/i_u_m/i_u_m_install/\e[0m"
exit 1 exit 1
fi fi
@ -173,7 +204,7 @@ else
echo -e "\033[31mCould not determine branch input..." echo -e "\033[31mCould not determine branch input..."
echo -e "\033[31mExiting." echo -e "\033[31mExiting."
exit 1 exit 1
fi fi
if [ ! -z "${MAILCOW_BRANCH}" ]; then if [ ! -z "${MAILCOW_BRANCH}" ]; then
git_branch=${MAILCOW_BRANCH} git_branch=${MAILCOW_BRANCH}
@ -181,6 +212,11 @@ fi
[ ! -f ./data/conf/rspamd/override.d/worker-controller-password.inc ] && echo '# Placeholder' > ./data/conf/rspamd/override.d/worker-controller-password.inc [ ! -f ./data/conf/rspamd/override.d/worker-controller-password.inc ] && echo '# Placeholder' > ./data/conf/rspamd/override.d/worker-controller-password.inc
if [[ "${CONTAINER_ENGINE}" == "podman" ]]; then
# Apply patches for usage with Podman
bash ./patches-for-podman.sh
fi
cat << EOF > mailcow.conf cat << EOF > mailcow.conf
# ------------------------------ # ------------------------------
# mailcow web ui configuration # mailcow web ui configuration
@ -196,6 +232,9 @@ MAILCOW_HOSTNAME=${MAILCOW_HOSTNAME}
# see https://mailcow.github.io/mailcow-dockerized-docs/models/model-passwd/ # see https://mailcow.github.io/mailcow-dockerized-docs/models/model-passwd/
MAILCOW_PASS_SCHEME=BLF-CRYPT MAILCOW_PASS_SCHEME=BLF-CRYPT
# The directory used to store the data of the used containers (used in case the CUSTOM_STORAGE_LOCATION override is included)
MAILCOW_STORAGE_DIR=
# ------------------------------ # ------------------------------
# SQL database configuration # SQL database configuration
# ------------------------------ # ------------------------------
@ -227,6 +266,43 @@ HTTP_BIND=
HTTPS_PORT=443 HTTPS_PORT=443
HTTPS_BIND= HTTPS_BIND=
# ------------------------------
# Container environment
# ------------------------------
# The container engine to use to run this project (docker or podman).
MAILCOW_CONTAINER_ENGINE=${CONTAINER_ENGINE}
# The location of the container socket to use for volume mounts.
MAILCOW_CONTAINER_SOCKET=${CONTAINER_SOCKET}
# Fixed project name
# Please use lowercase letters only
COMPOSE_PROJECT_NAME=mailcowdockerized
# Used Docker Compose version
# Switch here between native (compose plugin) and standalone
# For more information take a look at the mailcow docs regarding the configuration options.
# Normally this should be untouched but if you decided to use either of those you can switch it manually here.
# Please be aware that at least one of those variants should be installed on your machine or mailcow will fail.
DOCKER_COMPOSE_VERSION=${COMPOSE_VERSION}
# Additional override files (relative to the repo root) that need to be taken care of when running mailcow scripts.
# Comma separated list without spaces!
# Example: DOCKER_COMPOSE_EXTRA_OVERRIDES=helper-scripts/docker-compose.override.yml.d/CONTAINER_ENGINE_PODMAN/docker-compose.override.yml,helper-scripts/docker-compose.override.yml.d/CUSTOM_STORAGE_LOCATION/docker-compose.override.yml
DOCKER_COMPOSE_EXTRA_OVERRIDES=
# The name of the docker-compose binary to use. This option can be used in case different versions of
# docker-compose are installed and another binary than 'docker-compose' (default) needs to be used.
# Example: docker-compose-v2
MAILCOW_DOCKER_COMPOSE=${MAILCOW_DOCKER_COMPOSE}
# ------------------------------ # ------------------------------
# Other bindings # Other bindings
# ------------------------------ # ------------------------------
@ -252,22 +328,9 @@ REDIS_PORT=127.0.0.1:7654
TZ=${MAILCOW_TZ} TZ=${MAILCOW_TZ}
# Fixed project name
# Please use lowercase letters only
COMPOSE_PROJECT_NAME=mailcowdockerized
# Used Docker Compose version
# Switch here between native (compose plugin) and standalone
# For more informations take a look at the mailcow docs regarding the configuration options.
# Normally this should be untouched but if you decided to use either of those you can switch it manually here.
# Please be aware that at least one of those variants should be installed on your maschine or mailcow will fail.
DOCKER_COMPOSE_VERSION=${COMPOSE_VERSION}
# Set this to "allow" to enable the anyone pseudo user. Disabled by default. # Set this to "allow" to enable the anyone pseudo user. Disabled by default.
# When enabled, ACL can be created, that apply to "All authenticated users" # When enabled, ACL can be created, that apply to "All authenticated users"
# This should probably only be activated on mail hosts, that are used exclusivly by one organisation. # This should probably only be activated on mail hosts, that are used exclusively by one organisation.
# Otherwise a user might share data with too many other users. # Otherwise a user might share data with too many other users.
ACL_ANYONE=disallow ACL_ANYONE=disallow

View File

@ -0,0 +1,46 @@
version: '3.9'
# Pre-requisites on the host machine
#
# Since the sysctl option cannot be set and podman needs additional privileges to bind
# to ports lower than 1024, the following options need to be set:
# sudo sysctl net.ipv4.ip_unprivileged_port_start=25
# sudo sysctl net.core.somaxconn=4096
#
# Apparently compose extends instead of overrides (except for volumes), see
# https://github.com/docker/compose/issues/3729
# Because of that, the patch-docker-compose-for-podman.sh script exists to remove these options from the original
# docker-compose.yml
services:
dovecot-mailcow:
cap_add:
- SYS_CHROOT
postfix-mailcow:
cap_add:
- SYS_CHROOT
dockerapi-mailcow:
volumes:
- ${MAILCOW_CONTAINER_SOCKET}:/var/run/docker.sock:ro
ofelia-mailcow:
volumes:
- ${MAILCOW_CONTAINER_SOCKET}:/var/run/docker.sock:ro
ipv6nat-mailcow:
image: bash:latest
restart: "no"
entrypoint: ["echo", "ipv6nat disabled in compose.override.yml"]
# Because docker-compose extends instead of overrides, the volume still needs to be overwritten, even when it is not used.
volumes:
- ${MAILCOW_CONTAINER_SOCKET}:/var/run/docker.sock:ro
networks:
mailcow-network:
driver: bridge
ipam:
config:
- subnet: ${IPV4_NETWORK:-172.22.1}.0/24

View File

@ -0,0 +1,66 @@
version: '2.1'
services:
mysql-mailcow:
volumes:
- ${MAILCOW_STORAGE_DIR}/mysql:/var/lib/mysql/
- ${MAILCOW_STORAGE_DIR}/mysql-socket:/var/run/mysqld/
redis-mailcow:
volumes:
- ${MAILCOW_STORAGE_DIR}/redis:/data/
clamd-mailcow:
volumes:
- ${MAILCOW_STORAGE_DIR}/clamd-db:/var/lib/clamav
rspamd-mailcow:
volumes:
- ${MAILCOW_STORAGE_DIR}/rspamd:/var/lib/rspamd
php-fpm-mailcow:
volumes:
- ${MAILCOW_STORAGE_DIR}/rspamd:/var/lib/rspamd
- ${MAILCOW_STORAGE_DIR}/mysql-socket:/var/run/mysqld/
sogo-mailcow:
volumes:
- ${MAILCOW_STORAGE_DIR}/mysql-socket:/var/run/mysqld/
- ${MAILCOW_STORAGE_DIR}/sogo-web:/sogo_web
- ${MAILCOW_STORAGE_DIR}/sogo-userdata-backup:/sogo_backup
dovecot-mailcow:
volumes:
- ${MAILCOW_STORAGE_DIR}/vmail:/var/vmail
- ${MAILCOW_STORAGE_DIR}/vmail-index:/var/vmail_index
- ${MAILCOW_STORAGE_DIR}/crypt:/mail_crypt/
- ${MAILCOW_STORAGE_DIR}/rspamd:/var/lib/rspamd
- ${MAILCOW_STORAGE_DIR}/mysql-socket:/var/run/mysqld/
postfix-mailcow:
volumes:
- ${MAILCOW_STORAGE_DIR}/postfix:/var/spool/postfix
- ${MAILCOW_STORAGE_DIR}/crypt:/var/lib/zeyple
- ${MAILCOW_STORAGE_DIR}/rspamd:/var/lib/rspamd
- ${MAILCOW_STORAGE_DIR}/mysql-socket:/var/run/mysqld/
nginx-mailcow:
volumes:
- ${MAILCOW_STORAGE_DIR}/sogo-web:/usr/lib/GNUstep/SOGo/
acme-mailcow:
volumes:
- ${MAILCOW_STORAGE_DIR}/mysql-socket:/var/run/mysqld/
watchdog-mailcow:
volumes:
- ${MAILCOW_STORAGE_DIR}/rspamd:/var/lib/rspamd
- ${MAILCOW_STORAGE_DIR}/mysql-socket:/var/run/mysqld/
- ${MAILCOW_STORAGE_DIR}/postfix:/var/spool/postfix
solr-mailcow:
volumes:
- ${MAILCOW_STORAGE_DIR}/solr:/opt/solr/server/solr/dovecot-fts/data
volumes: {}

View File

@ -7,8 +7,10 @@ if [[ -z ${DBUSER} ]] || [[ -z ${DBPASS} ]] || [[ -z ${DBNAME} ]]; then
exit 1 exit 1
fi fi
_engine="${MAILCOW_CONTAINER_ENGINE}"
echo -n "Checking MySQL service... " echo -n "Checking MySQL service... "
if [[ -z $(docker ps -qf name=mysql-mailcow) ]]; then if [[ -z $(${_engine} ps -qf name=mysql-mailcow) ]]; then
echo "failed" echo "failed"
echo "MySQL (mysql-mailcow) is not up and running, exiting..." echo "MySQL (mysql-mailcow) is not up and running, exiting..."
exit 1 exit 1
@ -20,11 +22,11 @@ response=${response,,} # tolower
if [[ "$response" =~ ^(yes|y)$ ]]; then if [[ "$response" =~ ^(yes|y)$ ]]; then
echo -e "\nWorking, please wait..." echo -e "\nWorking, please wait..."
random=$(</dev/urandom tr -dc _A-Z-a-z-0-9 | head -c${1:-16}) random=$(</dev/urandom tr -dc _A-Z-a-z-0-9 | head -c${1:-16})
password=$(docker exec -it $(docker ps -qf name=dovecot-mailcow) doveadm pw -s SSHA256 -p ${random} | tr -d '\r') password=$(${_engine} exec -it $(${_engine} ps -qf name=dovecot-mailcow) doveadm pw -s SSHA256 -p ${random} | tr -d '\r')
docker exec -it $(docker ps -qf name=mysql-mailcow) mysql -u${DBUSER} -p${DBPASS} ${DBNAME} -e "DELETE FROM admin WHERE username='admin';" ${_engine} exec -it $(${_engine} ps -qf name=mysql-mailcow) mysql -u${DBUSER} -p${DBPASS} ${DBNAME} -e "DELETE FROM admin WHERE username='admin';"
docker exec -it $(docker ps -qf name=mysql-mailcow) mysql -u${DBUSER} -p${DBPASS} ${DBNAME} -e "DELETE FROM domain_admins WHERE username='admin';" ${_engine} exec -it $(${_engine} ps -qf name=mysql-mailcow) mysql -u${DBUSER} -p${DBPASS} ${DBNAME} -e "DELETE FROM domain_admins WHERE username='admin';"
docker exec -it $(docker ps -qf name=mysql-mailcow) mysql -u${DBUSER} -p${DBPASS} ${DBNAME} -e "INSERT INTO admin (username, password, superadmin, active) VALUES ('admin', '${password}', 1, 1);" ${_engine} exec -it $(${_engine} ps -qf name=mysql-mailcow) mysql -u${DBUSER} -p${DBPASS} ${DBNAME} -e "INSERT INTO admin (username, password, superadmin, active) VALUES ('admin', '${password}', 1, 1);"
docker exec -it $(docker ps -qf name=mysql-mailcow) mysql -u${DBUSER} -p${DBPASS} ${DBNAME} -e "DELETE FROM tfa WHERE username='admin';" ${_engine} exec -it $(${_engine} ps -qf name=mysql-mailcow) mysql -u${DBUSER} -p${DBPASS} ${DBNAME} -e "DELETE FROM tfa WHERE username='admin';"
echo " echo "
Reset credentials: Reset credentials:
--- ---

View File

@ -1,30 +1,34 @@
#!/usr/bin/env bash #!/usr/bin/env bash
[[ -f mailcow.conf ]] && source mailcow.conf
[[ -f ../mailcow.conf ]] && source ../mailcow.conf
read -r -p "Are you sure you want to reset learned hashes from Rspamd (fuzzy, bayes, neural)? [y/N] " response read -r -p "Are you sure you want to reset learned hashes from Rspamd (fuzzy, bayes, neural)? [y/N] " response
response=${response,,} # tolower response=${response,,} # tolower
if [[ "$response" =~ ^(yes|y)$ ]]; then if [[ "$response" =~ ^(yes|y)$ ]]; then
_engine="${MAILCOW_CONTAINER_ENGINE}"
echo "Working, please wait..." echo "Working, please wait..."
REDIS_ID=$(docker ps -qf name=redis-mailcow) REDIS_ID=$(${_engine} ps -qf name=redis-mailcow)
RSPAMD_ID=$(docker ps -qf name=rspamd-mailcow) RSPAMD_ID=$(${_engine} ps -qf name=rspamd-mailcow)
if [ -z ${REDIS_ID} ] || [ -z ${RSPAMD_ID} ]; then if [ -z ${REDIS_ID} ] || [ -z ${RSPAMD_ID} ]; then
echo "Cannot determine Redis or Rspamd container ID" echo "Cannot determine Redis or Rspamd container ID"
exit 1 exit 1
else else
echo "Stopping Rspamd container" echo "Stopping Rspamd container"
docker stop ${RSPAMD_ID} ${_engine} stop ${RSPAMD_ID}
echo "LUA will return nil when it succeeds or print a warning/error when it fails." echo "LUA will return nil when it succeeds or print a warning/error when it fails."
echo "Deleting all RS* keys - if any" echo "Deleting all RS* keys - if any"
docker exec -it ${REDIS_ID} redis-cli EVAL "for _,k in ipairs(redis.call('keys', ARGV[1])) do redis.call('del', k) end" 0 'RS*' ${_engine} exec -it ${REDIS_ID} redis-cli EVAL "for _,k in ipairs(redis.call('keys', ARGV[1])) do redis.call('del', k) end" 0 'RS*'
echo "Deleting all BAYES* keys - if any" echo "Deleting all BAYES* keys - if any"
docker exec -it ${REDIS_ID} redis-cli EVAL "for _,k in ipairs(redis.call('keys', ARGV[1])) do redis.call('del', k) end" 0 'BAYES*' ${_engine} exec -it ${REDIS_ID} redis-cli EVAL "for _,k in ipairs(redis.call('keys', ARGV[1])) do redis.call('del', k) end" 0 'BAYES*'
echo "Deleting all learned* keys - if any" echo "Deleting all learned* keys - if any"
docker exec -it ${REDIS_ID} redis-cli EVAL "for _,k in ipairs(redis.call('keys', ARGV[1])) do redis.call('del', k) end" 0 'learned*' ${_engine} exec -it ${REDIS_ID} redis-cli EVAL "for _,k in ipairs(redis.call('keys', ARGV[1])) do redis.call('del', k) end" 0 'learned*'
echo "Deleting all fuzzy* keys - if any" echo "Deleting all fuzzy* keys - if any"
docker exec -it ${REDIS_ID} redis-cli EVAL "for _,k in ipairs(redis.call('keys', ARGV[1])) do redis.call('del', k) end" 0 'fuzzy*' ${_engine} exec -it ${REDIS_ID} redis-cli EVAL "for _,k in ipairs(redis.call('keys', ARGV[1])) do redis.call('del', k) end" 0 'fuzzy*'
echo "Deleting all tRFANN* keys - if any" echo "Deleting all tRFANN* keys - if any"
docker exec -it ${REDIS_ID} redis-cli EVAL "for _,k in ipairs(redis.call('keys', ARGV[1])) do redis.call('del', k) end" 0 'tRFANN*' ${_engine} exec -it ${REDIS_ID} redis-cli EVAL "for _,k in ipairs(redis.call('keys', ARGV[1])) do redis.call('del', k) end" 0 'tRFANN*'
echo "Starting Rspamd container" echo "Starting Rspamd container"
docker start ${RSPAMD_ID} ${_engine} start ${RSPAMD_ID}
fi fi
fi fi

View File

@ -4,56 +4,65 @@ SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
source ${SCRIPT_DIR}/../mailcow.conf source ${SCRIPT_DIR}/../mailcow.conf
if [ "${DOCKER_COMPOSE_VERSION}" == "standalone" ]; then if [ "${DOCKER_COMPOSE_VERSION}" == "standalone" ]; then
LATEST_COMPOSE=$(curl -Ls -w %{url_effective} -o /dev/null https://github.com/docker/compose/releases/latest) # redirect to latest release _compose="${MAILCOW_DOCKER_COMPOSE:-"docker-compose"}"
LATEST_COMPOSE=${LATEST_COMPOSE##*/v} #get the latest version from the redirect, excluding the "v" prefix
COMPOSE_VERSION=$(docker-compose version --short) LATEST_COMPOSE=$(curl -Ls -w %{url_effective} -o /dev/null https://github.com/docker/compose/releases/latest) # redirect to latest release
if [[ "$LATEST_COMPOSE" != "$COMPOSE_VERSION" ]]; then LATEST_COMPOSE=${LATEST_COMPOSE##*/v} #get the latest version from the redirect, excluding the "v" prefix
echo -e "\e[33mA new docker-compose Version is available: $LATEST_COMPOSE\e[0m" COMPOSE_VERSION=$(${_compose} version --short)
echo -e "\e[33mYour Version is: $COMPOSE_VERSION\e[0m" if [[ "$LATEST_COMPOSE" != "$COMPOSE_VERSION" ]]; then
else echo -e "\e[33mA new docker-compose Version is available: $LATEST_COMPOSE\e[0m"
echo -e "\e[32mYour docker-compose Version is up to date! Not updating it...\e[0m" echo -e "\e[33mYour Version of '${_compose}' is: $COMPOSE_VERSION\e[0m"
exit 0 else
fi echo -e "\e[32mYour docker-compose Version is up to date! Not updating it...\e[0m"
read -r -p "Do you want to update your docker-compose Version? It will automatic upgrade your docker-compose installation (recommended)? [y/N] " updatecomposeresponse exit 0
fi
read -r -p "Do you want to update your docker-compose Version? It will automatic upgrade your docker-compose installation (recommended)? [y/N] " updatecomposeresponse
if [[ ! "${updatecomposeresponse}" =~ ^([yY][eE][sS]|[yY])+$ ]]; then if [[ ! "${updatecomposeresponse}" =~ ^([yY][eE][sS]|[yY])+$ ]]; then
echo "OK, not updating docker-compose." echo "OK, not updating docker-compose."
exit 0 exit 0
fi fi
echo -e "\e[32mFetching new docker-compose (standalone) version...\e[0m" echo -e "\e[32mFetching new docker-compose (standalone) version...\e[0m"
echo -e "\e[32mTrying to determine GLIBC version...\e[0m" echo -e "\e[32mTrying to determine GLIBC version...\e[0m"
if ldd --version > /dev/null; then if ldd --version > /dev/null; then
GLIBC_V=$(ldd --version | grep -E '(GLIBC|GNU libc)' | rev | cut -d ' ' -f1 | rev | cut -d '.' -f2) 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 if [ ! -z "${GLIBC_V}" ] && [ ${GLIBC_V} -gt 27 ]; then
DC_DL_SUFFIX= DC_DL_SUFFIX=
else else
DC_DL_SUFFIX=legacy DC_DL_SUFFIX=legacy
fi fi
else else
DC_DL_SUFFIX=legacy DC_DL_SUFFIX=legacy
fi fi
sleep 1 sleep 1
if [[ $(command -v pip 2>&1) && $(pip list --local 2>&1 | grep -v DEPRECATION | grep -c docker-compose) == 1 || $(command -v pip3 2>&1) && $(pip3 list --local 2>&1 | grep -v DEPRECATION | grep -c docker-compose) == 1 ]]; then if [[ "${_compose}" == "docker-compose" ]] && [[ $(command -v pip 2>&1) && $(pip list --local 2>&1 | grep -v DEPRECATION | grep -c docker-compose) == 1 || $(command -v pip3 2>&1) && $(pip3 list --local 2>&1 | grep -v DEPRECATION | grep -c docker-compose) == 1 ]]; then
echo -e "\e[33mFound a docker-compose Version installed with pip!\e[0m" echo -e "\e[33mFound a docker-compose Version installed with pip!\e[0m"
echo -e "\e[31mPlease uninstall the pip Version of docker-compose since it doesn't support Versions higher than 1.29.2.\e[0m" echo -e "\e[31mPlease uninstall the pip Version of docker-compose since it doesn't support Versions higher than 1.29.2.\e[0m"
sleep 2 sleep 2
echo -e "\e[33mExiting...\e[0m" echo -e "\e[33mExiting...\e[0m"
exit 1 exit 1
#prevent breaking a working docker-compose installed with pip #prevent breaking a working docker-compose installed with pip
#when ${_compose} is set to a non-default value, don't complain, since in some cases both v1 and v2 are used
elif [[ $(curl -sL -w "%{http_code}" https://github.com/docker/compose/releases/latest -o /dev/null) == "200" ]]; then elif [[ $(curl -sL -w "%{http_code}" https://github.com/docker/compose/releases/latest -o /dev/null) == "200" ]]; then
LATEST_COMPOSE=$(curl -Ls -w %{url_effective} -o /dev/null https://github.com/docker/compose/releases/latest) # redirect to latest release LATEST_COMPOSE=$(curl -Ls -w %{url_effective} -o /dev/null https://github.com/docker/compose/releases/latest) # redirect to latest release
LATEST_COMPOSE=${LATEST_COMPOSE##*/} #get the latest version from the redirect, inlcuding the "v" prefix LATEST_COMPOSE=${LATEST_COMPOSE##*/} #get the latest version from the redirect, including the "v" prefix
COMPOSE_VERSION=$(docker-compose version --short) COMPOSE_VERSION=$(${_compose} version --short)
if [[ "$LATEST_COMPOSE" != "$COMPOSE_VERSION" ]]; then if [[ "$LATEST_COMPOSE" != "$COMPOSE_VERSION" ]]; then
COMPOSE_PATH=$(command -v docker-compose) COMPOSE_PATH=$(command -v ${_compose})
if [[ -w ${COMPOSE_PATH} ]]; then if [[ -w ${COMPOSE_PATH} ]]; then
curl -#L https://github.com/docker/compose/releases/download/${LATEST_COMPOSE}/docker-compose-$(uname -s)-$(uname -m) > $COMPOSE_PATH curl -#L https://github.com/docker/compose/releases/download/${LATEST_COMPOSE}/docker-compose-$(uname -s)-$(uname -m) > $COMPOSE_PATH
chmod +x $COMPOSE_PATH RC=$?
echo -e "\e[32mYour Docker Compose (standalone) has been updated to: $LATEST_COMPOSE\e[0m" if [[ $RC -eq 0 ]]; then
exit 0 chmod +x $COMPOSE_PATH
else echo -e "\e[32mYour Docker Compose (standalone) has been updated to: $LATEST_COMPOSE\e[0m"
echo -e "\e[33mWARNING: $COMPOSE_PATH is not writable, but new version $LATEST_COMPOSE is available (installed: $COMPOSE_VERSION)\e[0m" exit 0
exit 1 else
fi echo -e "\e[31mError with updating $COMPOSE_PATH, please retry...\e[0m"
exit 1
fi
else
echo -e "\e[33mWARNING: $COMPOSE_PATH is not writable, but new version $LATEST_COMPOSE is available (installed: $COMPOSE_VERSION)\e[0m"
exit 1
fi
fi fi
else else
echo -e "\e[33mCannot determine latest docker-compose version, skipping...\e[0m" echo -e "\e[33mCannot determine latest docker-compose version, skipping...\e[0m"
@ -69,4 +78,4 @@ elif [ "${DOCKER_COMPOSE_VERSION}" == "native" ]; then
else else
echo -e "\e[31mCan not read DOCKER_COMPOSE_VERSION variable from mailcow.conf! Is your mailcow up to date? Exiting...\e[0m" echo -e "\e[31mCan not read DOCKER_COMPOSE_VERSION variable from mailcow.conf! Is your mailcow up to date? Exiting...\e[0m"
exit 1 exit 1
fi fi

110
mailcow-compose.sh Executable file
View File

@ -0,0 +1,110 @@
#!/usr/bin/env bash
#
# docker-compose wrapper script for mailcow
#---------------------------------------
# functions
#---------------------------------------
function validate_input()
{
if [[ "$#" -eq 0 ]]; then
echo -e "\e[31mNo arguments given. Call this script with e.g. 'up -d' or 'down'\e[0m"
exit 1
fi
if [[ ! -f mailcow.conf ]]; then
echo -e "\e[31mmailcow.conf is missing! Is mailcow installed?\e[0m"
exit 1
fi
source mailcow.conf
}
function detect_docker_compose_command()
{
if ! [[ "${DOCKER_COMPOSE_VERSION}" == "native" ]] && ! [[ "${DOCKER_COMPOSE_VERSION}" == "standalone" ]]; then
if docker compose > /dev/null 2>&1; then
if docker compose version --short | grep "2." > /dev/null 2>&1; then
DOCKER_COMPOSE_VERSION=native
COMPOSE_COMMAND="docker compose"
echo -e "\e[31mFound Docker Compose Plugin (native).\e[0m"
echo -e "\e[31mSetting the DOCKER_COMPOSE_VERSION Variable to native\e[0m"
sleep 2
echo -e "\e[33mNotice: You'll have to update this Compose Version via your Package Manager manually! \e[0m"
else
echo -e "\e[31mCannot find Docker Compose with a Version Higher than 2.X.X.\e[0m"
echo -e "\e[31mPlease update/install it manually regarding to this doc site: https://mailcow.github.io/mailcow-dockerized-docs/i_u_m/i_u_m_install/\e[0m"
exit 1
fi
elif docker-compose > /dev/null 2>&1; then
if ! [[ $(alias docker-compose 2> /dev/null) ]] ; then
if docker-compose version --short | grep "^2." > /dev/null 2>&1; then
DOCKER_COMPOSE_VERSION=standalone
COMPOSE_COMMAND="docker-compose"
echo -e "\e[31mFound Docker Compose Standalone.\e[0m"
echo -e "\e[31mSetting the DOCKER_COMPOSE_VERSION Variable to standalone\e[0m"
sleep 2
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"
else
echo -e "\e[31mCannot find Docker Compose with a Version Higher than 2.X.X.\e[0m"
echo -e "\e[31mPlease update/install regarding to this doc site: https://mailcow.github.io/mailcow-dockerized-docs/i_u_m/i_u_m_install/\e[0m"
exit 1
fi
fi
else
echo -e "\e[31mCannot find Docker Compose.\e[0m"
echo -e "\e[31mPlease install it regarding to this doc site: https://mailcow.github.io/mailcow-dockerized-docs/i_u_m/i_u_m_install/\e[0m"
exit 1
fi
elif [[ "${DOCKER_COMPOSE_VERSION}" == "native" ]]; then
COMPOSE_COMMAND="docker compose"
elif [[ "${DOCKER_COMPOSE_VERSION}" == "standalone" ]]; then
COMPOSE_COMMAND="${MAILCOW_DOCKER_COMPOSE:-"docker-compose"}"
fi
}
function ensure_storage_directories_exist()
{
# In case the user specified MAILCOW_STORAGE_DIR, create the required subdirectories.
if [[ -n "${MAILCOW_STORAGE_DIR}" ]]; then
mkdir -p "${MAILCOW_STORAGE_DIR}/clamd-db"
mkdir -p "${MAILCOW_STORAGE_DIR}/crypt"
mkdir -p "${MAILCOW_STORAGE_DIR}/mysql"
mkdir -p "${MAILCOW_STORAGE_DIR}/mysql-socket"
mkdir -p "${MAILCOW_STORAGE_DIR}/postfix"
mkdir -p "${MAILCOW_STORAGE_DIR}/redis"
mkdir -p "${MAILCOW_STORAGE_DIR}/rspamd"
mkdir -p "${MAILCOW_STORAGE_DIR}/sogo-userdata-backup"
mkdir -p "${MAILCOW_STORAGE_DIR}/sogo-web"
mkdir -p "${MAILCOW_STORAGE_DIR}/solr"
mkdir -p "${MAILCOW_STORAGE_DIR}/vmail"
mkdir -p "${MAILCOW_STORAGE_DIR}/vmail-index"
fi
}
function run_compose()
{
if [[ -n "${DOCKER_COMPOSE_EXTRA_OVERRIDES}" ]]; then
IFS=',' read -r -a overrides <<< "${DOCKER_COMPOSE_EXTRA_OVERRIDES}"
COMPOSE_ARGUMENTS="-f docker-compose.yml "
for override in "${overrides[@]}"; do
COMPOSE_ARGUMENTS+="-f ${override} "
done
else
COMPOSE_ARGUMENTS=""
fi
echo -e "\e[32mExecuting: ${COMPOSE_COMMAND} ${COMPOSE_ARGUMENTS} $@ \e[0m"
${COMPOSE_COMMAND} ${COMPOSE_ARGUMENTS} $@
}
#---------------------------------------
# main
#---------------------------------------
validate_input $@
detect_docker_compose_command
ensure_storage_directories_exist
run_compose $@

View File

@ -0,0 +1,125 @@
--- docker-compose-original.yml 2023-01-09 13:46:07.792778709 +0100
+++ docker-compose.yml 2023-01-09 13:45:20.828836564 +0100
@@ -55,8 +55,8 @@
- "${REDIS_PORT:-127.0.0.1:7654}:6379"
environment:
- TZ=${TZ}
- sysctls:
- - net.core.somaxconn=4096
+# sysctls:
+# - net.core.somaxconn=4096
networks:
mailcow-network:
ipv4_address: ${IPV4_NETWORK:-172.22.1}.249
@@ -68,8 +68,8 @@
restart: always
depends_on:
- unbound-mailcow
- dns:
- - ${IPV4_NETWORK:-172.22.1}.254
+# dns:
+# - ${IPV4_NETWORK:-172.22.1}.254
environment:
- TZ=${TZ}
- SKIP_CLAMD=${SKIP_CLAMD:-n}
@@ -108,8 +108,8 @@
- label=disable
restart: always
hostname: rspamd
- dns:
- - ${IPV4_NETWORK:-172.22.1}.254
+# dns:
+# - ${IPV4_NETWORK:-172.22.1}.254
networks:
mailcow-network:
aliases:
@@ -140,8 +140,8 @@
- ./data/conf/nginx/:/etc/nginx/conf.d/
security_opt:
- label=disable
- dns:
- - ${IPV4_NETWORK:-172.22.1}.254
+# dns:
+# - ${IPV4_NETWORK:-172.22.1}.254
environment:
- REDIS_SLAVEOF_IP=${REDIS_SLAVEOF_IP:-}
- REDIS_SLAVEOF_PORT=${REDIS_SLAVEOF_PORT:-}
@@ -198,8 +198,8 @@
- MASTER=${MASTER:-y}
- REDIS_SLAVEOF_IP=${REDIS_SLAVEOF_IP:-}
- REDIS_SLAVEOF_PORT=${REDIS_SLAVEOF_PORT:-}
- dns:
- - ${IPV4_NETWORK:-172.22.1}.254
+# dns:
+# - ${IPV4_NETWORK:-172.22.1}.254
volumes:
- ./data/hooks/sogo:/hooks
- ./data/conf/sogo/:/etc/sogo/
@@ -233,8 +233,8 @@
image: mailcow/dovecot:1.21
depends_on:
- mysql-mailcow
- dns:
- - ${IPV4_NETWORK:-172.22.1}.254
+# dns:
+# - ${IPV4_NETWORK:-172.22.1}.254
cap_add:
- NET_BIND_SERVICE
volumes:
@@ -341,8 +341,8 @@
- "${SMTPS_PORT:-465}:465"
- "${SUBMISSION_PORT:-587}:587"
restart: always
- dns:
- - ${IPV4_NETWORK:-172.22.1}.254
+# dns:
+# - ${IPV4_NETWORK:-172.22.1}.254
networks:
mailcow-network:
ipv4_address: ${IPV4_NETWORK:-172.22.1}.253
@@ -367,8 +367,8 @@
- php-fpm-mailcow
- redis-mailcow
image: nginx:mainline-alpine
- dns:
- - ${IPV4_NETWORK:-172.22.1}.254
+# dns:
+# - ${IPV4_NETWORK:-172.22.1}.254
command: /bin/sh -c "envsubst < /etc/nginx/conf.d/templates/listen_plain.template > /etc/nginx/conf.d/listen_plain.active &&
envsubst < /etc/nginx/conf.d/templates/listen_ssl.template > /etc/nginx/conf.d/listen_ssl.active &&
envsubst < /etc/nginx/conf.d/templates/sogo.template > /etc/nginx/conf.d/sogo.active &&
@@ -412,8 +412,8 @@
depends_on:
- nginx-mailcow
image: mailcow/acme:1.83
- dns:
- - ${IPV4_NETWORK:-172.22.1}.254
+# dns:
+# - ${IPV4_NETWORK:-172.22.1}.254
environment:
- LOG_LINES=${LOG_LINES:-9999}
- ACME_CONTACT=${ACME_CONTACT:-}
@@ -475,8 +475,8 @@
watchdog-mailcow:
image: mailcow/watchdog:1.97
- dns:
- - ${IPV4_NETWORK:-172.22.1}.254
+# dns:
+# - ${IPV4_NETWORK:-172.22.1}.254
tmpfs:
- /tmp
volumes:
@@ -542,9 +542,9 @@
security_opt:
- label=disable
restart: always
- oom_kill_disable: true
- dns:
- - ${IPV4_NETWORK:-172.22.1}.254
+# oom_kill_disable: true
+# dns:
+# - ${IPV4_NETWORK:-172.22.1}.254
environment:
- DBROOT=${DBROOT}
- TZ=${TZ}

22
patches-for-podman.sh Executable file
View File

@ -0,0 +1,22 @@
#!/usr/bin/env bash
#
# This script patches the docker-compose.yml for usage with podman.
# This is necessary because not all options (e.g. DNS) can be overwritten by docker-compose, see
# https://github.com/docker/compose/issues/3729
#
# Next to that because IPv6 does not work (yet), patch the MySQL configuration file to bind to IPv4
set -e
PATCH_FILE="patch-docker-compose-for-podman.patch"
TIMESTAMP="$(date +'%Y%m%d%H%M')"
# Create a backup (in case custom changes are made)
cp docker-compose.yml docker-compose.yml.${TIMESTAMP}.bak
# Detect whether the patch has been applied by trying to reverse the patch in a dry-run scenario
if ! patch -R -s -f --dry-run docker-compose.yml < ${PATCH_FILE} > /dev/null 2>&1; then
patch docker-compose.yml < ${PATCH_FILE}
else
echo "docker-compose.yml already patched (or custom changes prevent applying the patch)"
fi

288
update.sh
View File

@ -22,7 +22,7 @@ prefetch_images() {
fi fi
fi fi
RET_C=0 RET_C=0
until docker pull ${image}; do until ${MAILCOW_CONTAINER_ENGINE} pull ${image}; do
RET_C=$((RET_C + 1)) RET_C=$((RET_C + 1))
echo -e "\e[33m\nError pulling $image, retrying...\e[0m" 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; } [ ${RET_C} -gt 3 ] && { echo -e "\e[31m\nToo many failed retries, exiting\e[0m"; exit 1; }
@ -38,7 +38,7 @@ docker_garbage() {
TAG=${container/*:} TAG=${container/*:}
V_MAIN=${container/*.} V_MAIN=${container/*.}
V_SUB=${container/*.} V_SUB=${container/*.}
EXISTING_TAGS=$(docker images | grep ${REPOSITORY} | awk '{ print $2 }') EXISTING_TAGS=$(${MAILCOW_CONTAINER_ENGINE} images | grep ${REPOSITORY} | awk '{ print $2 }')
for existing_tag in ${EXISTING_TAGS[@]}; do for existing_tag in ${EXISTING_TAGS[@]}; do
V_MAIN_EXISTING=${existing_tag/*.} V_MAIN_EXISTING=${existing_tag/*.}
V_SUB_EXISTING=${existing_tag/*.} V_SUB_EXISTING=${existing_tag/*.}
@ -62,21 +62,21 @@ docker_garbage() {
if [[ ! -z ${IMGS_TO_DELETE[*]} ]]; then if [[ ! -z ${IMGS_TO_DELETE[*]} ]]; then
echo "Run the following command to delete unused image tags:" echo "Run the following command to delete unused image tags:"
echo echo
echo " docker rmi ${IMGS_TO_DELETE[*]}" echo " ${MAILCOW_CONTAINER_ENGINE} rmi ${IMGS_TO_DELETE[*]}"
echo echo
if [ ! $FORCE ]; then if [ ! $FORCE ]; then
read -r -p "Do you want to delete old image tags right now? [y/N] " response read -r -p "Do you want to delete old image tags right now? [y/N] " response
if [[ "$response" =~ ^([yY][eE][sS]|[yY])+$ ]]; then if [[ "$response" =~ ^([yY][eE][sS]|[yY])+$ ]]; then
docker rmi ${IMGS_TO_DELETE[*]} ${MAILCOW_CONTAINER_ENGINE} rmi ${IMGS_TO_DELETE[*]}
else else
echo "OK, skipped." echo "OK, skipped."
fi fi
else else
echo "Running image removal without extra confirmation due to force mode." echo "Running image removal without extra confirmation due to force mode."
docker rmi ${IMGS_TO_DELETE[*]} ${MAILCOW_CONTAINER_ENGINE} rmi ${IMGS_TO_DELETE[*]}
fi fi
echo -e "\e[32mFurther cleanup...\e[0m" 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\"" echo "If you want to cleanup further garbage collected by ${MAILCOW_CONTAINER_ENGINE}, please make sure all containers are up and running before cleaning your system by executing \"${MAILCOW_CONTAINER_ENGINE} system prune\""
fi fi
} }
@ -139,10 +139,10 @@ migrate_docker_nat() {
# Removing legacy container # Removing legacy container
sed -i '/ipv6nat-mailcow:$/,/^$/d' docker-compose.yml sed -i '/ipv6nat-mailcow:$/,/^$/d' docker-compose.yml
if [ -s docker-compose.override.yml ]; then if [ -s docker-compose.override.yml ]; then
sed -i '/ipv6nat-mailcow:$/,/^$/d' docker-compose.override.yml sed -i '/ipv6nat-mailcow:$/,/^$/d' docker-compose.override.yml
if [[ "$(cat docker-compose.override.yml | sed '/^\s*$/d' | wc -l)" == "2" ]]; then if [[ "$(cat docker-compose.override.yml | sed '/^\s*$/d' | wc -l)" == "2" ]]; then
mv docker-compose.override.yml docker-compose.override.yml_backup mv docker-compose.override.yml docker-compose.override.yml_backup
fi fi
fi fi
echo -e "\e[32mGreat! \e[0mNative IPv6 NAT is active.\e[0m" echo -e "\e[32mGreat! \e[0mNative IPv6 NAT is active.\e[0m"
else else
@ -152,82 +152,47 @@ migrate_docker_nat() {
} }
remove_obsolete_nginx_ports() { remove_obsolete_nginx_ports() {
# Removing obsolete docker-compose.override.yml # Removing obsolete docker-compose.override.yml
for override in docker-compose.override.yml docker-compose.override.yaml; do for override in docker-compose.override.yml docker-compose.override.yaml; do
if [ -s $override ] ; then if [ -s $override ] ; then
if cat $override | grep nginx-mailcow > /dev/null 2>&1; then if cat $override | grep nginx-mailcow > /dev/null 2>&1; then
if cat $override | grep -E '(\[::])' > /dev/null 2>&1; then if cat $override | grep -E '(\[::])' > /dev/null 2>&1; then
if cat $override | grep -w 80:80 > /dev/null 2>&1 && cat $override | grep -w 443:443 > /dev/null 2>&1 ; then if cat $override | grep -w 80:80 > /dev/null 2>&1 && cat $override | grep -w 443:443 > /dev/null 2>&1 ; then
echo -e "\e[33mBacking up ${override} to preserve custom changes...\e[0m" echo -e "\e[33mBacking up ${override} to preserve custom changes...\e[0m"
echo -e "\e[33m!!! Manual Merge needed (if other overrides are set) !!!\e[0m" echo -e "\e[33m!!! Manual Merge needed (if other overrides are set) !!!\e[0m"
sleep 3 sleep 3
cp $override ${override}_backup cp $override ${override}_backup
sed -i '/nginx-mailcow:$/,/^$/d' $override sed -i '/nginx-mailcow:$/,/^$/d' $override
echo -e "\e[33mRemoved obsolete NGINX IPv6 Bind from original override File.\e[0m" echo -e "\e[33mRemoved obsolete NGINX IPv6 Bind from original override File.\e[0m"
if [[ "$(cat $override | sed '/^\s*$/d' | wc -l)" == "2" ]]; then if [[ "$(cat $override | sed '/^\s*$/d' | wc -l)" == "2" ]]; then
mv $override ${override}_empty mv $override ${override}_empty
echo -e "\e[31m${override} is empty. Renamed it to ensure mailcow is startable.\e[0m" echo -e "\e[31m${override} is empty. Renamed it to ensure mailcow is startable.\e[0m"
fi
fi fi
fi
fi fi
fi
done
}
detect_docker_compose_command(){
if ! [ "${DOCKER_COMPOSE_VERSION}" == "native" ] && ! [ "${DOCKER_COMPOSE_VERSION}" == "standalone" ]; then
if docker compose > /dev/null 2>&1; then
if docker compose version --short | grep "2." > /dev/null 2>&1; then
DOCKER_COMPOSE_VERSION=native
COMPOSE_COMMAND="docker compose"
echo -e "\e[31mFound Docker Compose Plugin (native).\e[0m"
echo -e "\e[31mSetting the DOCKER_COMPOSE_VERSION Variable to native\e[0m"
sleep 2
echo -e "\e[33mNotice: You'll have to update this Compose Version via your Package Manager manually!\e[0m"
else
echo -e "\e[31mCannot find Docker Compose with a Version Higher than 2.X.X.\e[0m"
echo -e "\e[31mPlease update/install it manually regarding to this doc site: https://mailcow.github.io/mailcow-dockerized-docs/i_u_m/i_u_m_install/\e[0m"
exit 1
fi
elif docker-compose > /dev/null 2>&1; then
if ! [[ $(alias docker-compose 2> /dev/null) ]] ; then
if docker-compose version --short | grep "^2." > /dev/null 2>&1; then
DOCKER_COMPOSE_VERSION=standalone
COMPOSE_COMMAND="docker-compose"
echo -e "\e[31mFound Docker Compose Standalone.\e[0m"
echo -e "\e[31mSetting the DOCKER_COMPOSE_VERSION Variable to standalone\e[0m"
sleep 2
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"
else
echo -e "\e[31mCannot find Docker Compose with a Version Higher than 2.X.X.\e[0m"
echo -e "\e[31mPlease update/install regarding to this doc site: https://mailcow.github.io/mailcow-dockerized-docs/i_u_m/i_u_m_install/\e[0m"
exit 1
fi fi
fi fi
else
echo -e "\e[31mCannot find Docker Compose.\e[0m"
echo -e "\e[31mPlease install it regarding to this doc site: https://mailcow.github.io/mailcow-dockerized-docs/i_u_m/i_u_m_install/\e[0m"
exit 1
fi fi
done
elif [ "${DOCKER_COMPOSE_VERSION}" == "native" ]; then
COMPOSE_COMMAND="docker compose"
elif [ "${DOCKER_COMPOSE_VERSION}" == "standalone" ]; then
COMPOSE_COMMAND="docker-compose"
fi
} }
############## End Function Section ############## ############## End Function Section ##############
# Check permissions # Exit on error and pipefail
if [ "$(id -u)" -ne "0" ]; then set -o pipefail
echo "You need to be root"
if [[ ! -f mailcow.conf ]]; then
echo -e "\e[31mmailcow.conf is missing! Is mailcow installed?\e[0m"
exit 1 exit 1
fi fi
chmod 600 mailcow.conf
source mailcow.conf
# Check permissions (only when docker is wanted)
if ([[ -z "${MAILCOW_CONTAINER_ENGINE}" ]] || [[ "${MAILCOW_CONTAINER_ENGINE}" == "docker" ]]) && [[ "$(id -u)" -ne "0" ]]; then
echo "You need to be root"
fi
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
# Run pre-update-hook # Run pre-update-hook
@ -251,9 +216,6 @@ if [[ "$(uname -r)" =~ ^4\.4\. ]]; then
read -p "Press any key to continue..." < /dev/tty read -p "Press any key to continue..." < /dev/tty
fi fi
# Exit on error and pipefail
set -o pipefail
# Setting high dc timeout # Setting high dc timeout
export COMPOSE_HTTP_TIMEOUT=600 export COMPOSE_HTTP_TIMEOUT=600
@ -262,15 +224,38 @@ PATH=$PATH:/opt/bin
umask 0022 umask 0022
# Unset COMPOSE_COMMAND and DOCKER_COMPOSE_VERSION Variable to be on the newest state. # Check if the container engine flag is set, otherwise set it
unset COMPOSE_COMMAND if [[ -z "${MAILCOW_CONTAINER_ENGINE}" ]]; then
unset DOCKER_COMPOSE_VERSION if command -v podman > /dev/null 2>&1; then
MAILCOW_CONTAINER_ENGINE="podman"
echo -e "\e[32mFound Podman container engine.\e[0m"
echo -e "\e[31mNOTE: Support for Podman is experimental, consider this before deploying to production! \e[0m"
for bin in curl docker git awk sha1sum; do if [[ -n "${DOCKER_HOST}" ]] && [[ "${DOCKER_HOST}" == "unix://"* ]]; then
if [[ -z $(command -v ${bin}) ]]; then CONTAINER_SOCKET="${DOCKER_HOST/"unix://"/}"
echo "Cannot find ${bin}, exiting..." else
exit 1; CONTAINER_SOCKET="/run/user/${UID}/podman/podman.sock"
fi fi
# To patch the docker-compose file for use with podman
EXTRA_REQUIRED_PACKAGES="patch"
elif command -v docker > /dev/null 2>&1; then
MAILCOW_CONTAINER_ENGINE="docker"
echo -e "\e[32mFound Docker container engine.\e[0m"
CONTAINER_SOCKET="/var/run/docker.sock"
EXTRA_REQUIRED_PACKAGES=""
else
echo "Cannot find container engine (Docker or Podman), exiting..."
exit 1
fi
fi
for bin in curl git awk sha1sum ${EXTRA_REQUIRED_PACKAGES}; do
if [[ -z $(command -v ${bin}) ]]; then
echo "Cannot find ${bin}, exiting..."
exit 1
fi
done done
export LC_ALL=C export LC_ALL=C
@ -344,16 +329,11 @@ while (($#)); do
shift shift
done done
chmod 600 mailcow.conf
source mailcow.conf
detect_docker_compose_command
[[ ! -f mailcow.conf ]] && { echo "mailcow.conf is missing! Is mailcow installed?"; exit 1;}
DOTS=${MAILCOW_HOSTNAME//[^.]}; DOTS=${MAILCOW_HOSTNAME//[^.]};
if [ ${#DOTS} -lt 2 ]; then if [ ${#DOTS} -lt 2 ]; then
echo "MAILCOW_HOSTNAME (${MAILCOW_HOSTNAME}) is not a FQDN!" echo "MAILCOW_HOSTNAME (${MAILCOW_HOSTNAME}) is not a FQDN!"
echo "Please change it to a FQDN and run $COMPOSE_COMMAND down followed by $COMPOSE_COMMAND up -d" echo "Please change it to a FQDN and run \"./mailcow-compose.sh down\" followed by \"./mailcow-compose.sh up -d\""
exit 1 exit 1
fi fi
@ -381,6 +361,10 @@ CONFIG_ARRAY=(
"SNAT6_TO_SOURCE" "SNAT6_TO_SOURCE"
"COMPOSE_PROJECT_NAME" "COMPOSE_PROJECT_NAME"
"DOCKER_COMPOSE_VERSION" "DOCKER_COMPOSE_VERSION"
"MAILCOW_CONTAINER_ENGINE"
"MAILCOW_CONTAINER_SOCKET"
"DOCKER_COMPOSE_EXTRA_OVERRIDES"
"MAILCOW_DOCKER_COMPOSE"
"SQL_PORT" "SQL_PORT"
"API_KEY" "API_KEY"
"API_KEY_READ_ONLY" "API_KEY_READ_ONLY"
@ -402,6 +386,7 @@ CONFIG_ARRAY=(
"ACME_CONTACT" "ACME_CONTACT"
"WATCHDOG_VERBOSE" "WATCHDOG_VERBOSE"
"WEBAUTHN_ONLY_TRUSTED_VENDORS" "WEBAUTHN_ONLY_TRUSTED_VENDORS"
"MAILCOW_STORAGE_DIR"
) )
sed -i --follow-symlinks '$a\' mailcow.conf sed -i --follow-symlinks '$a\' mailcow.conf
@ -421,12 +406,44 @@ for option in ${CONFIG_ARRAY[@]}; do
echo "Adding new option \"${option}\" to mailcow.conf" echo "Adding new option \"${option}\" to mailcow.conf"
echo "# Used Docker Compose version" >> mailcow.conf echo "# Used Docker Compose version" >> mailcow.conf
echo "# Switch here between native (compose plugin) and standalone" >> mailcow.conf echo "# Switch here between native (compose plugin) and standalone" >> mailcow.conf
echo "# For more informations take a look at the mailcow docs regarding the configuration options." >> mailcow.conf echo "# For more information take a look at the mailcow docs regarding the configuration options." >> mailcow.conf
echo "# Normally this should be untouched but if you decided to use either of those you can switch it manually here." >> mailcow.conf echo "# Normally this should be untouched but if you decided to use either of those you can switch it manually here." >> mailcow.conf
echo "# Please be aware that at least one of those variants should be installed on your maschine or mailcow will fail." >> mailcow.conf echo "# Please be aware that at least one of those variants should be installed on your machine or mailcow will fail." >> mailcow.conf
echo "" >> mailcow.conf echo "" >> mailcow.conf
echo "DOCKER_COMPOSE_VERSION=${DOCKER_COMPOSE_VERSION}" >> mailcow.conf echo "DOCKER_COMPOSE_VERSION=${DOCKER_COMPOSE_VERSION}" >> mailcow.conf
fi fi
elif [[ ${option} == "MAILCOW_CONTAINER_ENGINE" ]]; then
if ! grep -q ${option} mailcow.conf; then
echo "Adding new option \"${option}\" to mailcow.conf"
echo "# The container engine to use to run this project (docker or podman)." >> mailcow.conf
echo "" >> mailcow.conf
echo "MAILCOW_CONTAINER_ENGINE=${MAILCOW_CONTAINER_ENGINE}" >> mailcow.conf
fi
elif [[ ${option} == "MAILCOW_CONTAINER_SOCKET" ]]; then
if ! grep -q ${option} mailcow.conf; then
echo "Adding new option \"${option}\" to mailcow.conf"
echo "# The location of the container socket to use for volume mounts.." >> mailcow.conf
echo "" >> mailcow.conf
echo "MAILCOW_CONTAINER_SOCKET=${CONTAINER_SOCKET}" >> mailcow.conf
fi
elif [[ ${option} == "DOCKER_COMPOSE_EXTRA_OVERRIDES" ]]; then
if ! grep -q ${option} mailcow.conf; then
echo "Adding new option \"${option}\" to mailcow.conf"
echo "# Additional override files (relative to the repo root) that need to be taken care of when running mailcow scripts." >> mailcow.conf
echo "# Comma separated list without spaces!" >> mailcow.conf
echo "# Example: DOCKER_COMPOSE_EXTRA_OVERRIDES=helper-scripts/docker-compose.override.yml.d/CONTAINER_ENGINE_PODMAN/docker-compose.override.yml,helper-scripts/docker-compose.override.yml.d/CUSTOM_STORAGE_LOCATION/docker-compose.override.yml" >> mailcow.conf
echo "" >> mailcow.conf
echo "DOCKER_COMPOSE_EXTRA_OVERRIDES=" >> mailcow.conf
fi
elif [[ ${option} == "MAILCOW_DOCKER_COMPOSE" ]]; then
if ! grep -q ${option} mailcow.conf; then
echo "Adding new option \"${option}\" to mailcow.conf"
echo "# The name of the docker-compose binary to use. This option can be used in case different versions of" >> mailcow.conf
echo "# docker-compose are installed and another binary than 'docker-compose' (default) needs to be used." >> mailcow.conf
echo "# Example: docker-compose-v2" >> mailcow.conf
echo "" >> mailcow.conf
echo "MAILCOW_DOCKER_COMPOSE=${MAILCOW_DOCKER_COMPOSE:-"docker-compose"}" >> mailcow.conf
fi
elif [[ ${option} == "DOVEADM_PORT" ]]; then elif [[ ${option} == "DOVEADM_PORT" ]]; then
if ! grep -q ${option} mailcow.conf; then if ! grep -q ${option} mailcow.conf; then
echo "Adding new option \"${option}\" to mailcow.conf" echo "Adding new option \"${option}\" to mailcow.conf"
@ -602,6 +619,7 @@ for option in ${CONFIG_ARRAY[@]}; do
fi fi
elif [[ ${option} == "ADDITIONAL_SERVER_NAMES" ]]; then elif [[ ${option} == "ADDITIONAL_SERVER_NAMES" ]]; then
if ! grep -q ${option} mailcow.conf; then if ! grep -q ${option} mailcow.conf; then
echo "Adding new option \"${option}\" to mailcow.conf"
echo '# Additional server names for mailcow UI' >> mailcow.conf echo '# Additional server names for mailcow UI' >> mailcow.conf
echo '#' >> mailcow.conf echo '#' >> mailcow.conf
echo '# Specify alternative addresses for the mailcow UI to respond to' >> mailcow.conf echo '# Specify alternative addresses for the mailcow UI to respond to' >> mailcow.conf
@ -613,6 +631,7 @@ for option in ${CONFIG_ARRAY[@]}; do
fi fi
elif [[ ${option} == "ACME_CONTACT" ]]; then elif [[ ${option} == "ACME_CONTACT" ]]; then
if ! grep -q ${option} mailcow.conf; then if ! grep -q ${option} mailcow.conf; then
echo "Adding new option \"${option}\" to mailcow.conf"
echo '# Lets Encrypt registration contact information' >> mailcow.conf echo '# Lets Encrypt registration contact information' >> mailcow.conf
echo '# Optional: Leave empty for none' >> mailcow.conf echo '# Optional: Leave empty for none' >> mailcow.conf
echo '# This value is only used on first order!' >> mailcow.conf echo '# This value is only used on first order!' >> mailcow.conf
@ -622,16 +641,24 @@ for option in ${CONFIG_ARRAY[@]}; do
fi fi
elif [[ ${option} == "WEBAUTHN_ONLY_TRUSTED_VENDORS" ]]; then elif [[ ${option} == "WEBAUTHN_ONLY_TRUSTED_VENDORS" ]]; then
if ! grep -q ${option} mailcow.conf; then if ! grep -q ${option} mailcow.conf; then
echo "Adding new option \"${option}\" to mailcow.conf"
echo "# WebAuthn device manufacturer verification" >> mailcow.conf echo "# WebAuthn device manufacturer verification" >> mailcow.conf
echo '# After setting WEBAUTHN_ONLY_TRUSTED_VENDORS=y only devices from trusted manufacturers are allowed' >> mailcow.conf echo '# After setting WEBAUTHN_ONLY_TRUSTED_VENDORS=y only devices from trusted manufacturers are allowed' >> mailcow.conf
echo '# root certificates can be placed for validation under mailcow-dockerized/data/web/inc/lib/WebAuthn/rootCertificates' >> mailcow.conf echo '# root certificates can be placed for validation under mailcow-dockerized/data/web/inc/lib/WebAuthn/rootCertificates' >> mailcow.conf
echo 'WEBAUTHN_ONLY_TRUSTED_VENDORS=n' >> mailcow.conf echo 'WEBAUTHN_ONLY_TRUSTED_VENDORS=n' >> mailcow.conf
fi fi
elif [[ ${option} == "WATCHDOG_VERBOSE" ]]; then elif [[ ${option} == "WATCHDOG_VERBOSE" ]]; then
if ! grep -q ${option} mailcow.conf; then if ! grep -q ${option} mailcow.conf; then
echo "Adding new option \"${option}\" to mailcow.conf"
echo '# Enable watchdog verbose logging' >> mailcow.conf echo '# Enable watchdog verbose logging' >> mailcow.conf
echo 'WATCHDOG_VERBOSE=n' >> mailcow.conf echo 'WATCHDOG_VERBOSE=n' >> mailcow.conf
fi fi
elif [[ ${option} == "MAILCOW_STORAGE_DIR" ]]; then
if ! grep -q ${option} mailcow.conf; then
echo "Adding new option \"${option}\" to mailcow.conf"
echo '# The directory used to store the data of the used containers (used in case the CUSTOM_STORAGE_LOCATION override is included)' >> mailcow.conf
echo 'MAILCOW_STORAGE_DIR=' >> mailcow.conf
fi
elif ! grep -q ${option} mailcow.conf; then elif ! grep -q ${option} mailcow.conf; then
echo "Adding new option \"${option}\" to mailcow.conf" echo "Adding new option \"${option}\" to mailcow.conf"
echo "${option}=n" >> mailcow.conf echo "${option}=n" >> mailcow.conf
@ -639,16 +666,16 @@ elif [[ ${option} == "WATCHDOG_VERBOSE" ]]; then
done done
if [[( ${SKIP_PING_CHECK} == "y")]]; then if [[( ${SKIP_PING_CHECK} == "y")]]; then
echo -e "\e[32mSkipping Ping Check...\e[0m" echo -e "\e[32mSkipping Ping Check...\e[0m"
else else
echo -en "Checking internet connection... " echo -en "Checking internet connection... "
if ! check_online_status; then if ! check_online_status; then
echo -e "\e[31mfailed\e[0m" echo -e "\e[31mfailed\e[0m"
exit 1 exit 1
else else
echo -e "\e[32mOK\e[0m" echo -e "\e[32mOK\e[0m"
fi fi
fi fi
if ! [ $NEW_BRANCH ]; then if ! [ $NEW_BRANCH ]; then
@ -679,9 +706,9 @@ elif [ $NEW_BRANCH == "master" ] && [ $CURRENT_BRANCH != "master" ]; then
sleep 1 sleep 1
echo -e "\e[33mBefore you do: Please take a backup of all components to ensure that no Data is lost...\e[0m" echo -e "\e[33mBefore you do: Please take a backup of all components to ensure that no Data is lost...\e[0m"
sleep 1 sleep 1
echo -e "\e[31mWARNING: Please see on GitHub or ask in the communitys if a switch to master is stable or not. echo -e "\e[31mWARNING: Please see on GitHub or ask in the communities if a switch to master is stable or not.
In some rear cases a Update back to master can destroy your mailcow configuration in case of Database Upgrades etc. In some rear cases a Update back to master can destroy your mailcow configuration in case of Database Upgrades etc.
Normally a upgrade back to master should be safe during each full release. Normally a upgrade back to master should be safe during each full release.
Check GitHub for Database Changes and Update only if there similar to the full release!\e[0m" Check GitHub for Database Changes and Update only if there similar to the full release!\e[0m"
read -r -p "Are you sure you that want to continue upgrading to the stable (master) branch? [y/N] " response read -r -p "Are you sure you that want to continue upgrading to the stable (master) branch? [y/N] " response
if [[ ! "${response}" =~ ^([yY][eE][sS]|[yY])+$ ]]; then if [[ ! "${response}" =~ ^([yY][eE][sS]|[yY])+$ ]]; then
@ -744,7 +771,12 @@ if [ ! $FORCE ]; then
echo "OK, exiting." echo "OK, exiting."
exit 0 exit 0
fi fi
fi
if [[ "${MAILCOW_CONTAINER_ENGINE}" == "docker" ]]; then
migrate_docker_nat migrate_docker_nat
else
echo "Skipping migrating docker nat..."
fi fi
remove_obsolete_nginx_ports remove_obsolete_nginx_ports
@ -752,16 +784,20 @@ remove_obsolete_nginx_ports
echo -e "\e[32mValidating docker-compose stack configuration...\e[0m" echo -e "\e[32mValidating docker-compose stack configuration...\e[0m"
sed -i 's/HTTPS_BIND:-:/HTTPS_BIND:-/g' docker-compose.yml sed -i 's/HTTPS_BIND:-:/HTTPS_BIND:-/g' docker-compose.yml
sed -i 's/HTTP_BIND:-:/HTTP_BIND:-/g' docker-compose.yml sed -i 's/HTTP_BIND:-:/HTTP_BIND:-/g' docker-compose.yml
if ! $COMPOSE_COMMAND config -q; then if ! ./mailcow-compose.sh config -q; then
echo -e "\e[31m\nOh no, something went wrong. Please check the error message above.\e[0m" echo -e "\e[31m\nOh no, something went wrong. Please check the error message above.\e[0m"
exit 1 exit 1
fi fi
echo -e "\e[32mChecking for conflicting bridges...\e[0m" if [[ "${MAILCOW_CONTAINER_ENGINE}" == "docker" ]]; then
MAILCOW_BRIDGE=$($COMPOSE_COMMAND config | grep -i com.docker.network.bridge.name | cut -d':' -f2) echo -e "\e[32mChecking for conflicting bridges...\e[0m"
while read NAT_ID; do MAILCOW_BRIDGE=$(./mailcow-compose.sh config | grep -i com.docker.network.bridge.name | cut -d':' -f2)
iptables -t nat -D POSTROUTING $NAT_ID while read NAT_ID; do
done < <(iptables -L -vn -t nat --line-numbers | grep $IPV4_NETWORK | grep -E 'MASQUERADE.*all' | grep -v ${MAILCOW_BRIDGE} | cut -d' ' -f1) 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)
else
echo "Skipping check for conflicting bridges..."
fi
DIFF_DIRECTORY=update_diffs DIFF_DIRECTORY=update_diffs
DIFF_FILE=${DIFF_DIRECTORY}/diff_before_update_$(date +"%Y-%m-%d-%H-%M-%S") DIFF_FILE=${DIFF_DIRECTORY}/diff_before_update_$(date +"%Y-%m-%d-%H-%M-%S")
@ -778,12 +814,13 @@ prefetch_images
echo -e "\e[32mStopping mailcow...\e[0m" echo -e "\e[32mStopping mailcow...\e[0m"
sleep 2 sleep 2
MAILCOW_CONTAINERS=($($COMPOSE_COMMAND ps -q)) MAILCOW_CONTAINERS=($(./mailcow-compose.sh ps -q))
$COMPOSE_COMMAND down ./mailcow-compose.sh down
echo -e "\e[32mChecking for remaining containers...\e[0m" echo -e "\e[32mChecking for remaining containers...\e[0m"
sleep 2 sleep 2
for container in "${MAILCOW_CONTAINERS[@]}"; do for container in "${MAILCOW_CONTAINERS[@]}"; do
docker rm -f "$container" 2> /dev/null ${MAILCOW_CONTAINER_ENGINE} rm -f "$container" 2> /dev/null
done done
[[ -f data/conf/nginx/ZZZ-ejabberd.conf ]] && rm data/conf/nginx/ZZZ-ejabberd.conf [[ -f data/conf/nginx/ZZZ-ejabberd.conf ]] && rm data/conf/nginx/ZZZ-ejabberd.conf
@ -807,7 +844,7 @@ if [[ ${MERGE_RETURN} == 128 ]]; then
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" 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 exit 1
elif [[ ${MERGE_RETURN} == 1 ]]; then elif [[ ${MERGE_RETURN} == 1 ]]; then
echo -e "\e[93mPotenial conflict, trying to fix...\e[0m" echo -e "\e[93mPotential conflict, trying to fix...\e[0m"
git status --porcelain | grep -E "UD|DU" | awk '{print $2}' | xargs rm -v git status --porcelain | grep -E "UD|DU" | awk '{print $2}' | xargs rm -v
git add -A git add -A
git commit -m "After update on ${DATE}" > /dev/null git commit -m "After update on ${DATE}" > /dev/null
@ -816,13 +853,18 @@ elif [[ ${MERGE_RETURN} == 1 ]]; then
elif [[ ${MERGE_RETURN} != 0 ]]; then elif [[ ${MERGE_RETURN} != 0 ]]; then
echo -e "\e[31m\nOh no, something went wrong. Please check the error message above.\e[0m" echo -e "\e[31m\nOh no, something went wrong. Please check the error message above.\e[0m"
echo echo
echo "Run $COMPOSE_COMMAND up -d to restart your stack without updates or try again after fixing the mentioned errors." echo "Run ./mailcow-compose.sh up -d to restart your stack without updates or try again after fixing the mentioned errors."
exit 1 exit 1
fi fi
echo -e "\e[32mFetching new images, if any...\e[0m" echo -e "\e[32mFetching new images, if any...\e[0m"
sleep 2 sleep 2
$COMPOSE_COMMAND pull ./mailcow-compose.sh pull
if [[ "${MAILCOW_CONTAINER_ENGINE}" == "podman" ]]; then
# Apply patches for usage with Podman
bash ./patches-for-podman.sh
fi
# Fix missing SSL, does not overwrite existing files # Fix missing SSL, does not overwrite existing files
[[ ! -d data/assets/ssl ]] && mkdir -p data/assets/ssl [[ ! -d data/assets/ssl ]] && mkdir -p data/assets/ssl
@ -834,7 +876,7 @@ if grep -q 'SYSCTL_IPV6_DISABLED=1' mailcow.conf; then
echo '!! IMPORTANT !!' echo '!! IMPORTANT !!'
echo echo
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".' 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".'
echo 'This setting will only be active after a complete shutdown of mailcow by running $COMPOSE_COMMAND down followed by $COMPOSE_COMMAND up -d".' echo 'This setting will only be active after a complete shutdown of mailcow by running "./mailcow-compose.sh down" followed by "./mailcow-compose.sh up -d".'
echo echo
echo '!! IMPORTANT !!' echo '!! IMPORTANT !!'
echo echo
@ -872,8 +914,8 @@ else
mailcow_last_git_version="" mailcow_last_git_version=""
fi fi
mailcow_git_commit=$(git rev-parse origin/${BRANCH}) mailcow_git_commit=$(git rev-parse HEAD)
mailcow_git_commit_date=$(git log -1 --format=%ci @{upstream} ) mailcow_git_commit_date=$(git log -1 --format=%ci HEAD )
if [ $? -eq 0 ]; then if [ $? -eq 0 ]; then
echo '<?php' > data/web/inc/app_info.inc.php echo '<?php' > data/web/inc/app_info.inc.php
@ -906,11 +948,11 @@ fi
sed -i 's/^DOCKER_COMPOSE_VERSION=$/DOCKER_COMPOSE_VERSION='$DOCKER_COMPOSE_VERSION'/g' mailcow.conf sed -i 's/^DOCKER_COMPOSE_VERSION=$/DOCKER_COMPOSE_VERSION='$DOCKER_COMPOSE_VERSION'/g' mailcow.conf
if [[ ${SKIP_START} == "y" ]]; then if [[ ${SKIP_START} == "y" ]]; then
echo -e "\e[33mNot starting mailcow, please run \"$COMPOSE_COMMAND up -d --remove-orphans\" to start mailcow.\e[0m" echo -e "\e[33mNot starting mailcow, please run \"./mailcow-compose.sh up -d --remove-orphans\" to start mailcow.\e[0m"
else else
echo -e "\e[32mStarting mailcow...\e[0m" echo -e "\e[32mStarting mailcow...\e[0m"
sleep 2 sleep 2
$COMPOSE_COMMAND up -d --remove-orphans ./mailcow-compose.sh up -d --remove-orphans
fi fi
echo -e "\e[32mCollecting garbage...\e[0m" echo -e "\e[32mCollecting garbage...\e[0m"
@ -925,4 +967,4 @@ fi
# echo # echo
# git reflog --color=always | grep "Before update on " # git reflog --color=always | grep "Before update on "
# echo # echo
# echo "Use \"git reset --hard hash-on-the-left\" and run $COMPOSE_COMMAND up -d afterwards." # echo "Use \"git reset --hard hash-on-the-left\" and run ./mailcow-compose.sh up -d afterwards."