diff --git a/CHANGELOG.md b/CHANGELOG.md index 43b9110..d4d68de 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,14 +1,16 @@ # 1.2.2 -- [kopano](src/kopano) Adding support for gateway / IMAP iCAL search configuration via envvars in, 50-kopano-apply-envvars. -- [kopano](src/kopano) Fixed old bug where set but empty environment variable was ignored by 50-kopano-apply-envvars. +- [kopano](src/kopano) Adding support for gateway / IMAP iCAL search configuration via envvars in, `50-kopano-apply-envvars`. +- [kopano](src/kopano) Fixed old bug where set but empty environment variable was ignored by `50-kopano-apply-envvars`. - [demo](demo) Enable IMAP POP3 and CalDAV/iCAL in demo. -- [docker](Dockerfile) Update kopano services. +- [docker](Dockerfile) Update Kopano services. - [docker](README.md) Added sections `Mail client configuration` and `Implementation`. +- [docker](Dockerfile) Remove the `debugtools` build target. There already exists an `app-debugtools` target in the [`demo/Makefile`](demo/Makefile). +- [docker](Dockerfile) Now use an unlock file, which is removed after a virgin container has been configured. This locks the configuration on restarts unless `FORCE_CONFIG` is given. # 1.2.1 -- [docker](Dockerfile) The kopano installation now (version 10.0.6) populate all example-config files in /etc/kopano. This breaks our configuration, so we need to remove them. They can still be found here /usr/share/doc/kopano/example-config. +- [docker](Dockerfile) The Kopano installation now (version 10.0.6) populate all example-config files in /etc/kopano. This breaks our configuration, so we need to remove them. They can still be found here /usr/share/doc/kopano/example-config. # 1.2.0 diff --git a/Dockerfile b/Dockerfile index 969f0cf..382b258 100644 --- a/Dockerfile +++ b/Dockerfile @@ -20,6 +20,7 @@ ENV DEBIAN_FRONTEND=noninteractive \ DOCKER_RUNAS=kopano \ DOCKER_BUILD_DEB_DIR=/tmp/deb \ DOCKER_BUILD_PASSES=1 \ + DOCKER_UNLOCK_FILE=/etc/kopano/.docker.unlock \ SYSLOG_OPTIONS='-S' \ SYSLOG_LEVEL=5 # @@ -113,7 +114,8 @@ RUN mkdir -p $DOCKER_BUILD_DEB_DIR \ "-d kopano-grapi serve" \ "-d kopano-kapid serve --log-timestamp=false" \ "-d kopano-konnectd serve --log-timestamp=false" \ - "-d kopano-monitor" + "-d kopano-monitor" \ + && echo "This file unlocks the configuration, so it will be deleted after initialization." > $DOCKER_UNLOCK_FILE # # Have runit's runsvdir start all services # @@ -200,7 +202,7 @@ ENV DEBIAN_FRONTEND=noninteractive \ DOCKER_BUILD_DEB_DIR=/tmp/deb \ DOCKER_BUILD_PASSES=1 # -# Add Z-Push repository and install Z-Push configured to be used with kopano and apache +# Add Z-Push repository and install Z-Push configured to be used with Kopano and Apache # RUN debaddr="$(kopano-webaddr.sh --deb final http://repo.z-hub.io/z-push: ${DIST} ${REL})" \ && echo "deb $debaddr/ /" > /etc/apt/sources.list.d/z-push.list \ @@ -219,24 +221,3 @@ RUN debaddr="$(kopano-webaddr.sh --deb final http://repo.z-hub.io/z-push: ${DIST && dc_replace /usr/share/z-push/config.php 'define(\x27USE_CUSTOM_REMOTE_IP_HEADER\x27, false);' 'define(\x27USE_CUSTOM_REMOTE_IP_HEADER\x27, \x27HTTP_X_FORWARDED_FOR\x27);' \ && dc_replace /usr/share/z-push/config.php 'define(\x27LOGBACKEND\x27, \x27filelog\x27);' 'define(\x27LOGBACKEND\x27, \x27syslog\x27);' - - -FROM full AS debugtools -# -# Optionaly install debug tools -# -RUN apt-get update && apt-get install --yes --no-install-recommends \ - less \ - nano \ - ldap-utils \ - htop \ - net-tools \ - lsof \ - iputils-ping -# -# clean up -# -#RUN apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* - - - diff --git a/Makefile b/Makefile index 89991ff..1399aac 100644 --- a/Makefile +++ b/Makefile @@ -17,7 +17,7 @@ variables: ps: docker ps -a -build-all: build_core build_full build_debugtools +build-all: build_core build_full build: build_$(BLD_TGT) diff --git a/README.md b/README.md index c306ed5..3e2c27c 100644 --- a/README.md +++ b/README.md @@ -28,9 +28,9 @@ The `mlan/kopano` repository contains a multi staged built. You select which bui The version part of the tag is not based on the version of this repository. It is instead, based on the combined revision numbers of the nightly Kopano core and Kopano WebApp package suits that was available when building the images. For example, `8.7.80-3.5.2` indicates that the image was built using the 8.7.80 version of Kopano core and 3.5.2 version of Kopano WebApp. -The build part of the tag is one of `full`, `debugtools` and `core`. The image with tag `full` contain Kopano core components, as well as, the Kopano WebApp and Z-Push. The image with tag `debugtools` also contains some debug tools. The image with tag `core` contains the Kopano core components proving the server and IMAP, POP3 and ICAL access, but no web access. +The build part of the tag is one of `full` and `core`. The image with tag `full` contain Kopano core components, as well as, the Kopano WebApp and Z-Push. The image with tag `core` contains the Kopano core components proving the server and IMAP, POP3 and ICAL access, but no web access. -The tags `latest`, `full`, `debugtools` or `core` all reference the most recent builds. +The tags `latest`, `full`, or `core` all reference the most recent builds. To exemplify the usage of the tags, lets assume that the latest version tag is `8.7.80-3.5.2`. In this case `latest`, `8.7.80-3.5.2`, `full`, and `full-8.7.80-3.5.2` all identify the same image. @@ -196,12 +196,12 @@ There are at least three directories which should be considered for persistent s The `mlan/kopano` image contains an elaborate configuration / seeding procedure. The configuration is controlled by environment variables, described below. -The seeding procedure will leave any existing configuration untouched. This is achieved by the using an unlock file: `DOCKER_UNLOCK_FILE=/srv/etc/.docker.unlock`. +The seeding procedure will leave any existing configuration untouched. This is achieved by the using an unlock file: `DOCKER_UNLOCK_FILE=/etc/kopano/.docker.unlock`. During the image build this file is created. When the the container is started the configuration / seeding procedure will be executed if the `DOCKER_UNLOCK_FILE` can be found. Once the procedure completes the unlock file is deleted preventing the configuration / seeding procedure to run when the container is restarted. The unlock file approach was selected since it is difficult to accidentally _create_ a file. -In the rare event that want to modify the configuration of an existing container you can override the default behavior by setting `FORCE_CONFIG=OVERWRITE` to a no-empty string. +In the rare event that want to modify the configuration of an existing container you can override the default behavior by setting `FORCE_CONFIG=overwrite` to a no-empty string. ## Environment variables @@ -372,7 +372,7 @@ Here some topics relevant for arranging a mail server are presented. Kopano, using [Z-Push](http://z-push.org/), allows native interfacing with Microsoft Outlook 2013 and above via the [Exchange ActiveSync (EAS)](https://en.wikipedia.org/wiki/Exchange_ActiveSync) protocol, providing synchronization of mail, calendar, tasks and contacts. For details please see [Configuring Outlook](https://documentation.kopano.io/user_manual_kopanocore/configure_outlook.html). -It can be interesting to know that there is a [Kopano OL Extension](https://kb.kopano.io/display/WIKI/Setting+up+the+Kopano+OL+Extension) that can improve productivity. To install it [download](https://download.kopano.io/community/olextension%3A/) and run the `KopanoOLExtension--combined.exe` file on your Windows PC. +It can be interesting to know that there is a [Kopano OL Extension](https://kb.kopano.io/display/WIKI/Setting+up+the+Kopano+OL+Extension) that can improve productivity. To install it [download](https://download.kopano.io/community/olextension%3A/) and run the `KopanoOLExtension--combined.exe` file on your Windows PC. ### Mobile devices diff --git a/ROADMAP.md b/ROADMAP.md index a575b6c..38dbfd9 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -1,9 +1,5 @@ # Road map -## Dockerfile - -Consider removing debugtools build target. There already exists a app-debugtools target in the demo Makefile. - ## kDAV Consider integrating support for kDAV which provides CalDAV and CardDAV. diff --git a/demo/.env b/demo/.env index 517b75a..f88be98 100644 --- a/demo/.env +++ b/demo/.env @@ -2,6 +2,7 @@ COMPOSE_PROJECT_NAME=demo SYSLOG_LEVEL=5 MAIL_DOMAIN=example.com MAIL_SRV=mx +REGEX_ALIAS='/([^+]+)[+-].*@(.+)/ $1@$2' DKIM_SELECTOR=default SA_TAG_LEVEL_DEFLT=-999 SA_DEBUG=0 diff --git a/demo/Makefile b/demo/Makefile index bd2a074..f53ecb7 100644 --- a/demo/Makefile +++ b/demo/Makefile @@ -1,6 +1,7 @@ -include *.mk .env .init.env srv_list ?= auth app db mta +curl_dbg ?= -v _ip = $(shell docker inspect -f \ '{{range .NetworkSettings.Networks}}{{println .IPAddress}}{{end}}' \ $(1) | head -n1) @@ -10,9 +11,11 @@ _ip = $(shell docker inspect -f \ variables: make -pn | grep -A1 "^# makefile"| grep -v "^#\|^--" | sort | uniq -test: mta-test +test: mta-test_quiet mta-test_smtp -init: auth-up wait_11 auth-mod_index auth-add_user db-up mta-up app-up +init: auth-init db-up mta-up app-up + +auth-init: auth-up wait_11 auth-mod_hash auth-mod_index auth-add_user ps: docker-compose ps @@ -73,11 +76,19 @@ web: firefox localhost:8008 & auth-show_conf: + docker-compose exec auth ldap search -b cn=config "(cn=config)" + docker-compose exec auth ldap search -b cn=config olcDatabase={-1}frontend docker-compose exec auth ldap search -b cn=config olcDatabase={1}mdb auth-show_user: docker-compose exec auth ldap search -b "$(LDAP_BASE)" +auth-show_cat0: + docker-compose exec auth slapcat -n0 + +auth-show_cat1: + docker-compose exec auth slapcat -n1 + auth-add_user: printf "dn: ou=$(LDAP_USEROU),$(LDAP_BASE)\nchangetype: add\nobjectClass: organizationalUnit\nobjectClass: top\nou: $(LDAP_USEROU)\n\ndn: ou=$(LDAP_GROUPOU),$(LDAP_BASE)\nchangetype: add\nobjectClass: organizationalUnit\nobjectClass: top\nou: $(LDAP_GROUPOU)\n\ndn: uid=$(LDAP_TEST_USER),ou=$(LDAP_USEROU),$(LDAP_BASE)\nchangetype: add\nobjectClass: top\nobjectClass: inetOrgPerson\nobjectClass: $(LDAP_USEROBJ)\ncn: $(LDAP_TEST_USER)\nsn: $(LDAP_TEST_USER)\nuid: $(LDAP_TEST_USER)\nmail: $(LDAP_TEST_USER)@$(MAIL_DOMAIN)\nuidNumber: 1234\ngidNumber: 1234\nhomeDirectory: /home/$(LDAP_TEST_USER)\nuserPassword: $(LDAP_TEST_PASSWD)\n" \ | docker-compose exec -T auth ldap modify @@ -86,12 +97,25 @@ auth-mod_index: printf "dn: olcDatabase={1}mdb,cn=config\nchangetype: modify\nadd: olcDbIndex\nolcDbIndex: cn,ou,uid,mail eq\n" \ | docker-compose exec -T auth ldap modify +auth-mod_hash: + printf "dn: olcDatabase={-1}frontend,cn=config\nchangetype: modify\nadd: olcPasswordHash\nolcPasswordHash: {CRYPT}\n\ndn: cn=config\nchangetype: modify\nadd: olcPasswordCryptSaltFormat\nolcPasswordCryptSaltFormat: \$$6\$$%%.16s\n" \ + | docker-compose exec -T auth ldap modify + mta-bayes: docker-compose exec mta sh -c 'rm -f bayesian.database.gz && wget http://artinvoice.hu/spams/bayesian.database.gz && gunzip bayesian.database.gz && sa-learn --restore bayesian.database && chown -R amavis: /var/amavis/.spamassassin && rm -rf bayesian.database' -mta-test: - printf "EHLO mx\nMAIL FROM: \nRCPT TO: <$(LDAP_TEST_USER)@$(MAIL_DOMAIN)>\nDATA\nFrom: A tester \nTo: <$(LDAP_TEST_USER)@$(MAIL_DOMAIN)>\nDate: $$(date)\nSubject: A SMTP test message\n\nGreat news! You can receive email.\n.\nQUIT\n" \ - | nc -C localhost 25 +mta-test_quiet: + $(eval curl_dbg := ) + +mta-test_smtp: + printf "From: A tester \nTo: <$(LDAP_TEST_USER)@$(MAIL_DOMAIN)>\nDate: $$(date)\nSubject: A SMTP test message\n\nGreat news! You can receive email.\n" \ + | curl smtp://localhost -s -T - $(curl_dbg) \ + --mail-from test@example.biz --mail-rcpt $(LDAP_TEST_USER)@$(MAIL_DOMAIN) + +mta-test_smtp2: + printf "From: A info tester \nTo: <$(LDAP_TEST_USER)-info@$(MAIL_DOMAIN)>\nDate: $$(date)\nSubject: A SMTP test message \n\nGreat news! $(LDAP_TEST_USER)-info@$(MAIL_DOMAIN) can also receive email.\n" \ + | curl smtp://localhost -s -T - $(curl_dbg) \ + --mail-from test@example.biz --mail-rcpt $(LDAP_TEST_USER)@$(MAIL_DOMAIN) mta-razor: docker-compose exec mta run amavis_register_razor @@ -119,6 +143,29 @@ mta-encrypt: $(eval secret := $(shell whiptail --backtitle "doveadm pw" --title "encrypt password" --inputbox "password" 8 78 secret 3>&1 1>&2 2>&3)) docker-compose exec mta doveadm pw -p $(secret) +mta-show_doveconf: + docker-compose exec mta doveconf -n + +mta-show_postconf: + docker-compose exec mta postconf -n + +mta-hostaddr: + $(eval myhost := $(call _ip,$(COMPOSE_PROJECT_NAME)_mta_1)) + +mta-test_auth: + docker-compose exec mta doveadm auth test $(LDAP_TEST_USER) $(LDAP_TEST_PASSWD) + +mta-test_imap: mta-hostaddr + curl imap://$(myhost) -X CAPABILITY + curl imap://$(myhost) -u $(LDAP_TEST_USER):$(LDAP_TEST_PASSWD) + +mta-test_rimap: + docker-compose exec mta curl imap://app -X CAPABILITY + docker-compose exec mta curl imap://app -u $(LDAP_TEST_USER):$(LDAP_TEST_PASSWD) + +mta-test_ldap: mta-debugtools + docker-compose exec mta ldapsearch -H ldap://auth:389 -xLLL -s base namingContexts + db-test: docker-compose exec db mysqlshow -u $(MYSQL_USER) $(MYSQL_DATABASE) -p$(MYSQL_PASSWORD) @@ -136,7 +183,7 @@ app-man_server: app-man_ldap: docker-compose exec app man kopano-ldap.cfg -app-test_smtp: mta-test +app-test_smtp: mta-test_smtp app-test_lmtp: printf "LHLO mx\nMAIL FROM: \nRCPT TO: <$(LDAP_TEST_USER)@$(MAIL_DOMAIN)>\nDATA\nFrom: A tester \nTo: <$(LDAP_TEST_USER)@$(MAIL_DOMAIN)>\nDate: $$(date)\nSubject: A LMTP test message from me to you\n\nDelete me, please \n.\nQUIT\n" | nc -C $(call _ip,$(COMPOSE_PROJECT_NAME)_app_1) 2003 diff --git a/demo/docker-compose.yml b/demo/docker-compose.yml index a4c542d..0541175 100644 --- a/demo/docker-compose.yml +++ b/demo/docker-compose.yml @@ -57,6 +57,8 @@ services: - SMTP_TLS_WRAPPERMODE=${SMTP_TLS_WRAPPERMODE-no} - LDAP_USER_BASE=ou=${LDAP_USEROU-users},${LDAP_BASE-dc=example,dc=com} - LDAP_QUERY_FILTER_USER=(&(objectclass=${LDAP_USEROBJ-posixAccount})(mail=%s)) + - LDAP_QUERY_ATTRS_PASS=uid=user + - REGEX_ALIAS=${REGEX_ALIAS-} - DKIM_SELECTOR=${DKIM_SELECTOR-default} - SA_TAG_LEVEL_DEFLT=${SA_TAG_LEVEL_DEFLT-2.0} - SA_DEBUG=${SA_DEBUG-0} diff --git a/hooks/build b/hooks/build index 34ba6aa..feb35b0 100644 --- a/hooks/build +++ b/hooks/build @@ -8,7 +8,6 @@ echo "hooks/build called with IMAGE_NAME=${DOCKER_REPO}:${DOCKER_TAG}, so we wil case "${DOCKER_TAG}" in core) bld_target=core ;; full) bld_target=full ;; - debugtools) bld_target=debugtools ;; webapp) bld_target=core-webapp ;; *) echo "NOTHING since we do not know how to build with tag=${DOCKER_TAG}" diff --git a/src/docker/bin/docker-common.sh b/src/docker/bin/docker-common.sh index 401d4de..eb6bb4c 100644 --- a/src/docker/bin/docker-common.sh +++ b/src/docker/bin/docker-common.sh @@ -12,7 +12,7 @@ DOCKER_LOGUSAGE=${DOCKER_LOGUSAGE-usage} # Write messages to console if interactive or syslog if not. # Usage: inform priority message # The priority may be specified numerically or as a facility.level pair. -# Example user.notice, or 1.6 level is one of: +# Example user.notice, or 1.6 level is one of: # 0|emerg|1|alert|2|crit|3|err|4|warning|5|notice|6|info|7|debug # dc_log() { @@ -100,3 +100,31 @@ dc_update_loglevel() { [ -n "$DOCKER_RUNFUNC" ] && sv restart syslogd fi } + +# +# Print package versions +# +dc_pkg_versions() { + local pkgs="$@" + local len=$(echo $pkgs | tr " " "\n" | wc -L) + local ver ver_cmd sed_flt + local os=$(sed -rn 's/PRETTY_NAME="(.*)"/\1/p' /etc/os-release) + local kern=$(uname -r) + local host=$(uname -n) + dc_log 5 $host $os $kern + if [ -x "$(command -v apk)" ]; then + ver_cmd="apk info -s" + sed_flt="s/.*-(.*)-.*/\1/p" + elif [ -x "$(command -v apt)" ]; then + ver_cmd="apt list --installed" + sed_flt="s/[^ ]+ ([[:digit:]]+\.[[:digit:]]+\.[[:digit:]]+).*/\1/p" + else + dc_log 5 "No package manager found among: apk apt" + fi + for pkg in $pkgs; do + ver=$($ver_cmd $pkg 2> /dev/null | sed -rn "$sed_flt") + if [ -n "$ver" ]; then + printf "\t%-${len}s\t%s\n" $pkg $ver + fi + done +} diff --git a/src/docker/entry.d/10-docker-print-versions b/src/docker/entry.d/10-docker-print-versions new file mode 100755 index 0000000..60ce3e4 --- /dev/null +++ b/src/docker/entry.d/10-docker-print-versions @@ -0,0 +1,5 @@ +#!/bin/sh +# +# 10-docker-print-versions +# +dc_pkg_versions kopano-common kopano-webapp z-push-kopano diff --git a/src/docker/entry.d/80-docker-lock-config b/src/docker/entry.d/80-docker-lock-config new file mode 100755 index 0000000..66e0c7f --- /dev/null +++ b/src/docker/entry.d/80-docker-lock-config @@ -0,0 +1,9 @@ +#!/bin/sh +# +# 80-docker-lock-config +# +# Functions defined in: +# docker-config.sh +# +# +dc_lock_config diff --git a/src/kopano/entry.d/50-kopano-apply-envvars b/src/kopano/entry.d/10-kopano-common similarity index 89% rename from src/kopano/entry.d/50-kopano-apply-envvars rename to src/kopano/entry.d/10-kopano-common index fd64812..843fa94 100755 --- a/src/kopano/entry.d/50-kopano-apply-envvars +++ b/src/kopano/entry.d/10-kopano-common @@ -1,13 +1,13 @@ #!/bin/bash # -# 50-kopano-apply-envvars +# 10-kopano-common # # Kopano now installs without any cfg files, so we just write custom values # into their target cfg file. # # -# config +# Configuration # DOCKER_CONF_DIR1=${DOCKER_CONF_DIR1-/etc/kopano} @@ -26,7 +26,7 @@ sqlstate_cfg_file=$DOCKER_CONF_DIR2/backend/sqlstatemachine/config.php zpush_cfg_file=$DOCKER_CONF_DIR2/config.php # -# define environment variables +# Define environment variables # dagent_env_vars="LMTP_LISTEN LOG_LEVEL SPAM_HEADER_NAME SPAM_HEADER_VALUE" @@ -46,18 +46,19 @@ zpush_env_vars="TIMEZONE USE_CUSTOM_REMOTE_IP_HEADER USE_FULLEMAIL_FOR_LOGIN STA # _kopano_apply_envvars_gen() { - # do not touch existing cfg files + # move existing cfg files local cfg_file=$1 shift local env_vars=$@ - if [ ! -e $cfg_file ]; then - for env_var in $env_vars; do - if [ -n "${!env_var+x}" ]; then - dc_log 5 "Setting ${env_var,,} = ${!env_var} in $cfg_file" - echo ${env_var,,} = ${!env_var} >> $cfg_file - fi - done + if [ -e $cfg_file ]; then + mv -f $cfg_file $cfg_file.orig fi + for env_var in $env_vars; do + if [ -n "${!env_var+x}" ]; then + dc_log 5 "Setting ${env_var,,} = ${!env_var} in $cfg_file" + echo ${env_var,,} = ${!env_var} >> $cfg_file + fi + done } _kopano_apply_phpenvvars_gen() { @@ -89,10 +90,3 @@ kopano_apply_phpenvvars() { _kopano_apply_phpenvvars_gen $sqlstate_cfg_file $sqlstate_env_vars _kopano_apply_phpenvvars_gen $zpush_cfg_file $zpush_env_vars } - -# -# run -# - -kopano_apply_envvars -kopano_apply_phpenvvars diff --git a/src/kopano/entry.d/50-kopano-config b/src/kopano/entry.d/50-kopano-config new file mode 100755 index 0000000..08a4d49 --- /dev/null +++ b/src/kopano/entry.d/50-kopano-config @@ -0,0 +1,16 @@ +#!/bin/sh +# +# 50-kopano-config +# +# Functions defined in: +# docker-config.sh 10-kopano-common +# +# + +# +# Configure Kopano if it is unlocked. +# +if dc_is_unlocked; then + kopano_apply_envvars + kopano_apply_phpenvvars +fi