From a5eb7a1046d1b08411d37b11f5681c4ef61cf265 Mon Sep 17 00:00:00 2001 From: Roy Lenferink Date: Sun, 8 Jan 2023 11:55:48 +0100 Subject: [PATCH 01/19] Disable security labels within the container on rootless SELinux enabled hosts --- docker-compose.yml | 136 ++++++++++++++++++++++++++++----------------- 1 file changed, 84 insertions(+), 52 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index b940b336..c0b7401a 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -6,8 +6,10 @@ services: environment: - TZ=${TZ} volumes: - - ./data/hooks/unbound:/hooks:Z - - ./data/conf/unbound/unbound.conf:/etc/unbound/unbound.conf:ro,Z + - ./data/hooks/unbound:/hooks + - ./data/conf/unbound/unbound.conf:/etc/unbound/unbound.conf:ro + security_opt: + - label=disable restart: always tty: true networks: @@ -24,7 +26,9 @@ services: volumes: - mysql-vol-1:/var/lib/mysql/ - 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: - TZ=${TZ} - MYSQL_ROOT_PASSWORD=${DBROOT} @@ -44,6 +48,8 @@ services: image: redis:7-alpine volumes: - redis-vol-1:/data/ + security_opt: + - label=disable restart: always ports: - "${REDIS_PORT:-127.0.0.1:7654}:6379" @@ -68,8 +74,10 @@ services: - TZ=${TZ} - SKIP_CLAMD=${SKIP_CLAMD:-n} volumes: - - ./data/conf/clamav/:/etc/clamav/:Z + - ./data/conf/clamav/:/etc/clamav/ - clamd-db-vol-1:/var/lib/clamav + security_opt: + - label=disable networks: mailcow-network: aliases: @@ -87,15 +95,17 @@ services: - REDIS_SLAVEOF_IP=${REDIS_SLAVEOF_IP:-} - REDIS_SLAVEOF_PORT=${REDIS_SLAVEOF_PORT:-} volumes: - - ./data/hooks/rspamd:/hooks:Z - - ./data/conf/rspamd/custom/:/etc/rspamd/custom:z - - ./data/conf/rspamd/override.d/:/etc/rspamd/override.d:Z - - ./data/conf/rspamd/local.d/:/etc/rspamd/local.d:Z - - ./data/conf/rspamd/plugins.d/:/etc/rspamd/plugins.d:Z - - ./data/conf/rspamd/lua/:/etc/rspamd/lua/:ro,Z - - ./data/conf/rspamd/rspamd.conf.local:/etc/rspamd/rspamd.conf.local:Z - - ./data/conf/rspamd/rspamd.conf.override:/etc/rspamd/rspamd.conf.override:Z + - ./data/hooks/rspamd:/hooks + - ./data/conf/rspamd/custom/:/etc/rspamd/custom + - ./data/conf/rspamd/override.d/:/etc/rspamd/override.d + - ./data/conf/rspamd/local.d/:/etc/rspamd/local.d + - ./data/conf/rspamd/plugins.d/:/etc/rspamd/plugins.d + - ./data/conf/rspamd/lua/:/etc/rspamd/lua/:ro + - ./data/conf/rspamd/rspamd.conf.local:/etc/rspamd/rspamd.conf.local + - ./data/conf/rspamd/rspamd.conf.override:/etc/rspamd/rspamd.conf.override - rspamd-vol-1:/var/lib/rspamd + security_opt: + - label=disable restart: always hostname: rspamd dns: @@ -111,23 +121,25 @@ services: depends_on: - redis-mailcow volumes: - - ./data/hooks/phpfpm:/hooks:Z - - ./data/web:/web:z - - ./data/conf/rspamd/dynmaps:/dynmaps:ro,z - - ./data/conf/rspamd/custom/:/rspamd_custom_maps:z + - ./data/hooks/phpfpm:/hooks + - ./data/web:/web + - ./data/conf/rspamd/dynmaps:/dynmaps:ro + - ./data/conf/rspamd/custom/:/rspamd_custom_maps - rspamd-vol-1:/var/lib/rspamd - mysql-socket-vol-1:/var/run/mysqld/ - - ./data/conf/sogo/:/etc/sogo/:z - - ./data/conf/rspamd/meta_exporter:/meta_exporter:ro,z - - ./data/conf/phpfpm/sogo-sso/:/etc/sogo-sso/:z - - ./data/conf/phpfpm/php-fpm.d/pools.conf:/usr/local/etc/php-fpm.d/z-pools.conf:Z - - ./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/upload.ini:/usr/local/etc/php/conf.d/upload.ini:Z - - ./data/conf/phpfpm/php-conf.d/other.ini:/usr/local/etc/php/conf.d/zzz-other.ini:Z - - ./data/conf/dovecot/global_sieve_before:/global_sieve/before:z - - ./data/conf/dovecot/global_sieve_after:/global_sieve/after:z - - ./data/assets/templates:/tpls:z - - ./data/conf/nginx/:/etc/nginx/conf.d/:z + - ./data/conf/sogo/:/etc/sogo/ + - ./data/conf/rspamd/meta_exporter:/meta_exporter:ro + - ./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 + - ./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 + - ./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 + - ./data/conf/dovecot/global_sieve_after:/global_sieve/after + - ./data/assets/templates:/tpls + - ./data/conf/nginx/:/etc/nginx/conf.d/ + security_opt: + - label=disable dns: - ${IPV4_NETWORK:-172.22.1}.254 environment: @@ -189,15 +201,17 @@ services: dns: - ${IPV4_NETWORK:-172.22.1}.254 volumes: - - ./data/hooks/sogo:/hooks:Z - - ./data/conf/sogo/:/etc/sogo/:z - - ./data/web/inc/init_db.inc.php:/init_db.inc.php:Z - - ./data/conf/sogo/custom-favicon.ico:/usr/lib/GNUstep/SOGo/WebServerResources/img/sogo.ico:z - - ./data/conf/sogo/custom-theme.js:/usr/lib/GNUstep/SOGo/WebServerResources/js/theme.js:z - - ./data/conf/sogo/custom-sogo.js:/usr/lib/GNUstep/SOGo/WebServerResources/js/custom-sogo.js:z + - ./data/hooks/sogo:/hooks + - ./data/conf/sogo/:/etc/sogo/ + - ./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 + - ./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 - mysql-socket-vol-1:/var/run/mysqld/ - sogo-web-vol-1:/sogo_web - sogo-userdata-backup-vol-1:/sogo_backup + security_opt: + - label=disable labels: ofelia.enabled: "true" ofelia.job-exec.sogo_sessions.schedule: "@every 1m" @@ -224,18 +238,20 @@ services: cap_add: - NET_BIND_SERVICE volumes: - - ./data/hooks/dovecot:/hooks:Z - - ./data/conf/dovecot:/etc/dovecot:z - - ./data/assets/ssl:/etc/ssl/mail/:ro,z - - ./data/conf/sogo/:/etc/sogo/:z - - ./data/conf/phpfpm/sogo-sso/:/etc/phpfpm/:z + - ./data/hooks/dovecot:/hooks + - ./data/conf/dovecot:/etc/dovecot + - ./data/assets/ssl:/etc/ssl/mail/:ro + - ./data/conf/sogo/:/etc/sogo/ + - ./data/conf/phpfpm/sogo-sso/:/etc/phpfpm/ - vmail-vol-1:/var/vmail - vmail-index-vol-1:/var/vmail_index - crypt-vol-1:/mail_crypt/ - - ./data/conf/rspamd/custom/:/etc/rspamd/custom:z - - ./data/assets/templates:/templates:z + - ./data/conf/rspamd/custom/:/etc/rspamd/custom + - ./data/assets/templates:/templates - rspamd-vol-1:/var/lib/rspamd - mysql-socket-vol-1:/var/run/mysqld/ + security_opt: + - label=disable environment: - DOVECOT_MASTER_USER=${DOVECOT_MASTER_USER:-} - DOVECOT_MASTER_PASS=${DOVECOT_MASTER_PASS:-} @@ -300,13 +316,15 @@ services: depends_on: - mysql-mailcow volumes: - - ./data/hooks/postfix:/hooks:Z - - ./data/conf/postfix:/opt/postfix/conf:z - - ./data/assets/ssl:/etc/ssl/mail/:ro,z + - ./data/hooks/postfix:/hooks + - ./data/conf/postfix:/opt/postfix/conf + - ./data/assets/ssl:/etc/ssl/mail/:ro - postfix-vol-1:/var/spool/postfix - crypt-vol-1:/var/lib/zeyple - rspamd-vol-1:/var/lib/rspamd - mysql-socket-vol-1:/var/run/mysqld/ + security_opt: + - label=disable environment: - LOG_LINES=${LOG_LINES:-9999} - TZ=${TZ} @@ -334,6 +352,8 @@ services: memcached-mailcow: image: memcached:alpine restart: always + security_opt: + - label=disable environment: - TZ=${TZ} networks: @@ -371,12 +391,14 @@ services: - ALLOW_ADMIN_EMAIL_LOGIN=${ALLOW_ADMIN_EMAIL_LOGIN:-n} - ADDITIONAL_SERVER_NAMES=${ADDITIONAL_SERVER_NAMES:-} volumes: - - ./data/web:/web:ro,z - - ./data/conf/rspamd/dynmaps:/dynmaps:ro,z - - ./data/assets/ssl/:/etc/ssl/mail/:ro,z - - ./data/conf/nginx/:/etc/nginx/conf.d/:z - - ./data/conf/rspamd/meta_exporter:/meta_exporter:ro,z + - ./data/web:/web:ro + - ./data/conf/rspamd/dynmaps:/dynmaps:ro + - ./data/assets/ssl/:/etc/ssl/mail/:ro + - ./data/conf/nginx/:/etc/nginx/conf.d/ + - ./data/conf/rspamd/meta_exporter:/meta_exporter:ro - sogo-web-vol-1:/usr/lib/GNUstep/SOGo/ + security_opt: + - label=disable ports: - "${HTTPS_BIND:-}:${HTTPS_PORT:-443}:${HTTPS_PORT:-443}" - "${HTTP_BIND:-}:${HTTP_PORT:-80}:${HTTP_PORT:-80}" @@ -414,10 +436,12 @@ services: - SNAT_TO_SOURCE=${SNAT_TO_SOURCE:-n} - SNAT6_TO_SOURCE=${SNAT6_TO_SOURCE:-n} volumes: - - ./data/web/.well-known/acme-challenge:/var/www/acme:z - - ./data/assets/ssl:/var/lib/acme/:z - - ./data/assets/ssl-example:/var/lib/ssl-example/:ro,Z + - ./data/web/.well-known/acme-challenge:/var/www/acme + - ./data/assets/ssl:/var/lib/acme/ + - ./data/assets/ssl-example:/var/lib/ssl-example/:ro - mysql-socket-vol-1:/var/run/mysqld/ + security_opt: + - label=disable restart: always networks: mailcow-network: @@ -446,6 +470,8 @@ services: network_mode: "host" volumes: - /lib/modules:/lib/modules:ro + security_opt: + - label=disable watchdog-mailcow: image: mailcow/watchdog:1.97 @@ -457,7 +483,9 @@ services: - rspamd-vol-1:/var/lib/rspamd - mysql-socket-vol-1:/var/run/mysqld/ - 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 environment: - IPV6_NETWORK=${IPV6_NETWORK:-fd4d:6169:6c63:6f77::/64} @@ -534,6 +562,8 @@ services: restart: always volumes: - solr-vol-1:/opt/solr/server/solr/dovecot-fts/data + security_opt: + - label=disable ports: - "${SOLR_PORT:-127.0.0.1:18983}:8983" environment: @@ -548,6 +578,8 @@ services: olefy-mailcow: image: mailcow/olefy:1.11 restart: always + security_opt: + - label=disable environment: - TZ=${TZ} - OLEFY_BINDADDRESS=0.0.0.0 From f8ab350a5291e39dab788d94d0d60c0e9f69c56f Mon Sep 17 00:00:00 2001 From: Roy Lenferink Date: Sun, 8 Jan 2023 12:55:32 +0100 Subject: [PATCH 02/19] Do not exclude example/helper docker-compose override files --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 5782cad9..69ed15fe 100644 --- a/.gitignore +++ b/.gitignore @@ -60,6 +60,7 @@ data/web/inc/app_info.inc.php data/web/nextcloud*/ data/web/rc*/ docker-compose.override.yml +!helper-scripts/docker-compose.override.yml.d/**/docker-compose.override.yml mailcow.conf mailcow.conf_backup rebuild-images.sh From d4965e386d31a467871292ca779887f9aadfd1a2 Mon Sep 17 00:00:00 2001 From: Roy Lenferink Date: Sun, 8 Jan 2023 13:00:19 +0100 Subject: [PATCH 03/19] Add example override file for specifying a custom storage location --- .../docker-compose.override.yml | 66 +++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 helper-scripts/docker-compose.override.yml.d/CUSTOM_STORAGE_LOCATION/docker-compose.override.yml diff --git a/helper-scripts/docker-compose.override.yml.d/CUSTOM_STORAGE_LOCATION/docker-compose.override.yml b/helper-scripts/docker-compose.override.yml.d/CUSTOM_STORAGE_LOCATION/docker-compose.override.yml new file mode 100644 index 00000000..b173fa80 --- /dev/null +++ b/helper-scripts/docker-compose.override.yml.d/CUSTOM_STORAGE_LOCATION/docker-compose.override.yml @@ -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: {} From 399e831ce3dfe707828223b1dadee7d8836890c3 Mon Sep 17 00:00:00 2001 From: Roy Lenferink Date: Sun, 8 Jan 2023 18:16:43 +0100 Subject: [PATCH 04/19] Add override file for running mailcow with podman --- .../docker-compose.override.yml | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 helper-scripts/docker-compose.override.yml.d/CONTAINER_ENGINE_PODMAN/docker-compose.override.yml diff --git a/helper-scripts/docker-compose.override.yml.d/CONTAINER_ENGINE_PODMAN/docker-compose.override.yml b/helper-scripts/docker-compose.override.yml.d/CONTAINER_ENGINE_PODMAN/docker-compose.override.yml new file mode 100644 index 00000000..89fdf079 --- /dev/null +++ b/helper-scripts/docker-compose.override.yml.d/CONTAINER_ENGINE_PODMAN/docker-compose.override.yml @@ -0,0 +1,38 @@ +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: + + 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 From 13496998e6df1ddb5b6d8dd28c17a87eea4d6fe0 Mon Sep 17 00:00:00 2001 From: Roy Lenferink Date: Mon, 9 Jan 2023 14:36:40 +0100 Subject: [PATCH 05/19] Update generate_config.sh to support Podman --- .gitignore | 1 + generate_config.sh | 108 ++++++++++++++++------ patch-docker-compose-for-podman.patch | 125 ++++++++++++++++++++++++++ patch-docker-compose-for-podman.sh | 20 +++++ 4 files changed, 228 insertions(+), 26 deletions(-) create mode 100644 patch-docker-compose-for-podman.patch create mode 100755 patch-docker-compose-for-podman.sh diff --git a/.gitignore b/.gitignore index 69ed15fe..7d1c7c3e 100644 --- a/.gitignore +++ b/.gitignore @@ -59,6 +59,7 @@ data/web/inc/vars.local.inc.php data/web/inc/app_info.inc.php data/web/nextcloud*/ data/web/rc*/ +docker-compose.yml**.bak docker-compose.override.yml !helper-scripts/docker-compose.override.yml.d/**/docker-compose.override.yml mailcow.conf diff --git a/generate_config.sh b/generate_config.sh index 6b3ad711..702c2540 100755 --- a/generate_config.sh +++ b/generate_config.sh @@ -21,38 +21,61 @@ 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 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. +# 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" + + if [[ -n "${DOCKER_HOST}" ]] && [[ "${DOCKER_HOST}" == "unix://"* ]]; then + CONTAINER_SOCKET="${DOCKER_HOST/"unix://"/}" + else + CONTAINER_SOCKET="/run/user/${UID}/podman/podman.sock" + fi +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" +else + echo "Cannot find container engine (Docker or Podman), exiting..." + exit 1 +fi + +for bin in openssl curl git awk sha1sum; do if [[ -z $(which ${bin}) ]]; then echo "Cannot find ${bin}, exiting..."; exit 1; fi done -if command -v docker compose > /dev/null 2>&1; then +MAILCOW_DOCKER_COMPOSE=${MAILCOW_DOCKER_COMPOSE:-"docker-compose"} + +if [[ "${CONTAINER_ENGINE}" == "docker" ]] && command -v docker compose > /dev/null 2>&1; then version=$(docker compose version --short) if [[ $version =~ ^2\.([0-9]+)\.([0-9]+) ]]; then COMPOSE_VERSION=native 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" + 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[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" exit 1 fi -elif command -v docker-compose > /dev/null 2>&1; then - version=$(docker-compose version --short) +elif command -v $MAILCOW_DOCKER_COMPOSE > /dev/null 2>&1; then + version=$($MAILCOW_DOCKER_COMPOSE version --short) if [[ $version =~ ^2\.([0-9]+)\.([0-9]+) ]]; then COMPOSE_VERSION=standalone 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" + 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 - 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" exit 1 fi 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 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 @@ -172,7 +195,7 @@ else echo -e "\033[31mCould not determine branch input..." echo -e "\033[31mExiting." exit 1 -fi +fi if [ ! -z "${MAILCOW_BRANCH}" ]; then git_branch=${MAILCOW_BRANCH} @@ -180,6 +203,17 @@ fi [ ! -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 + MAILCOW_HTTP_BIND="127.0.0.1" + MAILCOW_HTTPS_BIND="127.0.0.1" + + # Patch the docker-compose.yml for usage with Podman + bash ./patch-docker-compose-for-podman.sh +else + MAILCOW_HTTP_BIND="" + MAILCOW_HTTPS_BIND="" +fi + cat << EOF > mailcow.conf # ------------------------------ # mailcow web ui configuration @@ -195,6 +229,9 @@ MAILCOW_HOSTNAME=${MAILCOW_HOSTNAME} # see https://mailcow.github.io/mailcow-dockerized-docs/models/model-passwd/ MAILCOW_PASS_SCHEME=BLF-CRYPT +# The directory used to store the data of the used containers +MAILCOW_STORAGE_DIR= + # ------------------------------ # SQL database configuration # ------------------------------ @@ -221,10 +258,42 @@ DBROOT=$(LC_ALL=C /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} diff --git a/patch-docker-compose-for-podman.sh b/patch-docker-compose-for-podman.sh new file mode 100755 index 00000000..70236a2e --- /dev/null +++ b/patch-docker-compose-for-podman.sh @@ -0,0 +1,20 @@ +#!/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 + +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 "Patch file already applied or custom changes prevent applying the patch" +fi From acee85f5b9ac2540a1be8d17033dc8e2717b9c88 Mon Sep 17 00:00:00 2001 From: Roy Lenferink Date: Mon, 9 Jan 2023 14:52:21 +0100 Subject: [PATCH 06/19] Re-order my.cnf --- data/conf/mysql/my.cnf | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/data/conf/mysql/my.cnf b/data/conf/mysql/my.cnf index b4c34886..ccc9fcab 100644 --- a/data/conf/mysql/my.cnf +++ b/data/conf/mysql/my.cnf @@ -1,3 +1,9 @@ +[client] +default-character-set = utf8mb4 + +[mysql] +default-character-set = utf8mb4 + [mysqld] character-set-client-handshake = FALSE character-set-server = utf8mb4 @@ -27,9 +33,3 @@ log-warnings = 0 event_scheduler = 1 interactive_timeout = 3610 wait_timeout = 3610 - -[client] -default-character-set = utf8mb4 - -[mysql] -default-character-set = utf8mb4 From 2863ecfdcfa420a29fef873db8befcd9051be015 Mon Sep 17 00:00:00 2001 From: Roy Lenferink Date: Mon, 9 Jan 2023 16:05:51 +0100 Subject: [PATCH 07/19] Add patching of my.cnf for Podman usage --- generate_config.sh | 4 ++-- ...r-compose-for-podman.sh => patches-for-podman.sh | 13 ++++++++++++- 2 files changed, 14 insertions(+), 3 deletions(-) rename patch-docker-compose-for-podman.sh => patches-for-podman.sh (59%) diff --git a/generate_config.sh b/generate_config.sh index 702c2540..2450bf80 100755 --- a/generate_config.sh +++ b/generate_config.sh @@ -207,8 +207,8 @@ if [[ "${CONTAINER_ENGINE}" == "podman" ]]; then MAILCOW_HTTP_BIND="127.0.0.1" MAILCOW_HTTPS_BIND="127.0.0.1" - # Patch the docker-compose.yml for usage with Podman - bash ./patch-docker-compose-for-podman.sh + # Apply patches for usage with Podman + bash ./patches-for-podman.sh else MAILCOW_HTTP_BIND="" MAILCOW_HTTPS_BIND="" diff --git a/patch-docker-compose-for-podman.sh b/patches-for-podman.sh similarity index 59% rename from patch-docker-compose-for-podman.sh rename to patches-for-podman.sh index 70236a2e..711e470a 100755 --- a/patch-docker-compose-for-podman.sh +++ b/patches-for-podman.sh @@ -3,6 +3,8 @@ # 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 @@ -16,5 +18,14 @@ cp docker-compose.yml docker-compose.yml.${TIMESTAMP}.bak 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 "Patch file already applied or custom changes prevent applying the patch" + echo "docker-compose.yml already patched (or custom changes prevent applying the patch)" +fi + +# Patch the MySQL configuration file +MYCNF_PATH="data/conf/mysql/my.cnf" +if ! grep "bind_address" ${MYCNF_PATH} > /dev/null 2>&1; then + echo "patching file my.cnf" + echo "bind_address = 0.0.0.0" >> ${MYCNF_PATH} +else + echo "my.cnf already patched" fi From 62c3fc075b34baa0929463acae54ff956414d30a Mon Sep 17 00:00:00 2001 From: Roy Lenferink Date: Mon, 9 Jan 2023 16:26:04 +0100 Subject: [PATCH 08/19] Update reset-admin script for usage with Docker and Podman --- helper-scripts/mailcow-reset-admin.sh | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/helper-scripts/mailcow-reset-admin.sh b/helper-scripts/mailcow-reset-admin.sh index ee95d3e9..0b0186ec 100755 --- a/helper-scripts/mailcow-reset-admin.sh +++ b/helper-scripts/mailcow-reset-admin.sh @@ -7,8 +7,10 @@ if [[ -z ${DBUSER} ]] || [[ -z ${DBPASS} ]] || [[ -z ${DBNAME} ]]; then exit 1 fi +_engine="${MAILCOW_CONTAINER_ENGINE}" + 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 "MySQL (mysql-mailcow) is not up and running, exiting..." exit 1 @@ -20,11 +22,11 @@ response=${response,,} # tolower if [[ "$response" =~ ^(yes|y)$ ]]; then echo -e "\nWorking, please wait..." random=$( Date: Mon, 9 Jan 2023 16:30:17 +0100 Subject: [PATCH 09/19] Update reset-learns script for usage with Docker and Podman --- helper-scripts/reset-learns.sh | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/helper-scripts/reset-learns.sh b/helper-scripts/reset-learns.sh index 9fd11232..989eaba8 100755 --- a/helper-scripts/reset-learns.sh +++ b/helper-scripts/reset-learns.sh @@ -1,30 +1,34 @@ #!/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 response=${response,,} # tolower if [[ "$response" =~ ^(yes|y)$ ]]; then + _engine="${MAILCOW_CONTAINER_ENGINE}" + echo "Working, please wait..." - REDIS_ID=$(docker ps -qf name=redis-mailcow) - RSPAMD_ID=$(docker ps -qf name=rspamd-mailcow) + REDIS_ID=$(${_engine} ps -qf name=redis-mailcow) + RSPAMD_ID=$(${_engine} ps -qf name=rspamd-mailcow) if [ -z ${REDIS_ID} ] || [ -z ${RSPAMD_ID} ]; then echo "Cannot determine Redis or Rspamd container ID" exit 1 else 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 "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" - 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" - 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" - 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" - 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" - docker start ${RSPAMD_ID} + ${_engine} start ${RSPAMD_ID} fi fi From d10ec0286973412704482ffbc3d2621a7d20bede Mon Sep 17 00:00:00 2001 From: Roy Lenferink Date: Mon, 9 Jan 2023 17:03:38 +0100 Subject: [PATCH 10/19] Update update_compose script to support a custom docker-compose name Also fixed indentation issues --- helper-scripts/update_compose.sh | 73 ++++++++++++++++++-------------- 1 file changed, 41 insertions(+), 32 deletions(-) diff --git a/helper-scripts/update_compose.sh b/helper-scripts/update_compose.sh index ae2d6ab1..47cc061d 100755 --- a/helper-scripts/update_compose.sh +++ b/helper-scripts/update_compose.sh @@ -4,56 +4,65 @@ SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" source ${SCRIPT_DIR}/../mailcow.conf 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 -LATEST_COMPOSE=${LATEST_COMPOSE##*/v} #get the latest version from the redirect, excluding the "v" prefix -COMPOSE_VERSION=$(docker-compose version --short) -if [[ "$LATEST_COMPOSE" != "$COMPOSE_VERSION" ]]; then - echo -e "\e[33mA new docker-compose Version is available: $LATEST_COMPOSE\e[0m" - echo -e "\e[33mYour Version is: $COMPOSE_VERSION\e[0m" -else - echo -e "\e[32mYour docker-compose Version is up to date! Not updating it...\e[0m" - 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 + _compose="${MAILCOW_DOCKER_COMPOSE:-"docker-compose"}" + + 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##*/v} #get the latest version from the redirect, excluding the "v" prefix + COMPOSE_VERSION=$(${_compose} version --short) + if [[ "$LATEST_COMPOSE" != "$COMPOSE_VERSION" ]]; then + echo -e "\e[33mA new docker-compose Version is available: $LATEST_COMPOSE\e[0m" + echo -e "\e[33mYour Version of '${_compose}' is: $COMPOSE_VERSION\e[0m" + else + echo -e "\e[32mYour docker-compose Version is up to date! Not updating it...\e[0m" + 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 - echo "OK, not updating docker-compose." - exit 0 - fi -echo -e "\e[32mFetching new docker-compose (standalone) version...\e[0m" -echo -e "\e[32mTrying to determine GLIBC version...\e[0m" + echo "OK, not updating docker-compose." + exit 0 + fi + echo -e "\e[32mFetching new docker-compose (standalone) version...\e[0m" + echo -e "\e[32mTrying to determine GLIBC version...\e[0m" if ldd --version > /dev/null; then 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 - DC_DL_SUFFIX= + DC_DL_SUFFIX= else - DC_DL_SUFFIX=legacy + DC_DL_SUFFIX=legacy fi else DC_DL_SUFFIX=legacy fi 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[31mPlease uninstall the pip Version of docker-compose since it doesn't support Versions higher than 1.29.2.\e[0m" sleep 2 echo -e "\e[33mExiting...\e[0m" exit 1 #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 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 - COMPOSE_VERSION=$(docker-compose version --short) + LATEST_COMPOSE=${LATEST_COMPOSE##*/} #get the latest version from the redirect, including the "v" prefix + COMPOSE_VERSION=$(${_compose} version --short) if [[ "$LATEST_COMPOSE" != "$COMPOSE_VERSION" ]]; then - COMPOSE_PATH=$(command -v docker-compose) - if [[ -w ${COMPOSE_PATH} ]]; then - curl -#L https://github.com/docker/compose/releases/download/${LATEST_COMPOSE}/docker-compose-$(uname -s)-$(uname -m) > $COMPOSE_PATH - chmod +x $COMPOSE_PATH - echo -e "\e[32mYour Docker Compose (standalone) has been updated to: $LATEST_COMPOSE\e[0m" - exit 0 - 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 + COMPOSE_PATH=$(command -v ${_compose}) + if [[ -w ${COMPOSE_PATH} ]]; then + curl -#L https://github.com/docker/compose/releases/download/${LATEST_COMPOSE}/docker-compose-$(uname -s)-$(uname -m) > $COMPOSE_PATH + RC=$? + if [[ $RC -eq 0 ]]; then + chmod +x $COMPOSE_PATH + echo -e "\e[32mYour Docker Compose (standalone) has been updated to: $LATEST_COMPOSE\e[0m" + exit 0 + else + 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 else echo -e "\e[33mCannot determine latest docker-compose version, skipping...\e[0m" @@ -69,4 +78,4 @@ elif [ "${DOCKER_COMPOSE_VERSION}" == "native" ]; then else echo -e "\e[31mCan not read DOCKER_COMPOSE_VERSION variable from mailcow.conf! Is your mailcow up to date? Exiting...\e[0m" exit 1 -fi \ No newline at end of file +fi From 580e9390657e82baa0a31e5d5cdd755a421f024c Mon Sep 17 00:00:00 2001 From: Roy Lenferink Date: Mon, 9 Jan 2023 19:41:25 +0100 Subject: [PATCH 11/19] Add mailcow.sh script for easier starting and stopping of mailcow This prevents extreme long docker-compose commands --- generate_config.sh | 6 ++++ mailcow-compose.sh | 89 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 95 insertions(+) create mode 100755 mailcow-compose.sh diff --git a/generate_config.sh b/generate_config.sh index 2450bf80..c46e11c5 100755 --- a/generate_config.sh +++ b/generate_config.sh @@ -288,6 +288,12 @@ COMPOSE_PROJECT_NAME=mailcowdockerized 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 both # docker-compose v1 and docker-compose v2 need to be installed. # Default: docker-compose diff --git a/mailcow-compose.sh b/mailcow-compose.sh new file mode 100755 index 00000000..0afde8e9 --- /dev/null +++ b/mailcow-compose.sh @@ -0,0 +1,89 @@ +#!/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 +} + +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 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 +run_compose $@ From 17094f14b78d4cae7430ed224a01b63823d9e825 Mon Sep 17 00:00:00 2001 From: Roy Lenferink Date: Tue, 10 Jan 2023 16:52:52 +0100 Subject: [PATCH 12/19] Update update.sh for usage with podman & ensure support for new variables is added --- generate_config.sh | 12 +- mailcow-compose.sh | 32 +++--- update.sh | 277 +++++++++++++++++++++++++-------------------- 3 files changed, 179 insertions(+), 142 deletions(-) diff --git a/generate_config.sh b/generate_config.sh index c46e11c5..d2d3e98e 100755 --- a/generate_config.sh +++ b/generate_config.sh @@ -43,7 +43,10 @@ else fi for bin in openssl curl git awk sha1sum; do - if [[ -z $(which ${bin}) ]]; then echo "Cannot find ${bin}, exiting..."; exit 1; fi + if [[ -z $(which ${bin}) ]]; then + echo "Cannot find ${bin}, exiting..." + exit 1 + fi done MAILCOW_DOCKER_COMPOSE=${MAILCOW_DOCKER_COMPOSE:-"docker-compose"} @@ -229,7 +232,7 @@ MAILCOW_HOSTNAME=${MAILCOW_HOSTNAME} # see https://mailcow.github.io/mailcow-dockerized-docs/models/model-passwd/ MAILCOW_PASS_SCHEME=BLF-CRYPT -# The directory used to store the data of the used containers +# The directory used to store the data of the used containers (used in case the CUSTOM_STORAGE_LOCATION override is included) MAILCOW_STORAGE_DIR= # ------------------------------ @@ -294,9 +297,8 @@ DOCKER_COMPOSE_VERSION=${COMPOSE_VERSION} DOCKER_COMPOSE_EXTRA_OVERRIDES= -# The name of the docker-compose binary to use. This option can be used in case both -# docker-compose v1 and docker-compose v2 need to be installed. -# Default: docker-compose +# 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} diff --git a/mailcow-compose.sh b/mailcow-compose.sh index 0afde8e9..5f458bc0 100755 --- a/mailcow-compose.sh +++ b/mailcow-compose.sh @@ -22,8 +22,9 @@ function validate_input() 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 + if command -v docker compose > /dev/null 2>&1; then + version=$(docker compose version --short) + if [[ $version =~ ^2\.([0-9]+)\.([0-9]+) ]]; then DOCKER_COMPOSE_VERSION=native COMPOSE_COMMAND="docker compose" echo -e "\e[31mFound Docker Compose Plugin (native).\e[0m" @@ -35,20 +36,19 @@ detect_docker_compose_command(){ 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 + elif command -v docker-compose > /dev/null 2>&1; then + version=$(docker-compose version --short) + if [[ $version =~ ^2\.([0-9]+)\.([0-9]+) ]]; 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 else diff --git a/update.sh b/update.sh index db6be252..e4940c09 100755 --- a/update.sh +++ b/update.sh @@ -22,7 +22,7 @@ prefetch_images() { fi fi RET_C=0 - until docker pull ${image}; do + until ${MAILCOW_CONTAINER_ENGINE} pull ${image}; do RET_C=$((RET_C + 1)) echo -e "\e[33m\nError pulling $image, retrying...\e[0m" [ ${RET_C} -gt 3 ] && { echo -e "\e[31m\nToo many failed retries, exiting\e[0m"; exit 1; } @@ -38,7 +38,7 @@ docker_garbage() { TAG=${container/*:} V_MAIN=${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 V_MAIN_EXISTING=${existing_tag/*.} V_SUB_EXISTING=${existing_tag/*.} @@ -62,21 +62,21 @@ docker_garbage() { if [[ ! -z ${IMGS_TO_DELETE[*]} ]]; then echo "Run the following command to delete unused image tags:" echo - echo " docker rmi ${IMGS_TO_DELETE[*]}" + echo " ${MAILCOW_CONTAINER_ENGINE} rmi ${IMGS_TO_DELETE[*]}" echo if [ ! $FORCE ]; then read -r -p "Do you want to delete old image tags right now? [y/N] " response if [[ "$response" =~ ^([yY][eE][sS]|[yY])+$ ]]; then - docker rmi ${IMGS_TO_DELETE[*]} + ${MAILCOW_CONTAINER_ENGINE} rmi ${IMGS_TO_DELETE[*]} else echo "OK, skipped." fi else echo "Running image removal without extra confirmation due to force mode." - docker rmi ${IMGS_TO_DELETE[*]} + ${MAILCOW_CONTAINER_ENGINE} rmi ${IMGS_TO_DELETE[*]} fi echo -e "\e[32mFurther cleanup...\e[0m" - echo "If you want to cleanup further garbage collected by Docker, please make sure all containers are up and running before cleaning your system by executing \"docker system prune\"" + 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 } @@ -139,10 +139,10 @@ migrate_docker_nat() { # Removing legacy container sed -i '/ipv6nat-mailcow:$/,/^$/d' docker-compose.yml if [ -s docker-compose.override.yml ]; then - sed -i '/ipv6nat-mailcow:$/,/^$/d' docker-compose.override.yml - if [[ "$(cat docker-compose.override.yml | sed '/^\s*$/d' | wc -l)" == "2" ]]; then - mv docker-compose.override.yml docker-compose.override.yml_backup - fi + sed -i '/ipv6nat-mailcow:$/,/^$/d' docker-compose.override.yml + if [[ "$(cat docker-compose.override.yml | sed '/^\s*$/d' | wc -l)" == "2" ]]; then + mv docker-compose.override.yml docker-compose.override.yml_backup + fi fi echo -e "\e[32mGreat! \e[0mNative IPv6 NAT is active.\e[0m" else @@ -152,79 +152,47 @@ migrate_docker_nat() { } remove_obsolete_nginx_ports() { - # Removing obsolete docker-compose.override.yml - for override in docker-compose.override.yml docker-compose.override.yaml; do - if [ -s $override ] ; 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 -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[33m!!! Manual Merge needed (if other overrides are set) !!!\e[0m" - sleep 3 - cp $override ${override}_backup - sed -i '/nginx-mailcow:$/,/^$/d' $override - echo -e "\e[33mRemoved obsolete NGINX IPv6 Bind from original override File.\e[0m" - if [[ "$(cat $override | sed '/^\s*$/d' | wc -l)" == "2" ]]; then - mv $override ${override}_empty - echo -e "\e[31m${override} is empty. Renamed it to ensure mailcow is startable.\e[0m" - fi + # Removing obsolete docker-compose.override.yml + for override in docker-compose.override.yml docker-compose.override.yaml; do + if [ -s $override ] ; 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 -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[33m!!! Manual Merge needed (if other overrides are set) !!!\e[0m" + sleep 3 + cp $override ${override}_backup + sed -i '/nginx-mailcow:$/,/^$/d' $override + echo -e "\e[33mRemoved obsolete NGINX IPv6 Bind from original override File.\e[0m" + if [[ "$(cat $override | sed '/^\s*$/d' | wc -l)" == "2" ]]; then + mv $override ${override}_empty + echo -e "\e[31m${override} is empty. Renamed it to ensure mailcow is startable.\e[0m" fi - fi fi + fi fi - done -} - -detect_docker_compose_command(){ -if ! [ "${DOCKER_COMPOSE_VERSION}" == "native" ] && ! [ "${DOCKER_COMPOSE_VERSION}" == "standalone" ]; then - if command -v docker compose > /dev/null 2>&1; then - version=$(docker compose version --short) - if [[ $version =~ ^2\.([0-9]+)\.([0-9]+) ]]; then - COMPOSE_VERSION=native - 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 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 command -v docker-compose > /dev/null 2>&1; then - version=$(docker-compose version --short) - if [[ $version =~ ^2\.([0-9]+)\.([0-9]+) ]]; then - COMPOSE_VERSION=standalone - 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 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 - else - echo -e "\e[31mCannot find Docker Compose.\e[0m" - echo -e "\e[31mPlease 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_VERSION}" == "native" ]; then - COMPOSE_COMMAND="docker compose" - -elif [ "${DOCKER_COMPOSE_VERSION}" == "standalone" ]; then - COMPOSE_COMMAND="docker-compose" -fi + done } ############## End Function Section ############## -# Check permissions -if [ "$(id -u)" -ne "0" ]; then - echo "You need to be root" +# Exit on error and pipefail +set -o pipefail + +if [[ ! -f mailcow.conf ]]; then + echo -e "\e[31mmailcow.conf is missing! Is mailcow installed?\e[0m" exit 1 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 )" # Run pre-update-hook @@ -248,9 +216,6 @@ if [[ "$(uname -r)" =~ ^4\.4\. ]]; then read -p "Press any key to continue..." < /dev/tty fi -# Exit on error and pipefail -set -o pipefail - # Setting high dc timeout export COMPOSE_HTTP_TIMEOUT=600 @@ -259,15 +224,33 @@ PATH=$PATH:/opt/bin umask 0022 -# Unset COMPOSE_COMMAND and DOCKER_COMPOSE_VERSION Variable to be on the newest state. -unset COMPOSE_COMMAND -unset DOCKER_COMPOSE_VERSION +# Check if the container engine flag is set, otherwise set it +if [[ -z "${MAILCOW_CONTAINER_ENGINE}" ]]; then + if command -v podman > /dev/null 2>&1; then + MAILCOW_CONTAINER_ENGINE="podman" + echo -e "\e[32mFound Podman container engine.\e[0m" -for bin in curl docker git awk sha1sum; do - if [[ -z $(command -v ${bin}) ]]; then - echo "Cannot find ${bin}, exiting..." - exit 1; - fi + if [[ -n "${DOCKER_HOST}" ]] && [[ "${DOCKER_HOST}" == "unix://"* ]]; then + CONTAINER_SOCKET="${DOCKER_HOST/"unix://"/}" + else + CONTAINER_SOCKET="/run/user/${UID}/podman/podman.sock" + fi + 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" + else + echo "Cannot find container engine (Docker or Podman), exiting..." + exit 1 + fi +fi + +for bin in curl git awk sha1sum; do + if [[ -z $(command -v ${bin}) ]]; then + echo "Cannot find ${bin}, exiting..." + exit 1 + fi done export LC_ALL=C @@ -341,16 +324,11 @@ while (($#)); do shift 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//[^.]}; if [ ${#DOTS} -lt 2 ]; then 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 fi @@ -378,6 +356,10 @@ CONFIG_ARRAY=( "SNAT6_TO_SOURCE" "COMPOSE_PROJECT_NAME" "DOCKER_COMPOSE_VERSION" + "MAILCOW_CONTAINER_ENGINE" + "MAILCOW_CONTAINER_SOCKET" + "DOCKER_COMPOSE_EXTRA_OVERRIDES" + "MAILCOW_DOCKER_COMPOSE" "SQL_PORT" "API_KEY" "API_KEY_READ_ONLY" @@ -399,6 +381,7 @@ CONFIG_ARRAY=( "ACME_CONTACT" "WATCHDOG_VERBOSE" "WEBAUTHN_ONLY_TRUSTED_VENDORS" + "MAILCOW_STORAGE_DIR" ) sed -i --follow-symlinks '$a\' mailcow.conf @@ -418,12 +401,44 @@ for option in ${CONFIG_ARRAY[@]}; do echo "Adding new option \"${option}\" to mailcow.conf" echo "# Used Docker Compose version" >> 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 "# 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 "DOCKER_COMPOSE_VERSION=${DOCKER_COMPOSE_VERSION}" >> mailcow.conf 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}" >> mailcow.conf + fi elif [[ ${option} == "DOVEADM_PORT" ]]; then if ! grep -q ${option} mailcow.conf; then echo "Adding new option \"${option}\" to mailcow.conf" @@ -624,11 +639,16 @@ for option in ${CONFIG_ARRAY[@]}; do 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 fi -elif [[ ${option} == "WATCHDOG_VERBOSE" ]]; then + elif [[ ${option} == "WATCHDOG_VERBOSE" ]]; then if ! grep -q ${option} mailcow.conf; then echo '# Enable watchdog verbose logging' >> mailcow.conf echo 'WATCHDOG_VERBOSE=n' >> mailcow.conf - fi + fi + elif [[ ${option} == "MAILCOW_STORAGE_DIR" ]]; then + if ! grep -q ${option} mailcow.conf; then + 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 echo "Adding new option \"${option}\" to mailcow.conf" echo "${option}=n" >> mailcow.conf @@ -636,16 +656,16 @@ elif [[ ${option} == "WATCHDOG_VERBOSE" ]]; then done if [[( ${SKIP_PING_CHECK} == "y")]]; then -echo -e "\e[32mSkipping Ping Check...\e[0m" + echo -e "\e[32mSkipping Ping Check...\e[0m" else - echo -en "Checking internet connection... " - if ! check_online_status; then - echo -e "\e[31mfailed\e[0m" - exit 1 - else - echo -e "\e[32mOK\e[0m" - fi + echo -en "Checking internet connection... " + if ! check_online_status; then + echo -e "\e[31mfailed\e[0m" + exit 1 + else + echo -e "\e[32mOK\e[0m" + fi fi if ! [ $NEW_BRANCH ]; then @@ -676,9 +696,9 @@ elif [ $NEW_BRANCH == "master" ] && [ $CURRENT_BRANCH != "master" ]; then sleep 1 echo -e "\e[33mBefore you do: Please take a backup of all components to ensure that no Data is lost...\e[0m" 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. - 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" 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 @@ -741,7 +761,12 @@ if [ ! $FORCE ]; then echo "OK, exiting." exit 0 fi +fi + +if [[ "${MAILCOW_CONTAINER_ENGINE}" == "docker" ]]; then migrate_docker_nat +else + echo "Skipping migrating docker nat..." fi remove_obsolete_nginx_ports @@ -749,16 +774,20 @@ remove_obsolete_nginx_ports echo -e "\e[32mValidating docker-compose stack configuration...\e[0m" sed -i 's/HTTPS_BIND:-:/HTTPS_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" exit 1 fi -echo -e "\e[32mChecking for conflicting bridges...\e[0m" -MAILCOW_BRIDGE=$($COMPOSE_COMMAND config | grep -i com.docker.network.bridge.name | cut -d':' -f2) -while read NAT_ID; do - iptables -t nat -D POSTROUTING $NAT_ID -done < <(iptables -L -vn -t nat --line-numbers | grep $IPV4_NETWORK | grep -E 'MASQUERADE.*all' | grep -v ${MAILCOW_BRIDGE} | cut -d' ' -f1) +if [[ "${MAILCOW_CONTAINER_ENGINE}" == "docker" ]]; then + echo -e "\e[32mChecking for conflicting bridges...\e[0m" + MAILCOW_BRIDGE=$(./mailcow-compose.sh config | grep -i com.docker.network.bridge.name | cut -d':' -f2) + while read NAT_ID; do + iptables -t nat -D POSTROUTING $NAT_ID + done < <(iptables -L -vn -t nat --line-numbers | grep $IPV4_NETWORK | grep -E 'MASQUERADE.*all' | grep -v ${MAILCOW_BRIDGE} | cut -d' ' -f1) +else + echo "Skipping check for conflicting bridges..." +fi DIFF_DIRECTORY=update_diffs DIFF_FILE=${DIFF_DIRECTORY}/diff_before_update_$(date +"%Y-%m-%d-%H-%M-%S") @@ -775,12 +804,13 @@ prefetch_images echo -e "\e[32mStopping mailcow...\e[0m" sleep 2 -MAILCOW_CONTAINERS=($($COMPOSE_COMMAND ps -q)) -$COMPOSE_COMMAND down +MAILCOW_CONTAINERS=($(./mailcow-compose.sh ps -q)) +./mailcow-compose.sh down + echo -e "\e[32mChecking for remaining containers...\e[0m" sleep 2 for container in "${MAILCOW_CONTAINERS[@]}"; do - docker rm -f "$container" 2> /dev/null + ${MAILCOW_CONTAINER_ENGINE} rm -f "$container" 2> /dev/null done [[ -f data/conf/nginx/ZZZ-ejabberd.conf ]] && rm data/conf/nginx/ZZZ-ejabberd.conf @@ -804,7 +834,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" exit 1 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 add -A git commit -m "After update on ${DATE}" > /dev/null @@ -813,13 +843,18 @@ elif [[ ${MERGE_RETURN} == 1 ]]; then elif [[ ${MERGE_RETURN} != 0 ]]; then echo -e "\e[31m\nOh no, something went wrong. Please check the error message above.\e[0m" 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 fi echo -e "\e[32mFetching new images, if any...\e[0m" 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 [[ ! -d data/assets/ssl ]] && mkdir -p data/assets/ssl @@ -831,7 +866,7 @@ if grep -q 'SYSCTL_IPV6_DISABLED=1' mailcow.conf; then echo '!! IMPORTANT !!' 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 '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 '!! IMPORTANT !!' echo @@ -869,8 +904,8 @@ else mailcow_last_git_version="" fi -mailcow_git_commit=$(git rev-parse origin/${BRANCH}) -mailcow_git_commit_date=$(git log -1 --format=%ci @{upstream} ) +mailcow_git_commit=$(git rev-parse HEAD) +mailcow_git_commit_date=$(git log -1 --format=%ci HEAD ) if [ $? -eq 0 ]; then echo ' data/web/inc/app_info.inc.php @@ -903,11 +938,11 @@ fi sed -i 's/^DOCKER_COMPOSE_VERSION=$/DOCKER_COMPOSE_VERSION='$DOCKER_COMPOSE_VERSION'/g' mailcow.conf 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 echo -e "\e[32mStarting mailcow...\e[0m" sleep 2 - $COMPOSE_COMMAND up -d --remove-orphans + ./mailcow-compose.sh up -d --remove-orphans fi echo -e "\e[32mCollecting garbage...\e[0m" @@ -922,4 +957,4 @@ fi # echo # git reflog --color=always | grep "Before update on " # echo -# echo "Use \"git reset --hard hash-on-the-left\" and run $COMPOSE_COMMAND up -d afterwards." \ No newline at end of file +# echo "Use \"git reset --hard hash-on-the-left\" and run ./mailcow-compose.sh up -d afterwards." From 18ad7b018d24323ce6a61093a27b3ec11bc5d910 Mon Sep 17 00:00:00 2001 From: Roy Lenferink Date: Thu, 12 Jan 2023 13:25:24 +0100 Subject: [PATCH 13/19] Add check for patch utility in case of podman --- generate_config.sh | 6 +++++- update.sh | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/generate_config.sh b/generate_config.sh index d2d3e98e..4c17862e 100755 --- a/generate_config.sh +++ b/generate_config.sh @@ -32,17 +32,21 @@ if command -v podman > /dev/null 2>&1; then 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; do +for bin in openssl curl git awk sha1sum ${EXTRA_REQUIRED_PACKAGES}; do if [[ -z $(which ${bin}) ]]; then echo "Cannot find ${bin}, exiting..." exit 1 diff --git a/update.sh b/update.sh index e4940c09..6700a9ed 100755 --- a/update.sh +++ b/update.sh @@ -235,18 +235,22 @@ if [[ -z "${MAILCOW_CONTAINER_ENGINE}" ]]; then 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 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; do +for bin in curl git awk sha1sum ${EXTRA_REQUIRED_PACKAGES}; do if [[ -z $(command -v ${bin}) ]]; then echo "Cannot find ${bin}, exiting..." exit 1 From 5d91a9e0aae9ebf1b02cda3ce0836f78dcac3946 Mon Sep 17 00:00:00 2001 From: Roy Lenferink Date: Sat, 14 Jan 2023 19:54:23 +0100 Subject: [PATCH 14/19] Fixes for update script --- update.sh | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/update.sh b/update.sh index 6700a9ed..e7987736 100755 --- a/update.sh +++ b/update.sh @@ -441,7 +441,7 @@ for option in ${CONFIG_ARRAY[@]}; do 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}" >> mailcow.conf + echo "MAILCOW_DOCKER_COMPOSE=${MAILCOW_DOCKER_COMPOSE:-"docker-compose"}" >> mailcow.conf fi elif [[ ${option} == "DOVEADM_PORT" ]]; then if ! grep -q ${option} mailcow.conf; then @@ -618,6 +618,7 @@ for option in ${CONFIG_ARRAY[@]}; do fi elif [[ ${option} == "ADDITIONAL_SERVER_NAMES" ]]; 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 '#' >> mailcow.conf echo '# Specify alternative addresses for the mailcow UI to respond to' >> mailcow.conf @@ -629,6 +630,7 @@ for option in ${CONFIG_ARRAY[@]}; do fi elif [[ ${option} == "ACME_CONTACT" ]]; 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 '# Optional: Leave empty for none' >> mailcow.conf echo '# This value is only used on first order!' >> mailcow.conf @@ -638,6 +640,7 @@ for option in ${CONFIG_ARRAY[@]}; do fi elif [[ ${option} == "WEBAUTHN_ONLY_TRUSTED_VENDORS" ]]; then if ! grep -q ${option} mailcow.conf; then + echo "Adding new option \"${option}\" to 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 '# root certificates can be placed for validation under mailcow-dockerized/data/web/inc/lib/WebAuthn/rootCertificates' >> mailcow.conf @@ -645,11 +648,13 @@ for option in ${CONFIG_ARRAY[@]}; do fi elif [[ ${option} == "WATCHDOG_VERBOSE" ]]; then if ! grep -q ${option} mailcow.conf; then + echo "Adding new option \"${option}\" to mailcow.conf" echo '# Enable watchdog verbose logging' >> mailcow.conf echo 'WATCHDOG_VERBOSE=n' >> mailcow.conf 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 From 34b2e1270adb7159cc7e97a47f1b0a41dd1963ba Mon Sep 17 00:00:00 2001 From: Roy Lenferink Date: Mon, 16 Jan 2023 19:00:24 +0100 Subject: [PATCH 15/19] Add note to describe podman as experimental --- generate_config.sh | 1 + update.sh | 1 + 2 files changed, 2 insertions(+) diff --git a/generate_config.sh b/generate_config.sh index 4c17862e..90b25b1a 100755 --- a/generate_config.sh +++ b/generate_config.sh @@ -26,6 +26,7 @@ if sed --help 2>&1 | head -n 1 | grep -q -i "busybox"; then echo "BusyBox sed de 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://"/}" diff --git a/update.sh b/update.sh index e7987736..8a728400 100755 --- a/update.sh +++ b/update.sh @@ -229,6 +229,7 @@ if [[ -z "${MAILCOW_CONTAINER_ENGINE}" ]]; then 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" if [[ -n "${DOCKER_HOST}" ]] && [[ "${DOCKER_HOST}" == "unix://"* ]]; then CONTAINER_SOCKET="${DOCKER_HOST/"unix://"/}" From e58e8fc85ac8c990b62d6e0132fc7fa8ee5d8370 Mon Sep 17 00:00:00 2001 From: Roy Lenferink Date: Mon, 16 Jan 2023 19:19:00 +0100 Subject: [PATCH 16/19] Add directory creation to mailcow-compose script --- mailcow-compose.sh | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/mailcow-compose.sh b/mailcow-compose.sh index 5f458bc0..3130200e 100755 --- a/mailcow-compose.sh +++ b/mailcow-compose.sh @@ -20,7 +20,8 @@ function validate_input() source mailcow.conf } -detect_docker_compose_command(){ +function detect_docker_compose_command() +{ if ! [[ "${DOCKER_COMPOSE_VERSION}" == "native" ]] && ! [[ "${DOCKER_COMPOSE_VERSION}" == "standalone" ]]; then if command -v docker compose > /dev/null 2>&1; then version=$(docker compose version --short) @@ -65,6 +66,25 @@ detect_docker_compose_command(){ 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 @@ -86,4 +106,5 @@ function run_compose() #--------------------------------------- validate_input $@ detect_docker_compose_command +ensure_storage_directories_exist run_compose $@ From 781896562e578ef2ddb71d6a235f11e4fa8d410a Mon Sep 17 00:00:00 2001 From: Roy Lenferink Date: Mon, 16 Jan 2023 19:39:00 +0100 Subject: [PATCH 17/19] Remove fixed HTTP/HTTPS bind addresses --- generate_config.sh | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/generate_config.sh b/generate_config.sh index 90b25b1a..928f7e24 100755 --- a/generate_config.sh +++ b/generate_config.sh @@ -212,14 +212,8 @@ fi [ ! -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 - MAILCOW_HTTP_BIND="127.0.0.1" - MAILCOW_HTTPS_BIND="127.0.0.1" - # Apply patches for usage with Podman bash ./patches-for-podman.sh -else - MAILCOW_HTTP_BIND="" - MAILCOW_HTTPS_BIND="" fi cat << EOF > mailcow.conf @@ -266,10 +260,10 @@ DBROOT=$(LC_ALL=C Date: Mon, 16 Jan 2023 19:41:34 +0100 Subject: [PATCH 18/19] Revert MySQL configuration file changes, not needed --- data/conf/mysql/my.cnf | 12 ++++++------ patches-for-podman.sh | 9 --------- 2 files changed, 6 insertions(+), 15 deletions(-) diff --git a/data/conf/mysql/my.cnf b/data/conf/mysql/my.cnf index ccc9fcab..b4c34886 100644 --- a/data/conf/mysql/my.cnf +++ b/data/conf/mysql/my.cnf @@ -1,9 +1,3 @@ -[client] -default-character-set = utf8mb4 - -[mysql] -default-character-set = utf8mb4 - [mysqld] character-set-client-handshake = FALSE character-set-server = utf8mb4 @@ -33,3 +27,9 @@ log-warnings = 0 event_scheduler = 1 interactive_timeout = 3610 wait_timeout = 3610 + +[client] +default-character-set = utf8mb4 + +[mysql] +default-character-set = utf8mb4 diff --git a/patches-for-podman.sh b/patches-for-podman.sh index 711e470a..96ff6f56 100755 --- a/patches-for-podman.sh +++ b/patches-for-podman.sh @@ -20,12 +20,3 @@ if ! patch -R -s -f --dry-run docker-compose.yml < ${PATCH_FILE} > /dev/null 2>& else echo "docker-compose.yml already patched (or custom changes prevent applying the patch)" fi - -# Patch the MySQL configuration file -MYCNF_PATH="data/conf/mysql/my.cnf" -if ! grep "bind_address" ${MYCNF_PATH} > /dev/null 2>&1; then - echo "patching file my.cnf" - echo "bind_address = 0.0.0.0" >> ${MYCNF_PATH} -else - echo "my.cnf already patched" -fi From f92c4ac05fb5c910c95bfdd0ac10ac79430ab925 Mon Sep 17 00:00:00 2001 From: Roy Lenferink Date: Fri, 24 Feb 2023 14:00:29 +0100 Subject: [PATCH 19/19] Podman requires SYS_CHROOT for postfix and dovecot --- .../CONTAINER_ENGINE_PODMAN/docker-compose.override.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/helper-scripts/docker-compose.override.yml.d/CONTAINER_ENGINE_PODMAN/docker-compose.override.yml b/helper-scripts/docker-compose.override.yml.d/CONTAINER_ENGINE_PODMAN/docker-compose.override.yml index 89fdf079..54fc2c74 100644 --- a/helper-scripts/docker-compose.override.yml.d/CONTAINER_ENGINE_PODMAN/docker-compose.override.yml +++ b/helper-scripts/docker-compose.override.yml.d/CONTAINER_ENGINE_PODMAN/docker-compose.override.yml @@ -14,6 +14,14 @@ version: '3.9' services: + dovecot-mailcow: + cap_add: + - SYS_CHROOT + + postfix-mailcow: + cap_add: + - SYS_CHROOT + dockerapi-mailcow: volumes: - ${MAILCOW_CONTAINER_SOCKET}:/var/run/docker.sock:ro