From 4227d0475388732bd6094573289d4a47f97844bb Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Sat, 28 Mar 2015 15:59:15 +0100 Subject: [PATCH 001/155] First commit. Need to add README and default configurations. --- Dockerfile | 33 ++++++++++++++++++++++++++++ start-mailserver.sh | 53 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+) create mode 100644 Dockerfile create mode 100644 start-mailserver.sh diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..51f64e90 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,33 @@ +FROM ubuntu:14.04 +MAINTAINER Thomas VIAL + +# Packages +RUN apt-get update -q +RUN apt-get -y upgrade +RUN DEBIAN_FRONTEND=noninteractive apt-get -y install postfix sasl2-bin courier-imap courier-authdaemon supervisor libfam0 fam amavisd-new spamassassin clamav-daemon libnet-dns-perl libmail-spf-perl pyzor razor arj bzip2 cabextract cpio file gzip nomarch pax unzip zip zoo +RUN apt-get autoclean + +# Configures Saslauthd +RUN rm -rf /var/run/saslauthd && ln -s /var/spool/postfix/var/run/saslauthd /var/run/saslauthd +RUN adduser postfix sasl +RUN echo 'NAME="saslauthd"\nSTART=yes\nMECHANISMS="sasldb"\nTHREADS=0\nPWDIR=/var/spool/postfix/var/run/saslauthd\nPIDFILE="${PWDIR}/saslauthd.pid"\nOPTIONS="-n 0 -r -m /var/spool/postfix/var/run/saslauthd"' > /etc/default/saslauthd + +# Enables Spamassassin and CRON updates +RUN sed -i -r 's/^(CRON|ENABLED)=0/\1=1/g' /etc/default/spamassassin + +# Enables Amavis +RUN sed -i -r 's/#(@| \\%)bypass/\1bypass/g' /etc/amavis/conf.d/15-content_filter_mode +RUN adduser clamav amavis +RUN adduser amavis clamav +RUN echo "/dev/shm /var/lib/amavis tmpfs defaults,noexec,nodev,nosuid,size=150m,mode=750,uid=$(id -u amavis),gid=$(id -g clamav) 0 0" >> /etc/fstab + +# Enables Clamav +RUN mkdir -p /var/log/clamav && chown -R clamav:root /var/log/clamav +RUN (crontab -l ; echo "0 1 * * * /usr/bin/freshclam --quiet") | sort - | uniq - | crontab - +RUN freshclam + +# Start-mailserver script +ADD start-mailserver.sh /usr/local/bin/start-mailserver.sh +RUN chmod +x /usr/local/bin/start-mailserver.sh +CMD /usr/local/bin/start-mailserver.sh + diff --git a/start-mailserver.sh b/start-mailserver.sh new file mode 100644 index 00000000..b247332f --- /dev/null +++ b/start-mailserver.sh @@ -0,0 +1,53 @@ +#!/bin/sh + +echo "Regenerating 'vmailbox' for given users" + +echo "docker_mail_users => $docker_mail_users" + +echo "# WARNING: this file is auto-generated. Do not modify locally" > /etc/postfix/vmailbox +while IFS=$'|' read -r login pass +do + # Setting variables for better readability + user=$(echo ${login} | cut -d @ -f1) + domain=$(echo ${login} | cut -d @ -f2) + + # Let's go! + echo "user '${user}' for domain '${domain}' with password '${pass}'" + echo "${login} ${domain}/${user}/" >> /etc/postfix/vmailbox + userdb ${login} set uid=5000 gid=5000 home=/var/mail/${domain}/${user} mail=/var/mail/${domain}/${user} + echo "${pass}" | userdbpw -md5 | userdb ${login} set systempw + echo "${pass}" | saslpasswd2 -p -c -u ${domain} ${login} + mkdir -p /var/mail/ifusio.com + maildirmake /var/mail/${domain}/${user} + +done < /etc/postfix/docker-mail-users +makeuserdb + +echo "Postmap configurations" +postmap /etc/postfix/vmailbox +postmap /etc/postfix/virtual + +echo "Fixing permissions" +chown -R 5000:5000 /var/mail + +echo "Creating /etc/mailname" +echo $docker_mail_domain > /etc/mailname + +# echo "Mouting /var/lib/amavis as tmpfs" +# mount /var/lib/amavis + +echo "Starting daemons" +/etc/init.d/fam start +/etc/init.d/saslauthd start +/etc/init.d/courier-authdaemon start +/etc/init.d/courier-imap start +/etc/init.d/spamassassin start +/etc/init.d/clamav-daemon start +/etc/init.d/amavis start +/etc/init.d/postfix start + +echo "Listing SASL users" +sasldblistusers2 + +echo "Starting supervisord" +tail -f /var/log/mail.log \ No newline at end of file From f97eaee38c5edaca00d685f051c3c92685be74f4 Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Sat, 28 Mar 2015 16:04:09 +0100 Subject: [PATCH 002/155] Added basic README. --- README.md | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 00000000..c66be9df --- /dev/null +++ b/README.md @@ -0,0 +1,30 @@ +# docker-mailserver + +## installation + +TODO when automatic build will be enabled. + +## build + + docker build -t tvial/docker-mailserver . + +## docker-compose template + + mail: + build: . + hostname: mail + domainname: my-domain.com + ports: + - "25:25" + - "143:143" + - "587:587" + - "993:993" + volumes: + - ./configs/courier:/etc/courier + - ./configs/postfix:/etc/postfix + - ./configs/spamassassin:/etc/spamassassin + environment: + docker_mail_domain: "my-domain.com" + docker_mail_users: + - "username1@my-domain.com|username1password" + - "username2@my-domain.com|username2password" \ No newline at end of file From 22a54827ff6be9919756e35009430287804d4ebd Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Sat, 28 Mar 2015 16:44:40 +0100 Subject: [PATCH 003/155] Working image. --- Dockerfile | 2 +- README.md | 20 ++++++++++++++++++-- start-mailserver.sh | 3 --- 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/Dockerfile b/Dockerfile index 51f64e90..f56e32a3 100644 --- a/Dockerfile +++ b/Dockerfile @@ -19,7 +19,7 @@ RUN sed -i -r 's/^(CRON|ENABLED)=0/\1=1/g' /etc/default/spamassassin RUN sed -i -r 's/#(@| \\%)bypass/\1bypass/g' /etc/amavis/conf.d/15-content_filter_mode RUN adduser clamav amavis RUN adduser amavis clamav -RUN echo "/dev/shm /var/lib/amavis tmpfs defaults,noexec,nodev,nosuid,size=150m,mode=750,uid=$(id -u amavis),gid=$(id -g clamav) 0 0" >> /etc/fstab +# RUN echo "/dev/shm /var/lib/amavis tmpfs defaults,noexec,nodev,nosuid,size=150m,mode=750,uid=$(id -u amavis),gid=$(id -g clamav) 0 0" >> /etc/fstab # Enables Clamav RUN mkdir -p /var/log/clamav && chown -R clamav:root /var/log/clamav diff --git a/README.md b/README.md index c66be9df..0e4e8933 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,19 @@ # docker-mailserver +A fullstack but simple mailserver (smtp, imap, antispam, antivirus...) + +Includes: +- postfix +- courier-imap +- spamassasin +- clamav +- amavis + +Only config files, no *sql database required. + ## installation -TODO when automatic build will be enabled. + docker pull tvial/docker-mailserver ## build @@ -25,6 +36,11 @@ TODO when automatic build will be enabled. - ./configs/spamassassin:/etc/spamassassin environment: docker_mail_domain: "my-domain.com" + # format is user@domain.tld|clear_password docker_mail_users: - "username1@my-domain.com|username1password" - - "username2@my-domain.com|username2password" \ No newline at end of file + - "username2@my-domain.com|username2password" + +# wanna help? + +Fork, improve and PR. ;-) \ No newline at end of file diff --git a/start-mailserver.sh b/start-mailserver.sh index b247332f..256f2031 100644 --- a/start-mailserver.sh +++ b/start-mailserver.sh @@ -33,9 +33,6 @@ chown -R 5000:5000 /var/mail echo "Creating /etc/mailname" echo $docker_mail_domain > /etc/mailname -# echo "Mouting /var/lib/amavis as tmpfs" -# mount /var/lib/amavis - echo "Starting daemons" /etc/init.d/fam start /etc/init.d/saslauthd start From 45b1d1e583922811f8a42bd8203ee9603cda4d81 Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Sat, 28 Mar 2015 19:30:09 +0100 Subject: [PATCH 004/155] Users parsing from env and not from static file anymore. --- README.md | 2 +- start-mailserver.sh | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 0e4e8933..ed66435c 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # docker-mailserver -A fullstack but simple mailserver (smtp, imap, antispam, antivirus...) +A fullstack but simple mail server (smtp, imap, antispam, antivirus...) Includes: - postfix diff --git a/start-mailserver.sh b/start-mailserver.sh index 256f2031..01d816f5 100644 --- a/start-mailserver.sh +++ b/start-mailserver.sh @@ -5,6 +5,7 @@ echo "Regenerating 'vmailbox' for given users" echo "docker_mail_users => $docker_mail_users" echo "# WARNING: this file is auto-generated. Do not modify locally" > /etc/postfix/vmailbox +echo $docker_mail_users | sed -r 's/\[|\]|\x27| //g' | sed -r 's/,/\n/g' > /tmp/docker_mail_users while IFS=$'|' read -r login pass do # Setting variables for better readability @@ -20,7 +21,8 @@ do mkdir -p /var/mail/ifusio.com maildirmake /var/mail/${domain}/${user} -done < /etc/postfix/docker-mail-users +done < /tmp/docker_mail_users +rm /tmp/docker_mail_users makeuserdb echo "Postmap configurations" From 9cd746ef333ac9b3d73ab5db5dcecff684ee1000 Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Sun, 29 Mar 2015 14:07:56 +0200 Subject: [PATCH 005/155] Simplified configurations --- Dockerfile | 8 +++++--- README.md | 4 ++-- start-mailserver.sh | 4 +++- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/Dockerfile b/Dockerfile index f56e32a3..83e651fd 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,7 +4,7 @@ MAINTAINER Thomas VIAL # Packages RUN apt-get update -q RUN apt-get -y upgrade -RUN DEBIAN_FRONTEND=noninteractive apt-get -y install postfix sasl2-bin courier-imap courier-authdaemon supervisor libfam0 fam amavisd-new spamassassin clamav-daemon libnet-dns-perl libmail-spf-perl pyzor razor arj bzip2 cabextract cpio file gzip nomarch pax unzip zip zoo +RUN DEBIAN_FRONTEND=noninteractive apt-get -y install postfix sasl2-bin courier-imap courier-authdaemon supervisor libfam0 fam amavisd-new spamassassin clamav-daemon libnet-dns-perl libmail-spf-perl pyzor razor arj bzip2 cabextract cpio file gzip nomarch pax unzip zip zoo rsyslog RUN apt-get autoclean # Configures Saslauthd @@ -12,6 +12,10 @@ RUN rm -rf /var/run/saslauthd && ln -s /var/spool/postfix/var/run/saslauthd /var RUN adduser postfix sasl RUN echo 'NAME="saslauthd"\nSTART=yes\nMECHANISMS="sasldb"\nTHREADS=0\nPWDIR=/var/spool/postfix/var/run/saslauthd\nPIDFILE="${PWDIR}/saslauthd.pid"\nOPTIONS="-n 0 -r -m /var/spool/postfix/var/run/saslauthd"' > /etc/default/saslauthd +# Configures Courier +RUN sed -i -r 's/daemons=5/daemons=0/g' /etc/courier/authdaemonrc +RUN sed -i -r 's/authmodulelist="authpam"/authmodulelist="authuserdb"/g' /etc/courier/authdaemonrc + # Enables Spamassassin and CRON updates RUN sed -i -r 's/^(CRON|ENABLED)=0/\1=1/g' /etc/default/spamassassin @@ -19,10 +23,8 @@ RUN sed -i -r 's/^(CRON|ENABLED)=0/\1=1/g' /etc/default/spamassassin RUN sed -i -r 's/#(@| \\%)bypass/\1bypass/g' /etc/amavis/conf.d/15-content_filter_mode RUN adduser clamav amavis RUN adduser amavis clamav -# RUN echo "/dev/shm /var/lib/amavis tmpfs defaults,noexec,nodev,nosuid,size=150m,mode=750,uid=$(id -u amavis),gid=$(id -g clamav) 0 0" >> /etc/fstab # Enables Clamav -RUN mkdir -p /var/log/clamav && chown -R clamav:root /var/log/clamav RUN (crontab -l ; echo "0 1 * * * /usr/bin/freshclam --quiet") | sort - | uniq - | crontab - RUN freshclam diff --git a/README.md b/README.md index ed66435c..1f9d001d 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,7 @@ A fullstack but simple mail server (smtp, imap, antispam, antivirus...) Includes: + - postfix - courier-imap - spamassasin @@ -23,6 +24,7 @@ Only config files, no *sql database required. mail: build: . + # or use 'image: tvial/docker-mailserver' hostname: mail domainname: my-domain.com ports: @@ -31,9 +33,7 @@ Only config files, no *sql database required. - "587:587" - "993:993" volumes: - - ./configs/courier:/etc/courier - ./configs/postfix:/etc/postfix - - ./configs/spamassassin:/etc/spamassassin environment: docker_mail_domain: "my-domain.com" # format is user@domain.tld|clear_password diff --git a/start-mailserver.sh b/start-mailserver.sh index 01d816f5..900d2b3f 100644 --- a/start-mailserver.sh +++ b/start-mailserver.sh @@ -31,11 +31,13 @@ postmap /etc/postfix/virtual echo "Fixing permissions" chown -R 5000:5000 /var/mail +mkdir -p /var/log/clamav && chown -R clamav:root /var/log/clamav echo "Creating /etc/mailname" echo $docker_mail_domain > /etc/mailname echo "Starting daemons" +/etc/init.d/rsyslog start /etc/init.d/fam start /etc/init.d/saslauthd start /etc/init.d/courier-authdaemon start @@ -48,5 +50,5 @@ echo "Starting daemons" echo "Listing SASL users" sasldblistusers2 -echo "Starting supervisord" +echo "Starting..." tail -f /var/log/mail.log \ No newline at end of file From b951fe41293fa6678957fe847814eb482cd1c555 Mon Sep 17 00:00:00 2001 From: ASKz Date: Tue, 31 Mar 2015 16:36:53 +0200 Subject: [PATCH 006/155] replaced ifusio.com by ${domain} --- start-mailserver.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/start-mailserver.sh b/start-mailserver.sh index 900d2b3f..edeaeeb8 100644 --- a/start-mailserver.sh +++ b/start-mailserver.sh @@ -18,7 +18,7 @@ do userdb ${login} set uid=5000 gid=5000 home=/var/mail/${domain}/${user} mail=/var/mail/${domain}/${user} echo "${pass}" | userdbpw -md5 | userdb ${login} set systempw echo "${pass}" | saslpasswd2 -p -c -u ${domain} ${login} - mkdir -p /var/mail/ifusio.com + mkdir -p /var/mail/${domain} maildirmake /var/mail/${domain}/${user} done < /tmp/docker_mail_users @@ -51,4 +51,4 @@ echo "Listing SASL users" sasldblistusers2 echo "Starting..." -tail -f /var/log/mail.log \ No newline at end of file +tail -f /var/log/mail.log From ef34462e34f2d6a46f8da9dc4c068c2186b8ea54 Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Tue, 31 Mar 2015 17:27:54 +0200 Subject: [PATCH 007/155] Added default postfix configuration files --- Dockerfile | 5 ++ postfix/main.cf | 62 ++++++++++++++++ postfix/master.cf | 158 ++++++++++++++++++++++++++++++++++++++++ postfix/sasl/smtpd.conf | 3 + 4 files changed, 228 insertions(+) create mode 100644 postfix/main.cf create mode 100644 postfix/master.cf create mode 100644 postfix/sasl/smtpd.conf diff --git a/Dockerfile b/Dockerfile index 83e651fd..2bcf0c42 100644 --- a/Dockerfile +++ b/Dockerfile @@ -28,6 +28,11 @@ RUN adduser amavis clamav RUN (crontab -l ; echo "0 1 * * * /usr/bin/freshclam --quiet") | sort - | uniq - | crontab - RUN freshclam +# Configures Postfix +ADD postfix/main.cf /etc/postfix/main.cf +ADD postfix/master.cf /etc/postfix/master.cf +ADD postfix/sasl/smtpd.conf /etc/postfix/sasl/smtpd.conf + # Start-mailserver script ADD start-mailserver.sh /usr/local/bin/start-mailserver.sh RUN chmod +x /usr/local/bin/start-mailserver.sh diff --git a/postfix/main.cf b/postfix/main.cf new file mode 100644 index 00000000..0c1f9e45 --- /dev/null +++ b/postfix/main.cf @@ -0,0 +1,62 @@ +# See /usr/share/postfix/main.cf.dist for a commented, more complete version + + +# Debian specific: Specifying a file name will cause the first +# line of that file to be used as the name. The Debian default +# is /etc/mailname. +# myorigin = /etc/mailname + +smtpd_banner = $myhostname ESMTP $mail_name (Ubuntu) +biff = no + +# appending .domain is the MUA's job. +append_dot_mydomain = no + +# Uncomment the next line to generate "delayed mail" warnings +#delay_warning_time = 4h + +readme_directory = no + +# TLS parameters +smtpd_tls_cert_file=/etc/ssl/certs/ssl-cert-snakeoil.pem +smtpd_tls_key_file=/etc/ssl/private/ssl-cert-snakeoil.key +smtpd_use_tls=yes +smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache +smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache + +# See /usr/share/doc/postfix/TLS_README.gz in the postfix-doc package for +# information on enabling SSL in the smtp client. + +myhostname = DOCKER_MAIL_DOMAIN +alias_maps = hash:/etc/aliases +alias_database = hash:/etc/aliases +mydestination = localhost.localdomain, localhost +relayhost = +mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128 +mailbox_size_limit = 0 +recipient_delimiter = + +inet_interfaces = all +inet_protocols = all + +smtpd_relay_restrictions = permit_mynetworks permit_sasl_authenticated defer_unauth_destination +smtpd_recipient_restrictions = permit_sasl_authenticated, permit_mynetworks, reject_unauth_destination +smtpd_client_restrictions = permit_mynetworks, permit_sasl_authenticated, reject_unauth_destination +smtpd_sender_restrictions = permit_mynetworks +smtpd_sasl_auth_enable = yes +smtpd_sasl_path = smtpd +cyrus_sasl_config_path = /etc/postfix/sasl +smtpd_sasl_type = cyrus +smtpd_sasl_security_options = noanonymous, noplaintext +broken_sasl_auth_clients = yes +smtpd_sasl_local_domain = $myhostname + +virtual_mailbox_base = /var/mail +virtual_mailbox_domains = /etc/postfix/vhost +virtual_mailbox_maps = hash:/etc/postfix/vmailbox +virtual_alias_maps = hash:/etc/postfix/virtual +virtual_uid_maps = static:5000 +virtual_gid_maps = static:5000 + +# Additional option for filtering +content_filter = smtp-amavis:[127.0.0.1]:10024 + diff --git a/postfix/master.cf b/postfix/master.cf new file mode 100644 index 00000000..dde27793 --- /dev/null +++ b/postfix/master.cf @@ -0,0 +1,158 @@ +# +# Postfix master process configuration file. For details on the format +# of the file, see the master(5) manual page (command: "man 5 master" or +# on-line: http://www.postfix.org/master.5.html). +# +# Do not forget to execute "postfix reload" after editing this file. +# +# ========================================================================== +# service type private unpriv chroot wakeup maxproc command + args +# (yes) (yes) (yes) (never) (100) +# ========================================================================== +smtp inet n - n - - smtpd +#smtp inet n - - - 1 postscreen +#smtpd pass - - - - - smtpd +#dnsblog unix - - - - 0 dnsblog +#tlsproxy unix - - - - 0 tlsproxy +submission inet n - n - - smtpd + -o syslog_name=postfix/submission + -o smtpd_tls_security_level=encrypt + -o smtpd_sasl_auth_enable=yes + -o smtpd_reject_unlisted_recipient=no + -o smtpd_sasl_authenticated_header=yes +# -o smtpd_client_restrictions=$mua_client_restrictions +# -o smtpd_helo_restrictions=$mua_helo_restrictions +# -o smtpd_sender_restrictions=$mua_sender_restrictions +# -o smtpd_recipient_restrictions= + -o smtpd_relay_restrictions=permit_sasl_authenticated,reject +# -o milter_macro_daemon_name=ORIGINATING +smtps inet n - n - - smtpd + -o syslog_name=postfix/smtps + -o smtpd_tls_wrappermode=yes + -o smtpd_sasl_auth_enable=yes +# -o smtpd_reject_unlisted_recipient=no + -o smtpd_client_restrictions=permit_sasl_authenticated,reject +# -o smtpd_helo_restrictions=$mua_helo_restrictions +# -o smtpd_sender_restrictions=$mua_sender_restrictions +# -o smtpd_recipient_restrictions= + -o smtpd_relay_restrictions=permit_sasl_authenticated,reject + -o milter_macro_daemon_name=ORIGINATING +#628 inet n - - - - qmqpd +pickup fifo n - - 60 1 pickup + -o content_filter= + -o receive_override_options=no_header_body_checks + +cleanup unix n - - - 0 cleanup +qmgr unix n - n 300 1 qmgr +#qmgr unix n - n 300 1 oqmgr +tlsmgr unix - - - 1000? 1 tlsmgr +rewrite unix - - - - - trivial-rewrite +bounce unix - - - - 0 bounce +defer unix - - - - 0 bounce +trace unix - - - - 0 bounce +verify unix - - - - 1 verify +flush unix n - - 1000? 0 flush +proxymap unix - - n - - proxymap +proxywrite unix - - n - 1 proxymap +smtp unix - - - - - smtp +relay unix - - - - - smtp +# -o smtp_helo_timeout=5 -o smtp_connect_timeout=5 +showq unix n - - - - showq +error unix - - - - - error +retry unix - - - - - error +discard unix - - - - - discard +local unix - n n - - local +virtual unix - n n - - virtual +lmtp unix - - - - - lmtp +anvil unix - - - - 1 anvil +scache unix - - - - 1 scache +# +# ==================================================================== +# Interfaces to non-Postfix software. Be sure to examine the manual +# pages of the non-Postfix software to find out what options it wants. +# +# Many of the following services use the Postfix pipe(8) delivery +# agent. See the pipe(8) man page for information about ${recipient} +# and other message envelope options. +# ==================================================================== +# +# maildrop. See the Postfix MAILDROP_README file for details. +# Also specify in main.cf: maildrop_destination_recipient_limit=1 +# +maildrop unix - n n - - pipe + flags=DRhu user=vmail argv=/usr/bin/maildrop -d ${recipient} +# +# ==================================================================== +# +# Recent Cyrus versions can use the existing "lmtp" master.cf entry. +# +# Specify in cyrus.conf: +# lmtp cmd="lmtpd -a" listen="localhost:lmtp" proto=tcp4 +# +# Specify in main.cf one or more of the following: +# mailbox_transport = lmtp:inet:localhost +# virtual_transport = lmtp:inet:localhost +# +# ==================================================================== +# +# Cyrus 2.1.5 (Amos Gouaux) +# Also specify in main.cf: cyrus_destination_recipient_limit=1 +# +#cyrus unix - n n - - pipe +# user=cyrus argv=/cyrus/bin/deliver -e -r ${sender} -m ${extension} ${user} +# +# ==================================================================== +# Old example of delivery via Cyrus. +# +#old-cyrus unix - n n - - pipe +# flags=R user=cyrus argv=/cyrus/bin/deliver -e -m ${extension} ${user} +# +# ==================================================================== +# +# See the Postfix UUCP_README file for configuration details. +# +uucp unix - n n - - pipe + flags=Fqhu user=uucp argv=uux -r -n -z -a$sender - $nexthop!rmail ($recipient) +# +# Other external delivery methods. +# +ifmail unix - n n - - pipe + flags=F user=ftn argv=/usr/lib/ifmail/ifmail -r $nexthop ($recipient) +bsmtp unix - n n - - pipe + flags=Fq. user=bsmtp argv=/usr/lib/bsmtp/bsmtp -t$nexthop -f$sender $recipient +scalemail-backend unix - n n - 2 pipe + flags=R user=scalemail argv=/usr/lib/scalemail/bin/scalemail-store ${nexthop} ${user} ${extension} +mailman unix - n n - - pipe + flags=FR user=list argv=/usr/lib/mailman/bin/postfix-to-mailman.py + ${nexthop} ${user} + + +# +# Amavis configuraiton +# + +smtp-amavis unix - - - - 2 smtp + -o smtp_data_done_timeout=1200 + -o smtp_send_xforward_command=yes + -o disable_dns_lookups=yes + -o max_use=20 + +127.0.0.1:10025 inet n - - - - smtpd + -o content_filter= + -o local_recipient_maps= + -o relay_recipient_maps= + -o smtpd_restriction_classes= + -o smtpd_delay_reject=no + -o smtpd_client_restrictions=permit_mynetworks,reject + -o smtpd_helo_restrictions= + -o smtpd_sender_restrictions= + -o smtpd_recipient_restrictions=permit_mynetworks,reject + -o smtpd_data_restrictions=reject_unauth_pipelining + -o smtpd_end_of_data_restrictions= + -o mynetworks=127.0.0.0/8 + -o smtpd_error_sleep_time=0 + -o smtpd_soft_error_limit=1001 + -o smtpd_hard_error_limit=1000 + -o smtpd_client_connection_count_limit=0 + -o smtpd_client_connection_rate_limit=0 + -o receive_override_options=no_header_body_checks,no_unknown_recipient_checks diff --git a/postfix/sasl/smtpd.conf b/postfix/sasl/smtpd.conf new file mode 100644 index 00000000..75293ec9 --- /dev/null +++ b/postfix/sasl/smtpd.conf @@ -0,0 +1,3 @@ +pwcheck_method: auxprop +mech_list: digest-md5 cram-md5 +log_level: 7 \ No newline at end of file From 188356237a51dc0e5e5d4640014839d1dbb79c25 Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Tue, 31 Mar 2015 17:28:13 +0200 Subject: [PATCH 008/155] Now postfix configuration is generic. --- README.md | 13 +++++++------ start-mailserver.sh | 5 +++-- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 1f9d001d..b138936e 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,19 @@ # docker-mailserver -A fullstack but simple mail server (smtp, imap, antispam, antivirus...) +A fullstack but simple mail server (smtp, imap, antispam, antivirus...) Includes: -- postfix +- postfix with smtp auth - courier-imap +- amavis - spamassasin - clamav -- amavis -Only config files, no *sql database required. +Additional informations: + +- only config files, no *sql database required +- mails are stored in `/var/mail/${domain}/${username}` ## installation @@ -32,8 +35,6 @@ Only config files, no *sql database required. - "143:143" - "587:587" - "993:993" - volumes: - - ./configs/postfix:/etc/postfix environment: docker_mail_domain: "my-domain.com" # format is user@domain.tld|clear_password diff --git a/start-mailserver.sh b/start-mailserver.sh index edeaeeb8..4a1754b3 100644 --- a/start-mailserver.sh +++ b/start-mailserver.sh @@ -25,9 +25,10 @@ done < /tmp/docker_mail_users rm /tmp/docker_mail_users makeuserdb -echo "Postmap configurations" +echo "Postfix configurations" +sed -i -r 's/DOCKER_MAIL_DOMAIN/$docker_mail_domain/g' /etc/postfix/main.cf postmap /etc/postfix/vmailbox -postmap /etc/postfix/virtual +[ -f /etc/postfix/virtual ] && postmap /etc/postfix/virtual echo "Fixing permissions" chown -R 5000:5000 /var/mail From ccca15792069dbb2e540e74ad86c0ac71f50a053 Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Tue, 31 Mar 2015 19:31:18 +0200 Subject: [PATCH 009/155] Added SSL for courier-imap using courier-imap-ssl. Fixed /etc/postfix/vhost issue. --- Dockerfile | 2 +- README.md | 4 +++- start-mailserver.sh | 7 +++++-- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/Dockerfile b/Dockerfile index 2bcf0c42..0086a918 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,7 +4,7 @@ MAINTAINER Thomas VIAL # Packages RUN apt-get update -q RUN apt-get -y upgrade -RUN DEBIAN_FRONTEND=noninteractive apt-get -y install postfix sasl2-bin courier-imap courier-authdaemon supervisor libfam0 fam amavisd-new spamassassin clamav-daemon libnet-dns-perl libmail-spf-perl pyzor razor arj bzip2 cabextract cpio file gzip nomarch pax unzip zip zoo rsyslog +RUN DEBIAN_FRONTEND=noninteractive apt-get -y install postfix sasl2-bin courier-imap courier-imap-ssl courier-authdaemon supervisor libfam0 fam amavisd-new spamassassin clamav-daemon libnet-dns-perl libmail-spf-perl pyzor razor arj bzip2 cabextract cpio file gzip nomarch pax unzip zip zoo rsyslog RUN apt-get autoclean # Configures Saslauthd diff --git a/README.md b/README.md index b138936e..159a4381 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ A fullstack but simple mail server (smtp, imap, antispam, antivirus...) Includes: - postfix with smtp auth -- courier-imap +- courier-imap with ssl support - amavis - spamassasin - clamav @@ -14,6 +14,8 @@ Additional informations: - only config files, no *sql database required - mails are stored in `/var/mail/${domain}/${username}` +- email login are full email address (`username1@my-domain.com`) +- ssl is strongly recommended ## installation diff --git a/start-mailserver.sh b/start-mailserver.sh index 4a1754b3..5a0e39bb 100644 --- a/start-mailserver.sh +++ b/start-mailserver.sh @@ -20,15 +20,17 @@ do echo "${pass}" | saslpasswd2 -p -c -u ${domain} ${login} mkdir -p /var/mail/${domain} maildirmake /var/mail/${domain}/${user} + echo ${domain} >> /tmp/vhost.tmp done < /tmp/docker_mail_users rm /tmp/docker_mail_users makeuserdb echo "Postfix configurations" -sed -i -r 's/DOCKER_MAIL_DOMAIN/$docker_mail_domain/g' /etc/postfix/main.cf postmap /etc/postfix/vmailbox -[ -f /etc/postfix/virtual ] && postmap /etc/postfix/virtual +touch /etc/postfix/virtual && postmap /etc/postfix/virtual +sed -i -r 's/DOCKER_MAIL_DOMAIN/'"$docker_mail_domain"'/g' /etc/postfix/main.cf +cat /tmp/vhost.tmp | sort | uniq >> /etc/postfix/vhost && rm /tmp/vhost.tmp echo "Fixing permissions" chown -R 5000:5000 /var/mail @@ -43,6 +45,7 @@ echo "Starting daemons" /etc/init.d/saslauthd start /etc/init.d/courier-authdaemon start /etc/init.d/courier-imap start +/etc/init.d/courier-imap-ssl start /etc/init.d/spamassassin start /etc/init.d/clamav-daemon start /etc/init.d/amavis start From 41c0285e0126a5060cf8dfcec52f08dcf9dc3605 Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Tue, 31 Mar 2015 22:21:44 +0200 Subject: [PATCH 010/155] Added information about issues. --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 159a4381..51357b5e 100644 --- a/README.md +++ b/README.md @@ -44,6 +44,11 @@ Additional informations: - "username1@my-domain.com|username1password" - "username2@my-domain.com|username2password" +# todo + +Things to do or to improve are stored on [Github](https://github.com/tomav/docker-mailserver/issues), some open by myself. +Feel free to improve this docker image. + # wanna help? Fork, improve and PR. ;-) \ No newline at end of file From 50e96ab406e0f6d4d5805c34fbdd513975d1e74a Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Tue, 31 Mar 2015 22:21:56 +0200 Subject: [PATCH 011/155] Fixed deprecated configuration about TLS --- postfix/main.cf | 36 +++++++++---------------- postfix/master.cf | 68 ++--------------------------------------------- 2 files changed, 14 insertions(+), 90 deletions(-) diff --git a/postfix/main.cf b/postfix/main.cf index 0c1f9e45..51a6b0cd 100644 --- a/postfix/main.cf +++ b/postfix/main.cf @@ -1,32 +1,11 @@ # See /usr/share/postfix/main.cf.dist for a commented, more complete version - -# Debian specific: Specifying a file name will cause the first -# line of that file to be used as the name. The Debian default -# is /etc/mailname. -# myorigin = /etc/mailname - smtpd_banner = $myhostname ESMTP $mail_name (Ubuntu) biff = no - -# appending .domain is the MUA's job. append_dot_mydomain = no - -# Uncomment the next line to generate "delayed mail" warnings -#delay_warning_time = 4h - readme_directory = no -# TLS parameters -smtpd_tls_cert_file=/etc/ssl/certs/ssl-cert-snakeoil.pem -smtpd_tls_key_file=/etc/ssl/private/ssl-cert-snakeoil.key -smtpd_use_tls=yes -smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache -smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache - -# See /usr/share/doc/postfix/TLS_README.gz in the postfix-doc package for -# information on enabling SSL in the smtp client. - +# Basic configuration myhostname = DOCKER_MAIL_DOMAIN alias_maps = hash:/etc/aliases alias_database = hash:/etc/aliases @@ -38,18 +17,27 @@ recipient_delimiter = + inet_interfaces = all inet_protocols = all +# TLS parameters +smtpd_tls_cert_file=/etc/ssl/certs/ssl-cert-snakeoil.pem +smtpd_tls_key_file=/etc/ssl/private/ssl-cert-snakeoil.key +smtpd_tls_security_level = may +smtpd_use_tls=yes smtpd_relay_restrictions = permit_mynetworks permit_sasl_authenticated defer_unauth_destination smtpd_recipient_restrictions = permit_sasl_authenticated, permit_mynetworks, reject_unauth_destination smtpd_client_restrictions = permit_mynetworks, permit_sasl_authenticated, reject_unauth_destination smtpd_sender_restrictions = permit_mynetworks +smtp_tls_security_level = may + +# SASL smtpd_sasl_auth_enable = yes smtpd_sasl_path = smtpd -cyrus_sasl_config_path = /etc/postfix/sasl smtpd_sasl_type = cyrus smtpd_sasl_security_options = noanonymous, noplaintext -broken_sasl_auth_clients = yes smtpd_sasl_local_domain = $myhostname +cyrus_sasl_config_path = /etc/postfix/sasl +broken_sasl_auth_clients = yes +# Mail directory virtual_mailbox_base = /var/mail virtual_mailbox_domains = /etc/postfix/vhost virtual_mailbox_maps = hash:/etc/postfix/vmailbox diff --git a/postfix/master.cf b/postfix/master.cf index dde27793..c782b3da 100644 --- a/postfix/master.cf +++ b/postfix/master.cf @@ -9,42 +9,24 @@ # service type private unpriv chroot wakeup maxproc command + args # (yes) (yes) (yes) (never) (100) # ========================================================================== + smtp inet n - n - - smtpd -#smtp inet n - - - 1 postscreen -#smtpd pass - - - - - smtpd -#dnsblog unix - - - - 0 dnsblog -#tlsproxy unix - - - - 0 tlsproxy submission inet n - n - - smtpd -o syslog_name=postfix/submission -o smtpd_tls_security_level=encrypt -o smtpd_sasl_auth_enable=yes -o smtpd_reject_unlisted_recipient=no -o smtpd_sasl_authenticated_header=yes -# -o smtpd_client_restrictions=$mua_client_restrictions -# -o smtpd_helo_restrictions=$mua_helo_restrictions -# -o smtpd_sender_restrictions=$mua_sender_restrictions -# -o smtpd_recipient_restrictions= -o smtpd_relay_restrictions=permit_sasl_authenticated,reject -# -o milter_macro_daemon_name=ORIGINATING -smtps inet n - n - - smtpd - -o syslog_name=postfix/smtps - -o smtpd_tls_wrappermode=yes - -o smtpd_sasl_auth_enable=yes -# -o smtpd_reject_unlisted_recipient=no -o smtpd_client_restrictions=permit_sasl_authenticated,reject -# -o smtpd_helo_restrictions=$mua_helo_restrictions -# -o smtpd_sender_restrictions=$mua_sender_restrictions -# -o smtpd_recipient_restrictions= -o smtpd_relay_restrictions=permit_sasl_authenticated,reject -o milter_macro_daemon_name=ORIGINATING -#628 inet n - - - - qmqpd pickup fifo n - - 60 1 pickup -o content_filter= -o receive_override_options=no_header_body_checks cleanup unix n - - - 0 cleanup qmgr unix n - n 300 1 qmgr -#qmgr unix n - n 300 1 oqmgr tlsmgr unix - - - 1000? 1 tlsmgr rewrite unix - - - - - trivial-rewrite bounce unix - - - - 0 bounce @@ -56,7 +38,6 @@ proxymap unix - - n - - proxymap proxywrite unix - - n - 1 proxymap smtp unix - - - - - smtp relay unix - - - - - smtp -# -o smtp_helo_timeout=5 -o smtp_connect_timeout=5 showq unix n - - - - showq error unix - - - - - error retry unix - - - - - error @@ -66,56 +47,11 @@ virtual unix - n n - - virtual lmtp unix - - - - - lmtp anvil unix - - - - 1 anvil scache unix - - - - 1 scache -# -# ==================================================================== -# Interfaces to non-Postfix software. Be sure to examine the manual -# pages of the non-Postfix software to find out what options it wants. -# -# Many of the following services use the Postfix pipe(8) delivery -# agent. See the pipe(8) man page for information about ${recipient} -# and other message envelope options. -# ==================================================================== -# -# maildrop. See the Postfix MAILDROP_README file for details. -# Also specify in main.cf: maildrop_destination_recipient_limit=1 -# + maildrop unix - n n - - pipe flags=DRhu user=vmail argv=/usr/bin/maildrop -d ${recipient} -# -# ==================================================================== -# -# Recent Cyrus versions can use the existing "lmtp" master.cf entry. -# -# Specify in cyrus.conf: -# lmtp cmd="lmtpd -a" listen="localhost:lmtp" proto=tcp4 -# -# Specify in main.cf one or more of the following: -# mailbox_transport = lmtp:inet:localhost -# virtual_transport = lmtp:inet:localhost -# -# ==================================================================== -# -# Cyrus 2.1.5 (Amos Gouaux) -# Also specify in main.cf: cyrus_destination_recipient_limit=1 -# -#cyrus unix - n n - - pipe -# user=cyrus argv=/cyrus/bin/deliver -e -r ${sender} -m ${extension} ${user} -# -# ==================================================================== -# Old example of delivery via Cyrus. -# -#old-cyrus unix - n n - - pipe -# flags=R user=cyrus argv=/cyrus/bin/deliver -e -m ${extension} ${user} -# -# ==================================================================== -# -# See the Postfix UUCP_README file for configuration details. -# uucp unix - n n - - pipe flags=Fqhu user=uucp argv=uux -r -n -z -a$sender - $nexthop!rmail ($recipient) -# -# Other external delivery methods. -# ifmail unix - n n - - pipe flags=F user=ftn argv=/usr/lib/ifmail/ifmail -r $nexthop ($recipient) bsmtp unix - n n - - pipe From 81c08b82d51ccd1c07f7a9830a1e88e1973f403d Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Sat, 2 May 2015 19:05:34 +0200 Subject: [PATCH 012/155] Added virtual aliases management using dedicated env variable. --- README.md | 7 +++++-- start-mailserver.sh | 40 ++++++++++++++++++++++++++-------------- 2 files changed, 31 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 51357b5e..ad3fd7a4 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,7 @@ Additional informations: - mails are stored in `/var/mail/${domain}/${username}` - email login are full email address (`username1@my-domain.com`) - ssl is strongly recommended +- do not add whitespace in `$docker_mail_users` or `$docker_mail_aliases` ## installation @@ -28,8 +29,7 @@ Additional informations: ## docker-compose template mail: - build: . - # or use 'image: tvial/docker-mailserver' + image: tvial/docker-mailserver hostname: mail domainname: my-domain.com ports: @@ -43,6 +43,9 @@ Additional informations: docker_mail_users: - "username1@my-domain.com|username1password" - "username2@my-domain.com|username2password" + docker_mail_aliases: + - "username1@my-domain.com|alias1,alias2,alias3" + - "username2@my-domain.com|alias4" # todo diff --git a/start-mailserver.sh b/start-mailserver.sh index 5a0e39bb..09ab63bf 100644 --- a/start-mailserver.sh +++ b/start-mailserver.sh @@ -2,30 +2,42 @@ echo "Regenerating 'vmailbox' for given users" -echo "docker_mail_users => $docker_mail_users" - echo "# WARNING: this file is auto-generated. Do not modify locally" > /etc/postfix/vmailbox echo $docker_mail_users | sed -r 's/\[|\]|\x27| //g' | sed -r 's/,/\n/g' > /tmp/docker_mail_users while IFS=$'|' read -r login pass do - # Setting variables for better readability - user=$(echo ${login} | cut -d @ -f1) - domain=$(echo ${login} | cut -d @ -f2) + # Setting variables for better readability + user=$(echo ${login} | cut -d @ -f1) + domain=$(echo ${login} | cut -d @ -f2) - # Let's go! - echo "user '${user}' for domain '${domain}' with password '${pass}'" - echo "${login} ${domain}/${user}/" >> /etc/postfix/vmailbox - userdb ${login} set uid=5000 gid=5000 home=/var/mail/${domain}/${user} mail=/var/mail/${domain}/${user} - echo "${pass}" | userdbpw -md5 | userdb ${login} set systempw - echo "${pass}" | saslpasswd2 -p -c -u ${domain} ${login} - mkdir -p /var/mail/${domain} - maildirmake /var/mail/${domain}/${user} - echo ${domain} >> /tmp/vhost.tmp + # Let's go! + echo "user '${user}' for domain '${domain}' with password '${pass}'" + echo "${login} ${domain}/${user}/" >> /etc/postfix/vmailbox + userdb ${login} set uid=5000 gid=5000 home=/var/mail/${domain}/${user} mail=/var/mail/${domain}/${user} + echo "${pass}" | userdbpw -md5 | userdb ${login} set systempw + echo "${pass}" | saslpasswd2 -p -c -u ${domain} ${login} + mkdir -p /var/mail/${domain} + maildirmake /var/mail/${domain}/${user} + echo ${domain} >> /tmp/vhost.tmp done < /tmp/docker_mail_users rm /tmp/docker_mail_users makeuserdb +echo "Regenerating 'virtual' for given aliases" +echo $docker_mail_aliases | sed -r 's/\[|\]|\x27|//g' | sed -r 's/, /\n/g' > /tmp/docker_mail_aliases +while IFS=$'|' read -r login aliases +do + arr=$(echo $aliases | tr "," "\n") + for alias in $arr + do + user=$(echo ${login} | cut -d @ -f1) + domain=$(echo ${login} | cut -d @ -f2) + echo "$alias@$domain redirects to $login" + echo "$alias@$domain\t$login" >> /etc/postfix/virtual + done +done < /tmp/docker_mail_aliases + echo "Postfix configurations" postmap /etc/postfix/vmailbox touch /etc/postfix/virtual && postmap /etc/postfix/virtual From 1146423751481eb5b15f0d1ec597481da08ea50b Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Sat, 2 May 2015 19:06:20 +0200 Subject: [PATCH 013/155] Added docker-compose.yml example file. --- docker-compose.yml | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 docker-compose.yml diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 00000000..7b89291f --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,20 @@ +mail: + # image: tvial/docker-mailserver + build: . + hostname: mail + domainname: my-domain.com + ports: + - "25:25" + - "143:143" + - "587:587" + - "993:993" + environment: + docker_mail_domain: "my-domain.com" + # format is user@domain.tld|clear_password + docker_mail_users: + - "username1@my-domain.com|username1password" + - "username2@my-domain.com|username2password" + # format is user@domain.tld|list,of,aliases,comma,separated + docker_mail_aliases: + - "username1@my-domain.com|alias1,alias2,alias3" + - "username2@my-domain.com|alias4" \ No newline at end of file From 806519e6cf9f27fdd5f6c9c53dab3c587d0323de Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Sat, 2 May 2015 19:07:51 +0200 Subject: [PATCH 014/155] Added comment in README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index ad3fd7a4..aac74d78 100644 --- a/README.md +++ b/README.md @@ -43,6 +43,7 @@ Additional informations: docker_mail_users: - "username1@my-domain.com|username1password" - "username2@my-domain.com|username2password" + # format is user@domain.tld|list,of,aliases,comma,separated docker_mail_aliases: - "username1@my-domain.com|alias1,alias2,alias3" - "username2@my-domain.com|alias4" From 3fbe48fad55f5b8aa77897c9de3e45138f1e9df7 Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Wed, 6 May 2015 00:12:36 +0200 Subject: [PATCH 015/155] Fixes #5 => added how to run without docker-compose --- README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index aac74d78..c64066c9 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,11 @@ Additional informations: docker build -t tvial/docker-mailserver . -## docker-compose template +## run + + docker run -p "25:25" -p "143:143" -p "587:587" -p "993:993" -e docker_mail_users="username1@my-domain.com|username1password" -h mail.my-domain.com -e docker_mail_domain=my-domain.com -t tvial/docker-mailserver + +## docker-compose template (recommended) mail: image: tvial/docker-mailserver From 70a0649f4f23cab584a61c53137849d4f8a1870b Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Fri, 22 May 2015 14:40:00 +0200 Subject: [PATCH 016/155] Added Licence --- LICENCE | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 LICENCE diff --git a/LICENCE b/LICENCE new file mode 100644 index 00000000..f5e4ffb1 --- /dev/null +++ b/LICENCE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2015 Thomas VIAL + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. From 72d10ea14d223c35b1ed5091a5004d04bc529cf8 Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Mon, 29 Jun 2015 14:55:02 +0200 Subject: [PATCH 017/155] Renamed to .dist --- .gitignore | 2 ++ docker-compose.yml.dist | 20 ++++++++++++++++++++ 2 files changed, 22 insertions(+) create mode 100644 .gitignore create mode 100644 docker-compose.yml.dist diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..8f6d2801 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.DS_Store +docker-compose.yml \ No newline at end of file diff --git a/docker-compose.yml.dist b/docker-compose.yml.dist new file mode 100644 index 00000000..7b89291f --- /dev/null +++ b/docker-compose.yml.dist @@ -0,0 +1,20 @@ +mail: + # image: tvial/docker-mailserver + build: . + hostname: mail + domainname: my-domain.com + ports: + - "25:25" + - "143:143" + - "587:587" + - "993:993" + environment: + docker_mail_domain: "my-domain.com" + # format is user@domain.tld|clear_password + docker_mail_users: + - "username1@my-domain.com|username1password" + - "username2@my-domain.com|username2password" + # format is user@domain.tld|list,of,aliases,comma,separated + docker_mail_aliases: + - "username1@my-domain.com|alias1,alias2,alias3" + - "username2@my-domain.com|alias4" \ No newline at end of file From 1e19ca515e8d4ce128c2d4242fbed5d6772fa413 Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Mon, 29 Jun 2015 14:55:54 +0200 Subject: [PATCH 018/155] Improved documentation (added client configuration) --- README.md | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index c64066c9..d3b584b6 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ # docker-mailserver -A fullstack but simple mail server (smtp, imap, antispam, antivirus...) +A fullstack but simple mail server (smtp, imap, antispam, antivirus...). +Only configuration files, no SQL database. Keep it simple and versioned. +Easy to deploy and upgrade. Includes: @@ -8,7 +10,7 @@ Includes: - courier-imap with ssl support - amavis - spamassasin -- clamav +- clamav with automatic updates Additional informations: @@ -52,6 +54,25 @@ Additional informations: - "username1@my-domain.com|alias1,alias2,alias3" - "username2@my-domain.com|alias4" + # usage + docker-compose up -d mail + +# client configuration + + # imap + username: + password: + server: + imap port: 143 or 993 with ssl (recommended) + imap path prefix: INBOX + auth method: md5 challenge-response + + # smtp + smtp port: 25 or 587 with ssl (recommended) + username: + password: + auth method: md5 challenge-response + # todo Things to do or to improve are stored on [Github](https://github.com/tomav/docker-mailserver/issues), some open by myself. @@ -59,4 +80,4 @@ Feel free to improve this docker image. # wanna help? -Fork, improve and PR. ;-) \ No newline at end of file +Fork, improve and PR. ;-) From 09cd6cbeda290fd6415b8c01feaae275184a877b Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Mon, 29 Jun 2015 14:56:18 +0200 Subject: [PATCH 019/155] Renamed to .dist --- docker-compose.yml | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 7b89291f..a76204c0 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -2,19 +2,18 @@ mail: # image: tvial/docker-mailserver build: . hostname: mail - domainname: my-domain.com + domainname: cloudmailer.nl ports: - "25:25" - "143:143" - "587:587" - "993:993" environment: - docker_mail_domain: "my-domain.com" + docker_mail_domain: "cloudmailer.nl" # format is user@domain.tld|clear_password docker_mail_users: - - "username1@my-domain.com|username1password" - - "username2@my-domain.com|username2password" + - "info@cloudmailer.nl|secret!" + - "bounce@cloudmailer.nl|secret!" # format is user@domain.tld|list,of,aliases,comma,separated docker_mail_aliases: - - "username1@my-domain.com|alias1,alias2,alias3" - - "username2@my-domain.com|alias4" \ No newline at end of file + - "info@cloudmailer.nl|support" \ No newline at end of file From 31b9dbf05a138567e7167ab0f60a19534e9168c8 Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Mon, 29 Jun 2015 14:57:08 +0200 Subject: [PATCH 020/155] Improved markdown style. --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index d3b584b6..4cbd9b03 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ # docker-mailserver -A fullstack but simple mail server (smtp, imap, antispam, antivirus...). -Only configuration files, no SQL database. Keep it simple and versioned. -Easy to deploy and upgrade. +A fullstack but simple mail server (smtp, imap, antispam, antivirus...). +Only configuration files, no SQL database. Keep it simple and versioned. +Easy to deploy and upgrade. Includes: From 3dcceaef0cd89dc89af520d8c52ea27dfc648774 Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Wed, 1 Jul 2015 14:10:04 +0200 Subject: [PATCH 021/155] Changed permission to allow editing --- Dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/Dockerfile b/Dockerfile index 0086a918..96b1953a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -25,6 +25,7 @@ RUN adduser clamav amavis RUN adduser amavis clamav # Enables Clamav +RUN chmod 644 /etc/clamav/freshclam.conf RUN (crontab -l ; echo "0 1 * * * /usr/bin/freshclam --quiet") | sort - | uniq - | crontab - RUN freshclam From f2e52c32928444d4975f4f75d4412702de71ec80 Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Wed, 1 Jul 2015 14:10:29 +0200 Subject: [PATCH 022/155] Improvement on aliases management --- start-mailserver.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/start-mailserver.sh b/start-mailserver.sh index 09ab63bf..4b3ddf65 100644 --- a/start-mailserver.sh +++ b/start-mailserver.sh @@ -26,6 +26,7 @@ makeuserdb echo "Regenerating 'virtual' for given aliases" echo $docker_mail_aliases | sed -r 's/\[|\]|\x27|//g' | sed -r 's/, /\n/g' > /tmp/docker_mail_aliases +echo "" > /etc/postfix/virtual while IFS=$'|' read -r login aliases do arr=$(echo $aliases | tr "," "\n") @@ -37,6 +38,7 @@ do echo "$alias@$domain\t$login" >> /etc/postfix/virtual done done < /tmp/docker_mail_aliases +rm /tmp/docker_mail_aliases echo "Postfix configurations" postmap /etc/postfix/vmailbox From f0ad3151a9844df55bcbaee5a8593ecaa8748bfb Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Wed, 1 Jul 2015 14:10:52 +0200 Subject: [PATCH 023/155] Text formating --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4cbd9b03..e0640c9e 100644 --- a/README.md +++ b/README.md @@ -64,7 +64,7 @@ Additional informations: password: server: imap port: 143 or 993 with ssl (recommended) - imap path prefix: INBOX + imap path prefix: INBOX auth method: md5 challenge-response # smtp From a3634190b01611b5a794b5323a044ae377e94357 Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Sat, 4 Jul 2015 15:54:26 +0200 Subject: [PATCH 024/155] Added vim. --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 96b1953a..566d16b1 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,7 +4,7 @@ MAINTAINER Thomas VIAL # Packages RUN apt-get update -q RUN apt-get -y upgrade -RUN DEBIAN_FRONTEND=noninteractive apt-get -y install postfix sasl2-bin courier-imap courier-imap-ssl courier-authdaemon supervisor libfam0 fam amavisd-new spamassassin clamav-daemon libnet-dns-perl libmail-spf-perl pyzor razor arj bzip2 cabextract cpio file gzip nomarch pax unzip zip zoo rsyslog +RUN DEBIAN_FRONTEND=noninteractive apt-get -y install vim postfix sasl2-bin courier-imap courier-imap-ssl courier-authdaemon supervisor libfam0 fam amavisd-new spamassassin clamav-daemon libnet-dns-perl libmail-spf-perl pyzor razor arj bzip2 cabextract cpio file gzip nomarch pax unzip zip zoo rsyslog RUN apt-get autoclean # Configures Saslauthd From b4a07a21be2dd41d7bb7c70f0eb1922995e44daf Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Sat, 4 Jul 2015 15:54:40 +0200 Subject: [PATCH 025/155] Added spamassassin configuration. --- start-mailserver.sh | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/start-mailserver.sh b/start-mailserver.sh index 4b3ddf65..ff7f3dfe 100644 --- a/start-mailserver.sh +++ b/start-mailserver.sh @@ -26,7 +26,6 @@ makeuserdb echo "Regenerating 'virtual' for given aliases" echo $docker_mail_aliases | sed -r 's/\[|\]|\x27|//g' | sed -r 's/, /\n/g' > /tmp/docker_mail_aliases -echo "" > /etc/postfix/virtual while IFS=$'|' read -r login aliases do arr=$(echo $aliases | tr "," "\n") @@ -53,6 +52,12 @@ mkdir -p /var/log/clamav && chown -R clamav:root /var/log/clamav echo "Creating /etc/mailname" echo $docker_mail_domain > /etc/mailname +echo "Configuring Spamassassin" +echo "required_hits 5.0" >> /etc/mail/spamassassin/local.cf +echo "report_safe 0" >> /etc/mail/spamassassin/local.cf +echo "required_score 5" >> /etc/mail/spamassassin/local.cf +echo "rewrite_header Subject ***SPAM***" >> /etc/mail/spamassassin/local.cf + echo "Starting daemons" /etc/init.d/rsyslog start /etc/init.d/fam start From f79da1d3f7c99edeb9f13b75561d380c32df2515 Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Sat, 4 Jul 2015 15:55:26 +0200 Subject: [PATCH 026/155] Added newline --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 8f6d2801..423d89e9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,2 @@ .DS_Store -docker-compose.yml \ No newline at end of file +docker-compose.yml From 320156439fd00ed92d342159ea5949e65cf01803 Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Thu, 16 Jul 2015 19:35:11 +0200 Subject: [PATCH 027/155] Fixes #8 - BC BREAK - User configuration is no longer in docker-compose.yml to make it easier to maintain --- Dockerfile | 2 +- README.md | 25 +++++++++++++------------ docker-compose.yml.dist | 11 +++-------- postfix/accounts.cf | 1 + spamassassin/rules.cf | 1 + start-mailserver.sh | 32 ++++++++++++++------------------ 6 files changed, 33 insertions(+), 39 deletions(-) create mode 100644 postfix/accounts.cf create mode 100644 spamassassin/rules.cf diff --git a/Dockerfile b/Dockerfile index 566d16b1..9dad19b3 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,7 +2,7 @@ FROM ubuntu:14.04 MAINTAINER Thomas VIAL # Packages -RUN apt-get update -q +RUN apt-get update -q --fix-missing RUN apt-get -y upgrade RUN DEBIAN_FRONTEND=noninteractive apt-get -y install vim postfix sasl2-bin courier-imap courier-imap-ssl courier-authdaemon supervisor libfam0 fam amavisd-new spamassassin clamav-daemon libnet-dns-perl libmail-spf-perl pyzor razor arj bzip2 cabextract cpio file gzip nomarch pax unzip zip zoo rsyslog RUN apt-get autoclean diff --git a/README.md b/README.md index e0640c9e..4c2bf662 100644 --- a/README.md +++ b/README.md @@ -30,12 +30,13 @@ Additional informations: ## run - docker run -p "25:25" -p "143:143" -p "587:587" -p "993:993" -e docker_mail_users="username1@my-domain.com|username1password" -h mail.my-domain.com -e docker_mail_domain=my-domain.com -t tvial/docker-mailserver + docker run -p "25:25" -p "143:143" -p "587:587" -p "993:993" -e docker_mail_domain=my-domain.com -t tvial/docker-mailserver ## docker-compose template (recommended) mail: - image: tvial/docker-mailserver + # image: tvial/docker-mailserver + build: . hostname: mail domainname: my-domain.com ports: @@ -45,17 +46,17 @@ Additional informations: - "993:993" environment: docker_mail_domain: "my-domain.com" - # format is user@domain.tld|clear_password - docker_mail_users: - - "username1@my-domain.com|username1password" - - "username2@my-domain.com|username2password" - # format is user@domain.tld|list,of,aliases,comma,separated - docker_mail_aliases: - - "username1@my-domain.com|alias1,alias2,alias3" - - "username2@my-domain.com|alias4" + volumes: + - ./spamassassin:/tmp/spamassassin/:ro + - ./postfix:/tmp/postfix/:ro - # usage - docker-compose up -d mail +Volumes allow to: + +- Insert custom antispam rules +- Manage mail users, passwords and aliases + +# usage +docker-compose up -d mail # client configuration diff --git a/docker-compose.yml.dist b/docker-compose.yml.dist index 7b89291f..2dc2afe6 100644 --- a/docker-compose.yml.dist +++ b/docker-compose.yml.dist @@ -10,11 +10,6 @@ mail: - "993:993" environment: docker_mail_domain: "my-domain.com" - # format is user@domain.tld|clear_password - docker_mail_users: - - "username1@my-domain.com|username1password" - - "username2@my-domain.com|username2password" - # format is user@domain.tld|list,of,aliases,comma,separated - docker_mail_aliases: - - "username1@my-domain.com|alias1,alias2,alias3" - - "username2@my-domain.com|alias4" \ No newline at end of file + volumes: + - ./spamassassin:/tmp/spamassassin/:ro + - ./postfix:/tmp/postfix/:ro diff --git a/postfix/accounts.cf b/postfix/accounts.cf new file mode 100644 index 00000000..1489b4d7 --- /dev/null +++ b/postfix/accounts.cf @@ -0,0 +1 @@ +user@domain.tld|mypassword|alias1,alias2 \ No newline at end of file diff --git a/spamassassin/rules.cf b/spamassassin/rules.cf new file mode 100644 index 00000000..891e84ff --- /dev/null +++ b/spamassassin/rules.cf @@ -0,0 +1 @@ +# Place you custom Spamassasin rules here \ No newline at end of file diff --git a/start-mailserver.sh b/start-mailserver.sh index ff7f3dfe..d4f07b01 100644 --- a/start-mailserver.sh +++ b/start-mailserver.sh @@ -1,17 +1,20 @@ #!/bin/sh -echo "Regenerating 'vmailbox' for given users" - +echo "Regenerating postfix 'vmailbox' and 'virtual' for given users" +# rm /etc/postfix/virtual +# rm /etc/postfix/virtual.db +# rm /etc/postfix/vmailbox +# rm /etc/postfix/vmailbox.db echo "# WARNING: this file is auto-generated. Do not modify locally" > /etc/postfix/vmailbox -echo $docker_mail_users | sed -r 's/\[|\]|\x27| //g' | sed -r 's/,/\n/g' > /tmp/docker_mail_users -while IFS=$'|' read -r login pass +while IFS=$'|' read -r login pass aliases do + # Setting variables for better readability user=$(echo ${login} | cut -d @ -f1) domain=$(echo ${login} | cut -d @ -f2) # Let's go! - echo "user '${user}' for domain '${domain}' with password '${pass}'" + echo "user '${user}' for domain '${domain}' with password '********'" echo "${login} ${domain}/${user}/" >> /etc/postfix/vmailbox userdb ${login} set uid=5000 gid=5000 home=/var/mail/${domain}/${user} mail=/var/mail/${domain}/${user} echo "${pass}" | userdbpw -md5 | userdb ${login} set systempw @@ -20,28 +23,20 @@ do maildirmake /var/mail/${domain}/${user} echo ${domain} >> /tmp/vhost.tmp -done < /tmp/docker_mail_users -rm /tmp/docker_mail_users -makeuserdb - -echo "Regenerating 'virtual' for given aliases" -echo $docker_mail_aliases | sed -r 's/\[|\]|\x27|//g' | sed -r 's/, /\n/g' > /tmp/docker_mail_aliases -while IFS=$'|' read -r login aliases -do + # Aliases arr=$(echo $aliases | tr "," "\n") for alias in $arr do - user=$(echo ${login} | cut -d @ -f1) - domain=$(echo ${login} | cut -d @ -f2) echo "$alias@$domain redirects to $login" echo "$alias@$domain\t$login" >> /etc/postfix/virtual done -done < /tmp/docker_mail_aliases -rm /tmp/docker_mail_aliases + +done < /tmp/postfix/accounts.cf +makeuserdb echo "Postfix configurations" postmap /etc/postfix/vmailbox -touch /etc/postfix/virtual && postmap /etc/postfix/virtual +postmap /etc/postfix/virtual sed -i -r 's/DOCKER_MAIL_DOMAIN/'"$docker_mail_domain"'/g' /etc/postfix/main.cf cat /tmp/vhost.tmp | sort | uniq >> /etc/postfix/vhost && rm /tmp/vhost.tmp @@ -57,6 +52,7 @@ echo "required_hits 5.0" >> /etc/mail/spamassassin/local.cf echo "report_safe 0" >> /etc/mail/spamassassin/local.cf echo "required_score 5" >> /etc/mail/spamassassin/local.cf echo "rewrite_header Subject ***SPAM***" >> /etc/mail/spamassassin/local.cf +cp /tmp/spamassassin/rules.cf /etc/spamassassin/ echo "Starting daemons" /etc/init.d/rsyslog start From 51775c80209f4962ea4d7911cb69c27835424d57 Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Mon, 27 Jul 2015 10:00:53 +0200 Subject: [PATCH 028/155] Improved documentation to fix #9 --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 4c2bf662..c2505524 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,9 @@ Additional informations: - email login are full email address (`username1@my-domain.com`) - ssl is strongly recommended - do not add whitespace in `$docker_mail_users` or `$docker_mail_aliases` +- user accounts are managed in `./postfix/accounts.cf` +- antispam are rules are managed in `./spamassassin/rules.cf` +- both files must be mounted to `/tmp` in your container (see `docker-compose.yml` template) ## installation From 63caae1e251413824e2b80c685d748f629d426a1 Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Tue, 28 Jul 2015 15:12:50 +0200 Subject: [PATCH 029/155] Renamed to .dist --- docker-compose.yml | 19 ------------------- 1 file changed, 19 deletions(-) delete mode 100644 docker-compose.yml diff --git a/docker-compose.yml b/docker-compose.yml deleted file mode 100644 index a76204c0..00000000 --- a/docker-compose.yml +++ /dev/null @@ -1,19 +0,0 @@ -mail: - # image: tvial/docker-mailserver - build: . - hostname: mail - domainname: cloudmailer.nl - ports: - - "25:25" - - "143:143" - - "587:587" - - "993:993" - environment: - docker_mail_domain: "cloudmailer.nl" - # format is user@domain.tld|clear_password - docker_mail_users: - - "info@cloudmailer.nl|secret!" - - "bounce@cloudmailer.nl|secret!" - # format is user@domain.tld|list,of,aliases,comma,separated - docker_mail_aliases: - - "info@cloudmailer.nl|support" \ No newline at end of file From 23362190a8db7b04ebe602bdaf1cefb7d3719501 Mon Sep 17 00:00:00 2001 From: egavard Date: Wed, 5 Aug 2015 11:58:10 +0200 Subject: [PATCH 030/155] Trying to separate virtuals from accounts --- postfix/accounts.cf | 2 +- postfix/redirects.cf | 1 + start-mailserver.sh | 10 +++++++++- 3 files changed, 11 insertions(+), 2 deletions(-) create mode 100644 postfix/redirects.cf diff --git a/postfix/accounts.cf b/postfix/accounts.cf index 1489b4d7..94896e0d 100644 --- a/postfix/accounts.cf +++ b/postfix/accounts.cf @@ -1 +1 @@ -user@domain.tld|mypassword|alias1,alias2 \ No newline at end of file +user@domain.tld|mypassword \ No newline at end of file diff --git a/postfix/redirects.cf b/postfix/redirects.cf new file mode 100644 index 00000000..40eaea6a --- /dev/null +++ b/postfix/redirects.cf @@ -0,0 +1 @@ +user@domain.tld | otheruser@domain.tld otheruser@otherdomain.tld \ No newline at end of file diff --git a/start-mailserver.sh b/start-mailserver.sh index d4f07b01..c85191b0 100644 --- a/start-mailserver.sh +++ b/start-mailserver.sh @@ -6,7 +6,8 @@ echo "Regenerating postfix 'vmailbox' and 'virtual' for given users" # rm /etc/postfix/vmailbox # rm /etc/postfix/vmailbox.db echo "# WARNING: this file is auto-generated. Do not modify locally" > /etc/postfix/vmailbox -while IFS=$'|' read -r login pass aliases +# Creating users +while IFS=$'|' read -r login pass do # Setting variables for better readability @@ -33,6 +34,13 @@ do done < /tmp/postfix/accounts.cf makeuserdb +#creating virtuals +while IFS=$'|' read -r from to +do + echo "from : '$from' aliases: '$to'" + # Let's go! + echo "$from\t$to" >> /etc/postfix/virtual +done < /tmp/postfix/redirects.cf echo "Postfix configurations" postmap /etc/postfix/vmailbox From 5abadead333ae663a059cc62462d6fe86d359f69 Mon Sep 17 00:00:00 2001 From: egavard Date: Wed, 5 Aug 2015 12:09:24 +0200 Subject: [PATCH 031/155] Virtuals to must be separated with comma in order to be used directly. --- postfix/redirects.cf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/postfix/redirects.cf b/postfix/redirects.cf index 40eaea6a..c29ec5cc 100644 --- a/postfix/redirects.cf +++ b/postfix/redirects.cf @@ -1 +1 @@ -user@domain.tld | otheruser@domain.tld otheruser@otherdomain.tld \ No newline at end of file +user@domain.tld | otheruser@domain.tld,otheruser@otherdomain.tld \ No newline at end of file From b057ad2170ab6046c63d0d26de5d0c80c951eb11 Mon Sep 17 00:00:00 2001 From: egavard Date: Wed, 5 Aug 2015 12:09:53 +0200 Subject: [PATCH 032/155] Modified warning in virtual and vmailbox --- start-mailserver.sh | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/start-mailserver.sh b/start-mailserver.sh index c85191b0..dcac9d69 100644 --- a/start-mailserver.sh +++ b/start-mailserver.sh @@ -5,7 +5,8 @@ echo "Regenerating postfix 'vmailbox' and 'virtual' for given users" # rm /etc/postfix/virtual.db # rm /etc/postfix/vmailbox # rm /etc/postfix/vmailbox.db -echo "# WARNING: this file is auto-generated. Do not modify locally" > /etc/postfix/vmailbox +echo "# WARNING: this file is auto-generated. Modify accounts.cf in postfix directory on host" > /etc/postfix/vmailbox +echo "# WARNING: this file is auto-generated. Modify redirects.cf in postfix directory on host" > /etc/postfix/virtual # Creating users while IFS=$'|' read -r login pass do @@ -23,17 +24,9 @@ do mkdir -p /var/mail/${domain} maildirmake /var/mail/${domain}/${user} echo ${domain} >> /tmp/vhost.tmp - - # Aliases - arr=$(echo $aliases | tr "," "\n") - for alias in $arr - do - echo "$alias@$domain redirects to $login" - echo "$alias@$domain\t$login" >> /etc/postfix/virtual - done - done < /tmp/postfix/accounts.cf makeuserdb + #creating virtuals while IFS=$'|' read -r from to do From bf8fc5949d689ed865bfbc445cd25b6c5ad78dc7 Mon Sep 17 00:00:00 2001 From: egavard Date: Wed, 5 Aug 2015 13:29:05 +0200 Subject: [PATCH 033/155] Updated accounts and redirects cf files --- postfix/accounts.cf | 2 +- postfix/redirects.cf | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/postfix/accounts.cf b/postfix/accounts.cf index 94896e0d..ecb0f063 100644 --- a/postfix/accounts.cf +++ b/postfix/accounts.cf @@ -1 +1 @@ -user@domain.tld|mypassword \ No newline at end of file +user@domain.tld|mypassword diff --git a/postfix/redirects.cf b/postfix/redirects.cf index c29ec5cc..492eb3a0 100644 --- a/postfix/redirects.cf +++ b/postfix/redirects.cf @@ -1 +1 @@ -user@domain.tld | otheruser@domain.tld,otheruser@otherdomain.tld \ No newline at end of file +user@domain.tld|otheruser@domain.tld,otheruser@otherdomain.tld From 15835a0ead114f54d33de27a042374754b9ae888 Mon Sep 17 00:00:00 2001 From: GAVARD Ewann Date: Wed, 5 Aug 2015 13:35:22 +0200 Subject: [PATCH 034/155] Update README.md --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index c2505524..d124ffd0 100644 --- a/README.md +++ b/README.md @@ -20,8 +20,9 @@ Additional informations: - ssl is strongly recommended - do not add whitespace in `$docker_mail_users` or `$docker_mail_aliases` - user accounts are managed in `./postfix/accounts.cf` +- redirections are managed in `./postfix/redirects.cf` - antispam are rules are managed in `./spamassassin/rules.cf` -- both files must be mounted to `/tmp` in your container (see `docker-compose.yml` template) +- files must be mounted to `/tmp` in your container (see `docker-compose.yml` template) ## installation From 3eb0a13b37f10c888cf13f4e23903bdba46cd071 Mon Sep 17 00:00:00 2001 From: egavard Date: Thu, 6 Aug 2015 10:54:22 +0200 Subject: [PATCH 035/155] Now using virtual file directly from /tmp/postfix folder. --- postfix/redirects.cf | 1 - postfix/virtual | 4 ++++ start-mailserver.sh | 10 ++-------- 3 files changed, 6 insertions(+), 9 deletions(-) delete mode 100644 postfix/redirects.cf create mode 100644 postfix/virtual diff --git a/postfix/redirects.cf b/postfix/redirects.cf deleted file mode 100644 index c29ec5cc..00000000 --- a/postfix/redirects.cf +++ /dev/null @@ -1 +0,0 @@ -user@domain.tld | otheruser@domain.tld,otheruser@otherdomain.tld \ No newline at end of file diff --git a/postfix/virtual b/postfix/virtual new file mode 100644 index 00000000..9fc19fb0 --- /dev/null +++ b/postfix/virtual @@ -0,0 +1,4 @@ +#Mail redirection from user@domain.tld to otheruser@domain.tld and otheruser@otherdomain.tld +user@domain.tld|otheruser@domain.tld,otheruser@otherdomain.tld +#Mail redirection from postmaster@domain.tld and hostmaster@domain.tld to user@domain.tld +user@domain.tld| postmaster,hostmaster \ No newline at end of file diff --git a/start-mailserver.sh b/start-mailserver.sh index dcac9d69..ba6ab200 100644 --- a/start-mailserver.sh +++ b/start-mailserver.sh @@ -27,14 +27,8 @@ do done < /tmp/postfix/accounts.cf makeuserdb -#creating virtuals -while IFS=$'|' read -r from to -do - echo "from : '$from' aliases: '$to'" - # Let's go! - echo "$from\t$to" >> /etc/postfix/virtual -done < /tmp/postfix/redirects.cf - +#creating virtuals and redirects +cp /tmp/postfix/virtual /etc/postfix/virtual echo "Postfix configurations" postmap /etc/postfix/vmailbox postmap /etc/postfix/virtual From b70f9ee3fb72cac7dc64620475db6953349e3ff7 Mon Sep 17 00:00:00 2001 From: egavard Date: Thu, 6 Aug 2015 12:14:04 +0200 Subject: [PATCH 036/155] Updated virtual structure (key space value) --- postfix/virtual | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/postfix/virtual b/postfix/virtual index 9fc19fb0..7718604a 100644 --- a/postfix/virtual +++ b/postfix/virtual @@ -1,4 +1,4 @@ #Mail redirection from user@domain.tld to otheruser@domain.tld and otheruser@otherdomain.tld -user@domain.tld|otheruser@domain.tld,otheruser@otherdomain.tld +user1@domain.tld otheruser@domain.tld otheruser@otherdomain.tld #Mail redirection from postmaster@domain.tld and hostmaster@domain.tld to user@domain.tld -user@domain.tld| postmaster,hostmaster \ No newline at end of file +user2@domain.tld postmaster hostmaster \ No newline at end of file From 3f3fcb2a6ed773d752def30465613fa386e416a6 Mon Sep 17 00:00:00 2001 From: GAVARD Ewann Date: Fri, 7 Aug 2015 09:19:38 +0200 Subject: [PATCH 037/155] Removed useless echo in virtual file. --- start-mailserver.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/start-mailserver.sh b/start-mailserver.sh index ba6ab200..dd845180 100644 --- a/start-mailserver.sh +++ b/start-mailserver.sh @@ -6,7 +6,6 @@ echo "Regenerating postfix 'vmailbox' and 'virtual' for given users" # rm /etc/postfix/vmailbox # rm /etc/postfix/vmailbox.db echo "# WARNING: this file is auto-generated. Modify accounts.cf in postfix directory on host" > /etc/postfix/vmailbox -echo "# WARNING: this file is auto-generated. Modify redirects.cf in postfix directory on host" > /etc/postfix/virtual # Creating users while IFS=$'|' read -r login pass do @@ -27,8 +26,9 @@ do done < /tmp/postfix/accounts.cf makeuserdb -#creating virtuals and redirects +#copying virtual file cp /tmp/postfix/virtual /etc/postfix/virtual + echo "Postfix configurations" postmap /etc/postfix/vmailbox postmap /etc/postfix/virtual From dd4f90e66ec8f284840662d1bbc82b0b2c124e84 Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Mon, 10 Aug 2015 12:20:50 +0200 Subject: [PATCH 038/155] Improved documentation related to #11 --- README.md | 6 +++--- postfix/virtual | 11 +++++++---- start-mailserver.sh | 3 +-- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index d124ffd0..9f3ac44e 100644 --- a/README.md +++ b/README.md @@ -18,9 +18,8 @@ Additional informations: - mails are stored in `/var/mail/${domain}/${username}` - email login are full email address (`username1@my-domain.com`) - ssl is strongly recommended -- do not add whitespace in `$docker_mail_users` or `$docker_mail_aliases` - user accounts are managed in `./postfix/accounts.cf` -- redirections are managed in `./postfix/redirects.cf` +- aliases and fowards/redirects are managed in `./postfix/virtual` - antispam are rules are managed in `./spamassassin/rules.cf` - files must be mounted to `/tmp` in your container (see `docker-compose.yml` template) @@ -60,7 +59,8 @@ Volumes allow to: - Manage mail users, passwords and aliases # usage -docker-compose up -d mail + + docker-compose up -d mail # client configuration diff --git a/postfix/virtual b/postfix/virtual index 7718604a..03991098 100644 --- a/postfix/virtual +++ b/postfix/virtual @@ -1,4 +1,7 @@ -#Mail redirection from user@domain.tld to otheruser@domain.tld and otheruser@otherdomain.tld -user1@domain.tld otheruser@domain.tld otheruser@otherdomain.tld -#Mail redirection from postmaster@domain.tld and hostmaster@domain.tld to user@domain.tld -user2@domain.tld postmaster hostmaster \ No newline at end of file +# +# ALIAS => from alias@domain.tld (alias) to user@domain.tld (real account) +# alias@domain.tld user@domain.tld +# +# FORWARD => from redirect@domain.tld to a list of internal/external email addresses +# redirect@domain.tld otheruser@domain.tld otheruser@otherdomain.tld +# \ No newline at end of file diff --git a/start-mailserver.sh b/start-mailserver.sh index dd845180..60e50ecd 100644 --- a/start-mailserver.sh +++ b/start-mailserver.sh @@ -25,8 +25,7 @@ do echo ${domain} >> /tmp/vhost.tmp done < /tmp/postfix/accounts.cf makeuserdb - -#copying virtual file +# Copying virtual file cp /tmp/postfix/virtual /etc/postfix/virtual echo "Postfix configurations" From 09c8166a24be0f6c65971f5ad92d1533ae33e829 Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Mon, 17 Aug 2015 20:45:49 +0200 Subject: [PATCH 039/155] Fixed documentation when using docker to help on #13 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9f3ac44e..a2ad5231 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ Additional informations: ## run - docker run -p "25:25" -p "143:143" -p "587:587" -p "993:993" -e docker_mail_domain=my-domain.com -t tvial/docker-mailserver + docker run -v "$(pwd)/postfix":/tmp/postfix -v "$(pwd)/spamassassin":/tmp/spamassassin -p "25:25" -p "143:143" -p "587:587" -p "993:993" -e docker_mail_domain=my-domain.com -t tvial/docker-mailserver ## docker-compose template (recommended) From 63a7be0e975b39b72fe666a61517e32d32b98f55 Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Mon, 17 Aug 2015 22:16:08 +0200 Subject: [PATCH 040/155] Removed "docker_mail_domain" env. variable to use docker hostname and improved documentation for #13 --- README.md | 9 ++++----- postfix/accounts.cf | 2 +- start-mailserver.sh | 16 ++++++---------- 3 files changed, 11 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index a2ad5231..bfeea09a 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,7 @@ Additional informations: - only config files, no *sql database required - mails are stored in `/var/mail/${domain}/${username}` +- you should use a data volume container for `/var/mail` for data persistence - email login are full email address (`username1@my-domain.com`) - ssl is strongly recommended - user accounts are managed in `./postfix/accounts.cf` @@ -33,7 +34,7 @@ Additional informations: ## run - docker run -v "$(pwd)/postfix":/tmp/postfix -v "$(pwd)/spamassassin":/tmp/spamassassin -p "25:25" -p "143:143" -p "587:587" -p "993:993" -e docker_mail_domain=my-domain.com -t tvial/docker-mailserver + docker run --name mail -v "$(pwd)/postfix":/tmp/postfix -v "$(pwd)/spamassassin":/tmp/spamassassin -p "25:25" -p "143:143" -p "587:587" -p "993:993" -h mail.my-domain.com -t tvial/docker-mailserver ## docker-compose template (recommended) @@ -47,11 +48,9 @@ Additional informations: - "143:143" - "587:587" - "993:993" - environment: - docker_mail_domain: "my-domain.com" volumes: - - ./spamassassin:/tmp/spamassassin/:ro - - ./postfix:/tmp/postfix/:ro + - ./spamassassin:/tmp/spamassassin/ + - ./postfix:/tmp/postfix/ Volumes allow to: diff --git a/postfix/accounts.cf b/postfix/accounts.cf index 94896e0d..ecb0f063 100644 --- a/postfix/accounts.cf +++ b/postfix/accounts.cf @@ -1 +1 @@ -user@domain.tld|mypassword \ No newline at end of file +user@domain.tld|mypassword diff --git a/start-mailserver.sh b/start-mailserver.sh index 60e50ecd..dc64c045 100644 --- a/start-mailserver.sh +++ b/start-mailserver.sh @@ -1,23 +1,19 @@ #!/bin/sh echo "Regenerating postfix 'vmailbox' and 'virtual' for given users" -# rm /etc/postfix/virtual -# rm /etc/postfix/virtual.db -# rm /etc/postfix/vmailbox -# rm /etc/postfix/vmailbox.db echo "# WARNING: this file is auto-generated. Modify accounts.cf in postfix directory on host" > /etc/postfix/vmailbox +# Checking that /tmp/postfix/accounts.cf ends with a newline +sed -i -e '$a\' /tmp/postfix/accounts.cf # Creating users -while IFS=$'|' read -r login pass +while IFS=$'|' read login pass do - # Setting variables for better readability user=$(echo ${login} | cut -d @ -f1) domain=$(echo ${login} | cut -d @ -f2) - # Let's go! echo "user '${user}' for domain '${domain}' with password '********'" echo "${login} ${domain}/${user}/" >> /etc/postfix/vmailbox - userdb ${login} set uid=5000 gid=5000 home=/var/mail/${domain}/${user} mail=/var/mail/${domain}/${user} + /usr/sbin/userdb ${login} set uid=5000 gid=5000 home=/var/mail/${domain}/${user} mail=/var/mail/${domain}/${user} echo "${pass}" | userdbpw -md5 | userdb ${login} set systempw echo "${pass}" | saslpasswd2 -p -c -u ${domain} ${login} mkdir -p /var/mail/${domain} @@ -31,7 +27,7 @@ cp /tmp/postfix/virtual /etc/postfix/virtual echo "Postfix configurations" postmap /etc/postfix/vmailbox postmap /etc/postfix/virtual -sed -i -r 's/DOCKER_MAIL_DOMAIN/'"$docker_mail_domain"'/g' /etc/postfix/main.cf +sed -i -r 's/DOCKER_MAIL_DOMAIN/'"$(hostname -d)"'/g' /etc/postfix/main.cf cat /tmp/vhost.tmp | sort | uniq >> /etc/postfix/vhost && rm /tmp/vhost.tmp echo "Fixing permissions" @@ -39,7 +35,7 @@ chown -R 5000:5000 /var/mail mkdir -p /var/log/clamav && chown -R clamav:root /var/log/clamav echo "Creating /etc/mailname" -echo $docker_mail_domain > /etc/mailname +echo $(hostname -d) > /etc/mailname echo "Configuring Spamassassin" echo "required_hits 5.0" >> /etc/mail/spamassassin/local.cf From a848a55177d3bb191cfb30fbb592920f1a40b392 Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Tue, 18 Aug 2015 13:13:08 +0200 Subject: [PATCH 041/155] Added a way to generate and configure a specific SSL certificate for postfix #14 --- .gitignore | 1 + Dockerfile | 2 ++ README.md | 18 ++++++++++++++++++ bin/generate-ssl-certificate | 4 ++++ docker-compose.yml.dist | 6 ++---- start-mailserver.sh | 10 ++++++++++ 6 files changed, 37 insertions(+), 4 deletions(-) create mode 100644 bin/generate-ssl-certificate diff --git a/.gitignore b/.gitignore index 423d89e9..1c3101d7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ .DS_Store docker-compose.yml +postfix/ssl/* \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 9dad19b3..05bdbd23 100644 --- a/Dockerfile +++ b/Dockerfile @@ -33,6 +33,8 @@ RUN freshclam ADD postfix/main.cf /etc/postfix/main.cf ADD postfix/master.cf /etc/postfix/master.cf ADD postfix/sasl/smtpd.conf /etc/postfix/sasl/smtpd.conf +ADD bin/generate-ssl-certificate /usr/local/bin/generate-ssl-certificate +RUN chmod +x /usr/local/bin/generate-ssl-certificate # Start-mailserver script ADD start-mailserver.sh /usr/local/bin/start-mailserver.sh diff --git a/README.md b/README.md index bfeea09a..5ce8729a 100644 --- a/README.md +++ b/README.md @@ -61,6 +61,24 @@ Volumes allow to: docker-compose up -d mail +# configure ssl + +## generate ssl certificate + +You can easily generate en SSL certificate by using the following command: + + docker run -ti --rm -v "$(pwd)"/postfix/ssl:/ssl -h mail.my-domain.com -t tvial/docker-mailserver generate-ssl-certificate + + # will generate: + # postfix/ssl/mail.my-domain.com.key + # postfix/ssl/mail.my-domain.com.csr + +Note that the certificate will be generate for the container `fqdn`, that is passed as `-h` argument. + +## configure ssl certificate (convention over configuration) + +If a matching certificate (with `.key` and `.csr` files) is found in `postfix/ssl`, it will be automatically configured in postfix. You just have to place `mail.my-domain.com.key` and `mail.my-domain.com.csr` for domain `mail.my-domain.com` in `postfix/ssl` folder. + # client configuration # imap diff --git a/bin/generate-ssl-certificate b/bin/generate-ssl-certificate new file mode 100644 index 00000000..c65bc445 --- /dev/null +++ b/bin/generate-ssl-certificate @@ -0,0 +1,4 @@ +#!/bin/sh + +FQDN=$(hostname) +openssl req -new -newkey rsa:2048 -nodes -keyout /ssl/$FQDN.key -out /ssl/$FQDN.csr \ No newline at end of file diff --git a/docker-compose.yml.dist b/docker-compose.yml.dist index 2dc2afe6..6f3ba3b4 100644 --- a/docker-compose.yml.dist +++ b/docker-compose.yml.dist @@ -8,8 +8,6 @@ mail: - "143:143" - "587:587" - "993:993" - environment: - docker_mail_domain: "my-domain.com" volumes: - - ./spamassassin:/tmp/spamassassin/:ro - - ./postfix:/tmp/postfix/:ro + - ./spamassassin:/tmp/spamassassin/ + - ./postfix:/tmp/postfix/ diff --git a/start-mailserver.sh b/start-mailserver.sh index dc64c045..e362b594 100644 --- a/start-mailserver.sh +++ b/start-mailserver.sh @@ -2,8 +2,10 @@ echo "Regenerating postfix 'vmailbox' and 'virtual' for given users" echo "# WARNING: this file is auto-generated. Modify accounts.cf in postfix directory on host" > /etc/postfix/vmailbox + # Checking that /tmp/postfix/accounts.cf ends with a newline sed -i -e '$a\' /tmp/postfix/accounts.cf + # Creating users while IFS=$'|' read login pass do @@ -30,6 +32,14 @@ postmap /etc/postfix/virtual sed -i -r 's/DOCKER_MAIL_DOMAIN/'"$(hostname -d)"'/g' /etc/postfix/main.cf cat /tmp/vhost.tmp | sort | uniq >> /etc/postfix/vhost && rm /tmp/vhost.tmp +# Adding SSL certificate if name provided as $docker_mail_cert env +if [ -e "/tmp/postfix/ssl/$(hostname).csr" ]; then + echo "Adding $(hostname) csr/key SSL certificate" + cp -r /tmp/postfix/ssl /etc/postfix/ssl + sed -i -r 's/smtpd_tls_cert_file=\/etc\/ssl\/certs\/ssl-cert-snakeoil.pem/smtpd_tls_cert_file=\/etc\/postfix\/ssl\/'$docker_mail_cert'.csr/g' /etc/postfix/main.cf + sed -i -r 's/smtpd_tls_key_file=\/etc\/ssl\/private\/ssl-cert-snakeoil.key/smtpd_tls_key_file=\/etc\/postfix\/ssl\/'$docker_mail_cert'.key/g' /etc/postfix/main.cf +fi + echo "Fixing permissions" chown -R 5000:5000 /var/mail mkdir -p /var/log/clamav && chown -R clamav:root /var/log/clamav From db8391e4f40c324e8e06673b217bf11c3a8be952 Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Tue, 18 Aug 2015 13:24:12 +0200 Subject: [PATCH 042/155] Fixes #14 documentation. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5ce8729a..612aad00 100644 --- a/README.md +++ b/README.md @@ -18,11 +18,11 @@ Additional informations: - mails are stored in `/var/mail/${domain}/${username}` - you should use a data volume container for `/var/mail` for data persistence - email login are full email address (`username1@my-domain.com`) -- ssl is strongly recommended - user accounts are managed in `./postfix/accounts.cf` - aliases and fowards/redirects are managed in `./postfix/virtual` - antispam are rules are managed in `./spamassassin/rules.cf` - files must be mounted to `/tmp` in your container (see `docker-compose.yml` template) +- ssl is strongly recommended, you can provide a specific certificate (csr/key files), see below ## installation From 9f137bc1f51626e29ae8ed9b5272ef53701c0aea Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Tue, 18 Aug 2015 13:36:57 +0200 Subject: [PATCH 043/155] Fixes #14 and adds SSL certification configuration for courier imap-ssl --- start-mailserver.sh | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/start-mailserver.sh b/start-mailserver.sh index e362b594..cac6ff38 100644 --- a/start-mailserver.sh +++ b/start-mailserver.sh @@ -36,8 +36,12 @@ cat /tmp/vhost.tmp | sort | uniq >> /etc/postfix/vhost && rm /tmp/vhost.tmp if [ -e "/tmp/postfix/ssl/$(hostname).csr" ]; then echo "Adding $(hostname) csr/key SSL certificate" cp -r /tmp/postfix/ssl /etc/postfix/ssl - sed -i -r 's/smtpd_tls_cert_file=\/etc\/ssl\/certs\/ssl-cert-snakeoil.pem/smtpd_tls_cert_file=\/etc\/postfix\/ssl\/'$docker_mail_cert'.csr/g' /etc/postfix/main.cf - sed -i -r 's/smtpd_tls_key_file=\/etc\/ssl\/private\/ssl-cert-snakeoil.key/smtpd_tls_key_file=\/etc\/postfix\/ssl\/'$docker_mail_cert'.key/g' /etc/postfix/main.cf + # Postfix configuration + sed -i -r 's/smtpd_tls_cert_file=\/etc\/ssl\/certs\/ssl-cert-snakeoil.pem/smtpd_tls_cert_file=\/etc\/postfix\/ssl\/'$(hostname)'.csr/g' /etc/postfix/main.cf + sed -i -r 's/smtpd_tls_key_file=\/etc\/ssl\/private\/ssl-cert-snakeoil.key/smtpd_tls_key_file=\/etc\/postfix\/ssl\/'$(hostname)'.key/g' /etc/postfix/main.cf + ln -s /etc/postfix/ssl/$(hostname).csr /etc/ssl/certs/$(hostname).pem + # Courier configuration + sed -i -r 's/TLS_CERTFILE=\/etc\/courier\/imapd.pem/TLS_CERTFILE=\/etc\/ssl\/certs\/'$(hostname)'.pem/g' /etc/courier/imapd-ssl fi echo "Fixing permissions" From 4de6cea0332f64d5bee7a84af74dffc9fc84579e Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Tue, 18 Aug 2015 13:38:09 +0200 Subject: [PATCH 044/155] Improved comment on #14 --- start-mailserver.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/start-mailserver.sh b/start-mailserver.sh index cac6ff38..d17a7ba1 100644 --- a/start-mailserver.sh +++ b/start-mailserver.sh @@ -32,7 +32,7 @@ postmap /etc/postfix/virtual sed -i -r 's/DOCKER_MAIL_DOMAIN/'"$(hostname -d)"'/g' /etc/postfix/main.cf cat /tmp/vhost.tmp | sort | uniq >> /etc/postfix/vhost && rm /tmp/vhost.tmp -# Adding SSL certificate if name provided as $docker_mail_cert env +# Adding SSL certificate if provided in 'postfix/ssl' folder if [ -e "/tmp/postfix/ssl/$(hostname).csr" ]; then echo "Adding $(hostname) csr/key SSL certificate" cp -r /tmp/postfix/ssl /etc/postfix/ssl From ea830f5ec608c8de0320df16919cdb31fa18bec2 Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Tue, 18 Aug 2015 20:43:42 +0200 Subject: [PATCH 045/155] Fixes #14 with SSL configuration --- bin/generate-ssl-certificate | 15 ++++++++++++++- postfix/main.cf | 2 ++ start-mailserver.sh | 14 ++++++++------ 3 files changed, 24 insertions(+), 7 deletions(-) diff --git a/bin/generate-ssl-certificate b/bin/generate-ssl-certificate index c65bc445..080a2708 100644 --- a/bin/generate-ssl-certificate +++ b/bin/generate-ssl-certificate @@ -1,4 +1,17 @@ #!/bin/sh FQDN=$(hostname) -openssl req -new -newkey rsa:2048 -nodes -keyout /ssl/$FQDN.key -out /ssl/$FQDN.csr \ No newline at end of file + +cd /ssl +# Create CA certificate +/usr/lib/ssl/misc/CA.pl -newca +# Create an unpassworded private key and create an unsigned public key certificate +openssl req -new -nodes -keyout /ssl/$FQDN-key.pem -out /ssl/$FQDN-req.pem -days 3652 +# Sign the public key certificate with CA certificate +openssl ca -out /ssl/$FQDN-cert.pem -infiles /ssl/$FQDN-req.pem +# Combine certificates for courier +cat /ssl/$FQDN-key.pem /ssl/$FQDN-cert.pem >> /ssl/$FQDN-combined.pem + +# chmod 644 /etc/postfix/foo-cert.pem /etc/postfix/cacert.pem +# chmod 400 /etc/postfix/foo-key.pem + diff --git a/postfix/main.cf b/postfix/main.cf index 51a6b0cd..ef5ee284 100644 --- a/postfix/main.cf +++ b/postfix/main.cf @@ -20,6 +20,8 @@ inet_protocols = all # TLS parameters smtpd_tls_cert_file=/etc/ssl/certs/ssl-cert-snakeoil.pem smtpd_tls_key_file=/etc/ssl/private/ssl-cert-snakeoil.key +#smtpd_tls_CAfile= +#smtp_tls_CAfile= smtpd_tls_security_level = may smtpd_use_tls=yes smtpd_relay_restrictions = permit_mynetworks permit_sasl_authenticated defer_unauth_destination diff --git a/start-mailserver.sh b/start-mailserver.sh index d17a7ba1..f989b25a 100644 --- a/start-mailserver.sh +++ b/start-mailserver.sh @@ -33,15 +33,17 @@ sed -i -r 's/DOCKER_MAIL_DOMAIN/'"$(hostname -d)"'/g' /etc/postfix/main.cf cat /tmp/vhost.tmp | sort | uniq >> /etc/postfix/vhost && rm /tmp/vhost.tmp # Adding SSL certificate if provided in 'postfix/ssl' folder -if [ -e "/tmp/postfix/ssl/$(hostname).csr" ]; then - echo "Adding $(hostname) csr/key SSL certificate" +if [ -e "/tmp/postfix/ssl/$(hostname)-cert.pem" ]; then + echo "Adding $(hostname) SSL certificate" cp -r /tmp/postfix/ssl /etc/postfix/ssl # Postfix configuration - sed -i -r 's/smtpd_tls_cert_file=\/etc\/ssl\/certs\/ssl-cert-snakeoil.pem/smtpd_tls_cert_file=\/etc\/postfix\/ssl\/'$(hostname)'.csr/g' /etc/postfix/main.cf - sed -i -r 's/smtpd_tls_key_file=\/etc\/ssl\/private\/ssl-cert-snakeoil.key/smtpd_tls_key_file=\/etc\/postfix\/ssl\/'$(hostname)'.key/g' /etc/postfix/main.cf - ln -s /etc/postfix/ssl/$(hostname).csr /etc/ssl/certs/$(hostname).pem + sed -i -r 's/smtpd_tls_cert_file=\/etc\/ssl\/certs\/ssl-cert-snakeoil.pem/smtpd_tls_cert_file=\/etc\/postfix\/ssl\/'$(hostname)'-cert.pem/g' /etc/postfix/main.cf + sed -i -r 's/smtpd_tls_key_file=\/etc\/ssl\/private\/ssl-cert-snakeoil.key/smtpd_tls_key_file=\/etc\/postfix\/ssl\/'$(hostname)'-key.pem/g' /etc/postfix/main.cf + sed -i -r 's/#smtpd_tls_CAfile=/smtpd_tls_CAfile=\/etc\/postfix\/ssl\/demoCA\/cacert.pem/g' /etc/postfix/main.cf + sed -i -r 's/#smtp_tls_CAfile=/smtp_tls_CAfile=\/etc\/postfix\/ssl\/demoCA\/cacert.pem/g' /etc/postfix/main.cf + ln -s /etc/postfix/ssl/demoCA/cacert.pem /etc/ssl/certs/cacert-$(hostname).pem # Courier configuration - sed -i -r 's/TLS_CERTFILE=\/etc\/courier\/imapd.pem/TLS_CERTFILE=\/etc\/ssl\/certs\/'$(hostname)'.pem/g' /etc/courier/imapd-ssl + sed -i -r 's/TLS_CERTFILE=\/etc\/courier\/imapd.pem/TLS_CERTFILE=\/etc\/postfix\/ssl\/'$(hostname)'-combined.pem/g' /etc/courier/imapd-ssl fi echo "Fixing permissions" From 9be61a477c0b8d314033547c554cdae2c3846e4d Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Tue, 18 Aug 2015 20:49:49 +0200 Subject: [PATCH 046/155] Improved documentation for #14 --- README.md | 15 +++++++++++++-- bin/generate-ssl-certificate | 3 --- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 612aad00..98098134 100644 --- a/README.md +++ b/README.md @@ -69,9 +69,20 @@ You can easily generate en SSL certificate by using the following command: docker run -ti --rm -v "$(pwd)"/postfix/ssl:/ssl -h mail.my-domain.com -t tvial/docker-mailserver generate-ssl-certificate + # Press enter + # Enter a password when needed + # Fill information like Country, Organisation name + # Fill "mail.my-domain.com" as FQDN + # Don't fill extras + # Enter same password when needed + # Sign the certificate? [y/n]:y + # 1 out of 1 certificate requests certified, commit? [y/n]y + # will generate: - # postfix/ssl/mail.my-domain.com.key - # postfix/ssl/mail.my-domain.com.csr + # postfix/ssl/mail.my-domain.com-key.pem (used in postfix) + # postfix/ssl/mail.my-domain.com-req.pem + # postfix/ssl/mail.my-domain.com-cert.pem (used in postfix) + # postfix/ssl/mail.my-domain.com-combined.pem (used for courier) Note that the certificate will be generate for the container `fqdn`, that is passed as `-h` argument. diff --git a/bin/generate-ssl-certificate b/bin/generate-ssl-certificate index 080a2708..682b07d4 100644 --- a/bin/generate-ssl-certificate +++ b/bin/generate-ssl-certificate @@ -12,6 +12,3 @@ openssl ca -out /ssl/$FQDN-cert.pem -infiles /ssl/$FQDN-req.pem # Combine certificates for courier cat /ssl/$FQDN-key.pem /ssl/$FQDN-cert.pem >> /ssl/$FQDN-combined.pem -# chmod 644 /etc/postfix/foo-cert.pem /etc/postfix/cacert.pem -# chmod 400 /etc/postfix/foo-key.pem - From 920ac36badd92addfae5846e895c9b60261f4f76 Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Wed, 19 Aug 2015 10:08:43 +0200 Subject: [PATCH 047/155] Improved documentation about SSL certs. which are self-signed --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 98098134..39e6048e 100644 --- a/README.md +++ b/README.md @@ -63,9 +63,9 @@ Volumes allow to: # configure ssl -## generate ssl certificate +## generate self-signed ssl certificate -You can easily generate en SSL certificate by using the following command: +You can easily generate a self-signed SSL certificate by using the following command: docker run -ti --rm -v "$(pwd)"/postfix/ssl:/ssl -h mail.my-domain.com -t tvial/docker-mailserver generate-ssl-certificate From 725d6487085a8dc2c6a3c5265ad6368c2b943bbd Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Wed, 19 Aug 2015 10:13:56 +0200 Subject: [PATCH 048/155] Fixed #15 => $myhostname is taken from machine FQDN (use '-h' in docker to set it) --- postfix/main.cf | 2 +- start-mailserver.sh | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/postfix/main.cf b/postfix/main.cf index ef5ee284..261a71ce 100644 --- a/postfix/main.cf +++ b/postfix/main.cf @@ -6,7 +6,7 @@ append_dot_mydomain = no readme_directory = no # Basic configuration -myhostname = DOCKER_MAIL_DOMAIN +# myhostname = alias_maps = hash:/etc/aliases alias_database = hash:/etc/aliases mydestination = localhost.localdomain, localhost diff --git a/start-mailserver.sh b/start-mailserver.sh index f989b25a..e73c4e2d 100644 --- a/start-mailserver.sh +++ b/start-mailserver.sh @@ -29,7 +29,6 @@ cp /tmp/postfix/virtual /etc/postfix/virtual echo "Postfix configurations" postmap /etc/postfix/vmailbox postmap /etc/postfix/virtual -sed -i -r 's/DOCKER_MAIL_DOMAIN/'"$(hostname -d)"'/g' /etc/postfix/main.cf cat /tmp/vhost.tmp | sort | uniq >> /etc/postfix/vhost && rm /tmp/vhost.tmp # Adding SSL certificate if provided in 'postfix/ssl' folder From c95dea76f60077bb29bd973ffbefdd3f8d39d082 Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Wed, 19 Aug 2015 15:47:20 +0200 Subject: [PATCH 049/155] Added better check on self-signed certs. for #14 --- README.md | 9 +++++---- start-mailserver.sh | 15 ++++++++++++--- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 39e6048e..17bf376c 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ Additional informations: - aliases and fowards/redirects are managed in `./postfix/virtual` - antispam are rules are managed in `./spamassassin/rules.cf` - files must be mounted to `/tmp` in your container (see `docker-compose.yml` template) -- ssl is strongly recommended, you can provide a specific certificate (csr/key files), see below +- ssl is strongly recommended, you can provide a specific certificate, see below ## installation @@ -80,15 +80,16 @@ You can easily generate a self-signed SSL certificate by using the following com # will generate: # postfix/ssl/mail.my-domain.com-key.pem (used in postfix) - # postfix/ssl/mail.my-domain.com-req.pem + # postfix/ssl/mail.my-domain.com-req.pem (only used to generate other files) # postfix/ssl/mail.my-domain.com-cert.pem (used in postfix) - # postfix/ssl/mail.my-domain.com-combined.pem (used for courier) + # postfix/ssl/mail.my-domain.com-combined.pem (used in courier) + # postfix/ssl/demoCA/cacert.pem (certificate authority) Note that the certificate will be generate for the container `fqdn`, that is passed as `-h` argument. ## configure ssl certificate (convention over configuration) -If a matching certificate (with `.key` and `.csr` files) is found in `postfix/ssl`, it will be automatically configured in postfix. You just have to place `mail.my-domain.com.key` and `mail.my-domain.com.csr` for domain `mail.my-domain.com` in `postfix/ssl` folder. +If a matching certificate (files listed above) is found in `postfix/ssl`, it will be automatically setup in postfix and courier-imap-ssl. You just have to place them in `postfix/ssl` folder. # client configuration diff --git a/start-mailserver.sh b/start-mailserver.sh index e73c4e2d..84efc29f 100644 --- a/start-mailserver.sh +++ b/start-mailserver.sh @@ -31,16 +31,25 @@ postmap /etc/postfix/vmailbox postmap /etc/postfix/virtual cat /tmp/vhost.tmp | sort | uniq >> /etc/postfix/vhost && rm /tmp/vhost.tmp -# Adding SSL certificate if provided in 'postfix/ssl' folder -if [ -e "/tmp/postfix/ssl/$(hostname)-cert.pem" ]; then +# Adding self-signed SSL certificate if provided in 'postfix/ssl' folder +if [ -e "/tmp/postfix/ssl/$(hostname)-cert.pem" ] \ +&& [ -e "/tmp/postfix/ssl/$(hostname)-key.pem" ] \ +&& [ -e "/tmp/postfix/ssl/$(hostname)-combined.pem" ] \ +&& [ -e "/tmp/postfix/ssl/demoCA/cacert.pem" ]; then echo "Adding $(hostname) SSL certificate" - cp -r /tmp/postfix/ssl /etc/postfix/ssl + mkdir -p /etc/postfix/ssl + cp /tmp/postfix/ssl/$(hostname)-cert.pem /etc/postfix/ssl + cp /tmp/postfix/ssl/$(hostname)-key.pem /etc/postfix/ssl + cp /tmp/postfix/ssl/$(hostname)-combined.pem /etc/postfix/ssl + cp /tmp/postfix/ssl/demoCA/cacert.pem /etc/postfix/ssl + # Postfix configuration sed -i -r 's/smtpd_tls_cert_file=\/etc\/ssl\/certs\/ssl-cert-snakeoil.pem/smtpd_tls_cert_file=\/etc\/postfix\/ssl\/'$(hostname)'-cert.pem/g' /etc/postfix/main.cf sed -i -r 's/smtpd_tls_key_file=\/etc\/ssl\/private\/ssl-cert-snakeoil.key/smtpd_tls_key_file=\/etc\/postfix\/ssl\/'$(hostname)'-key.pem/g' /etc/postfix/main.cf sed -i -r 's/#smtpd_tls_CAfile=/smtpd_tls_CAfile=\/etc\/postfix\/ssl\/demoCA\/cacert.pem/g' /etc/postfix/main.cf sed -i -r 's/#smtp_tls_CAfile=/smtp_tls_CAfile=\/etc\/postfix\/ssl\/demoCA\/cacert.pem/g' /etc/postfix/main.cf ln -s /etc/postfix/ssl/demoCA/cacert.pem /etc/ssl/certs/cacert-$(hostname).pem + # Courier configuration sed -i -r 's/TLS_CERTFILE=\/etc\/courier\/imapd.pem/TLS_CERTFILE=\/etc\/postfix\/ssl\/'$(hostname)'-combined.pem/g' /etc/courier/imapd-ssl fi From da3dbd4b104eb407a6098b25f41a8170d4f90069 Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Wed, 19 Aug 2015 15:52:50 +0200 Subject: [PATCH 050/155] Fixed cron that was not started - #16 --- start-mailserver.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/start-mailserver.sh b/start-mailserver.sh index 84efc29f..ac307be8 100644 --- a/start-mailserver.sh +++ b/start-mailserver.sh @@ -69,6 +69,7 @@ echo "rewrite_header Subject ***SPAM***" >> /etc/mail/spamassassin/local.cf cp /tmp/spamassassin/rules.cf /etc/spamassassin/ echo "Starting daemons" +cron /etc/init.d/rsyslog start /etc/init.d/fam start /etc/init.d/saslauthd start From 7a28bb0f3a7ec073bd137f6010e7d07ad56ae0e9 Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Wed, 19 Aug 2015 15:59:04 +0200 Subject: [PATCH 051/155] Fixed typo. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 17bf376c..540f0357 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ Additional informations: - email login are full email address (`username1@my-domain.com`) - user accounts are managed in `./postfix/accounts.cf` - aliases and fowards/redirects are managed in `./postfix/virtual` -- antispam are rules are managed in `./spamassassin/rules.cf` +- antispam rules are managed in `./spamassassin/rules.cf` - files must be mounted to `/tmp` in your container (see `docker-compose.yml` template) - ssl is strongly recommended, you can provide a specific certificate, see below From 514fe97303fee56093deb8070700fdc4a318d390 Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Wed, 19 Aug 2015 16:13:56 +0200 Subject: [PATCH 052/155] Improved documentation --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 540f0357..9122d5df 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ Additional informations: - aliases and fowards/redirects are managed in `./postfix/virtual` - antispam rules are managed in `./spamassassin/rules.cf` - files must be mounted to `/tmp` in your container (see `docker-compose.yml` template) -- ssl is strongly recommended, you can provide a specific certificate, see below +- ssl is strongly recommended, you can provide a self-signed certificate, see below ## installation @@ -56,6 +56,7 @@ Volumes allow to: - Insert custom antispam rules - Manage mail users, passwords and aliases +- Manage SSL certificates # usage From 5b06f844caaec5142f7240a506adc483ed5b5944 Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Wed, 19 Aug 2015 18:05:10 +0200 Subject: [PATCH 053/155] Fixed cacert.pem path for #14 --- start-mailserver.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/start-mailserver.sh b/start-mailserver.sh index ac307be8..c12d3344 100644 --- a/start-mailserver.sh +++ b/start-mailserver.sh @@ -47,8 +47,8 @@ if [ -e "/tmp/postfix/ssl/$(hostname)-cert.pem" ] \ sed -i -r 's/smtpd_tls_cert_file=\/etc\/ssl\/certs\/ssl-cert-snakeoil.pem/smtpd_tls_cert_file=\/etc\/postfix\/ssl\/'$(hostname)'-cert.pem/g' /etc/postfix/main.cf sed -i -r 's/smtpd_tls_key_file=\/etc\/ssl\/private\/ssl-cert-snakeoil.key/smtpd_tls_key_file=\/etc\/postfix\/ssl\/'$(hostname)'-key.pem/g' /etc/postfix/main.cf sed -i -r 's/#smtpd_tls_CAfile=/smtpd_tls_CAfile=\/etc\/postfix\/ssl\/demoCA\/cacert.pem/g' /etc/postfix/main.cf - sed -i -r 's/#smtp_tls_CAfile=/smtp_tls_CAfile=\/etc\/postfix\/ssl\/demoCA\/cacert.pem/g' /etc/postfix/main.cf - ln -s /etc/postfix/ssl/demoCA/cacert.pem /etc/ssl/certs/cacert-$(hostname).pem + sed -i -r 's/#smtp_tls_CAfile=/smtp_tls_CAfile=\/etc\/postfix\/ssl\/cacert.pem/g' /etc/postfix/main.cf + ln -s /etc/postfix/ssl/cacert.pem /etc/ssl/certs/cacert-$(hostname).pem # Courier configuration sed -i -r 's/TLS_CERTFILE=\/etc\/courier\/imapd.pem/TLS_CERTFILE=\/etc\/postfix\/ssl\/'$(hostname)'-combined.pem/g' /etc/courier/imapd-ssl From c2c7ba70afc7af989f7eff6c1dd9b4efe3b44f8c Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Wed, 26 Aug 2015 10:04:07 +0200 Subject: [PATCH 054/155] Added a check on needed files with specific message - #17 --- start-mailserver.sh | 66 +++++++++++++++++++++++++++------------------ 1 file changed, 40 insertions(+), 26 deletions(-) diff --git a/start-mailserver.sh b/start-mailserver.sh index c12d3344..5acf51ff 100644 --- a/start-mailserver.sh +++ b/start-mailserver.sh @@ -1,35 +1,49 @@ #!/bin/sh -echo "Regenerating postfix 'vmailbox' and 'virtual' for given users" -echo "# WARNING: this file is auto-generated. Modify accounts.cf in postfix directory on host" > /etc/postfix/vmailbox +die () { + echo >&2 "$@" + exit 1 +} -# Checking that /tmp/postfix/accounts.cf ends with a newline -sed -i -e '$a\' /tmp/postfix/accounts.cf +if [ -f /tmp/postfix/accounts.cf ]; then + echo "Regenerating postfix 'vmailbox' and 'virtual' for given users" + echo "# WARNING: this file is auto-generated. Modify accounts.cf in postfix directory on host" > /etc/postfix/vmailbox -# Creating users -while IFS=$'|' read login pass -do - # Setting variables for better readability - user=$(echo ${login} | cut -d @ -f1) - domain=$(echo ${login} | cut -d @ -f2) - # Let's go! - echo "user '${user}' for domain '${domain}' with password '********'" - echo "${login} ${domain}/${user}/" >> /etc/postfix/vmailbox - /usr/sbin/userdb ${login} set uid=5000 gid=5000 home=/var/mail/${domain}/${user} mail=/var/mail/${domain}/${user} - echo "${pass}" | userdbpw -md5 | userdb ${login} set systempw - echo "${pass}" | saslpasswd2 -p -c -u ${domain} ${login} - mkdir -p /var/mail/${domain} - maildirmake /var/mail/${domain}/${user} - echo ${domain} >> /tmp/vhost.tmp -done < /tmp/postfix/accounts.cf -makeuserdb -# Copying virtual file -cp /tmp/postfix/virtual /etc/postfix/virtual + # Checking that /tmp/postfix/accounts.cf ends with a newline + sed -i -e '$a\' /tmp/postfix/accounts.cf + + # Creating users + while IFS=$'|' read login pass + do + # Setting variables for better readability + user=$(echo ${login} | cut -d @ -f1) + domain=$(echo ${login} | cut -d @ -f2) + # Let's go! + echo "user '${user}' for domain '${domain}' with password '********'" + echo "${login} ${domain}/${user}/" >> /etc/postfix/vmailbox + /usr/sbin/userdb ${login} set uid=5000 gid=5000 home=/var/mail/${domain}/${user} mail=/var/mail/${domain}/${user} + echo "${pass}" | userdbpw -md5 | userdb ${login} set systempw + echo "${pass}" | saslpasswd2 -p -c -u ${domain} ${login} + mkdir -p /var/mail/${domain} + maildirmake /var/mail/${domain}/${user} + echo ${domain} >> /tmp/vhost.tmp + done < /tmp/postfix/accounts.cf + makeuserdb + cat /tmp/vhost.tmp | sort | uniq >> /etc/postfix/vhost && rm /tmp/vhost.tmp +else + echo "==> Warning: '/tmp/postfix/accounts.cf' is not provided. No mail account created." +fi + +if [ -f /tmp/postfix/virtual ]; then + # Copying virtual file + cp /tmp/postfix/virtual /etc/postfix/virtual +else + echo "==> Warning: '/tmp/postfix/virtual' is not provided. No mail alias created." +fi echo "Postfix configurations" -postmap /etc/postfix/vmailbox -postmap /etc/postfix/virtual -cat /tmp/vhost.tmp | sort | uniq >> /etc/postfix/vhost && rm /tmp/vhost.tmp +touch /etc/postfix/vmailbox && postmap /etc/postfix/vmailbox +touch /etc/postfix/virtual && postmap /etc/postfix/virtual # Adding self-signed SSL certificate if provided in 'postfix/ssl' folder if [ -e "/tmp/postfix/ssl/$(hostname)-cert.pem" ] \ From a59eec646a12ec776453a982b7a6ccba56c13bac Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Wed, 26 Aug 2015 10:05:40 +0200 Subject: [PATCH 055/155] Added link to blog post. --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 9122d5df..295b80bd 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,9 @@ Includes: - spamassasin - clamav with automatic updates -Additional informations: +Why I created this container: [Simple mail server with Docker](http://tvi.al/simple-mail-server-with-docker/) + +## informations: - only config files, no *sql database required - mails are stored in `/var/mail/${domain}/${username}` From 2578443f2ca01fae8002479243bf2a13e1ce7d90 Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Wed, 26 Aug 2015 10:39:04 +0200 Subject: [PATCH 056/155] Fixed cacert.pem path for #14 --- start-mailserver.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/start-mailserver.sh b/start-mailserver.sh index 5acf51ff..d43c81ba 100644 --- a/start-mailserver.sh +++ b/start-mailserver.sh @@ -60,7 +60,7 @@ if [ -e "/tmp/postfix/ssl/$(hostname)-cert.pem" ] \ # Postfix configuration sed -i -r 's/smtpd_tls_cert_file=\/etc\/ssl\/certs\/ssl-cert-snakeoil.pem/smtpd_tls_cert_file=\/etc\/postfix\/ssl\/'$(hostname)'-cert.pem/g' /etc/postfix/main.cf sed -i -r 's/smtpd_tls_key_file=\/etc\/ssl\/private\/ssl-cert-snakeoil.key/smtpd_tls_key_file=\/etc\/postfix\/ssl\/'$(hostname)'-key.pem/g' /etc/postfix/main.cf - sed -i -r 's/#smtpd_tls_CAfile=/smtpd_tls_CAfile=\/etc\/postfix\/ssl\/demoCA\/cacert.pem/g' /etc/postfix/main.cf + sed -i -r 's/#smtpd_tls_CAfile=/smtpd_tls_CAfile=\/etc\/postfix\/ssl\/cacert.pem/g' /etc/postfix/main.cf sed -i -r 's/#smtp_tls_CAfile=/smtp_tls_CAfile=\/etc\/postfix\/ssl\/cacert.pem/g' /etc/postfix/main.cf ln -s /etc/postfix/ssl/cacert.pem /etc/ssl/certs/cacert-$(hostname).pem From d0e540d4045eb520ef90e370570eab6e2a709001 Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Sat, 12 Sep 2015 10:53:59 +0200 Subject: [PATCH 057/155] Fixed typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 295b80bd..f02720af 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ Includes: - spamassasin - clamav with automatic updates -Why I created this container: [Simple mail server with Docker](http://tvi.al/simple-mail-server-with-docker/) +Why I created this image: [Simple mail server with Docker](http://tvi.al/simple-mail-server-with-docker/) ## informations: From f18559f1c115e610999f67b313d730bc882bef79 Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Sat, 12 Sep 2015 10:54:30 +0200 Subject: [PATCH 058/155] Fixed #18 => moved from fam to gamin and added a 'docker' user with id '5000' --- Dockerfile | 3 ++- start-mailserver.sh | 1 - 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 05bdbd23..2ce0bcba 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,7 +4,7 @@ MAINTAINER Thomas VIAL # Packages RUN apt-get update -q --fix-missing RUN apt-get -y upgrade -RUN DEBIAN_FRONTEND=noninteractive apt-get -y install vim postfix sasl2-bin courier-imap courier-imap-ssl courier-authdaemon supervisor libfam0 fam amavisd-new spamassassin clamav-daemon libnet-dns-perl libmail-spf-perl pyzor razor arj bzip2 cabextract cpio file gzip nomarch pax unzip zip zoo rsyslog +RUN DEBIAN_FRONTEND=noninteractive apt-get -y install vim postfix sasl2-bin courier-imap courier-imap-ssl courier-authdaemon supervisor gamin amavisd-new spamassassin clamav clamav-daemon libnet-dns-perl libmail-spf-perl pyzor razor arj bzip2 cabextract cpio file gzip nomarch p7zip pax unzip zip zoo rsyslog --no-install-recommends RUN apt-get autoclean # Configures Saslauthd @@ -23,6 +23,7 @@ RUN sed -i -r 's/^(CRON|ENABLED)=0/\1=1/g' /etc/default/spamassassin RUN sed -i -r 's/#(@| \\%)bypass/\1bypass/g' /etc/amavis/conf.d/15-content_filter_mode RUN adduser clamav amavis RUN adduser amavis clamav +RUN useradd -u 5000 -d /home/docker -s /bin/bash -p $(echo docker | openssl passwd -1 -stdin) docker # Enables Clamav RUN chmod 644 /etc/clamav/freshclam.conf diff --git a/start-mailserver.sh b/start-mailserver.sh index d43c81ba..a03d2fb9 100644 --- a/start-mailserver.sh +++ b/start-mailserver.sh @@ -85,7 +85,6 @@ cp /tmp/spamassassin/rules.cf /etc/spamassassin/ echo "Starting daemons" cron /etc/init.d/rsyslog start -/etc/init.d/fam start /etc/init.d/saslauthd start /etc/init.d/courier-authdaemon start /etc/init.d/courier-imap start From c3c711afd004564a0adda20539148804279b677a Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Sat, 12 Sep 2015 11:30:24 +0200 Subject: [PATCH 059/155] Fixes #18 => removed --no-install-recommends --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 2ce0bcba..e029caa4 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,7 +4,7 @@ MAINTAINER Thomas VIAL # Packages RUN apt-get update -q --fix-missing RUN apt-get -y upgrade -RUN DEBIAN_FRONTEND=noninteractive apt-get -y install vim postfix sasl2-bin courier-imap courier-imap-ssl courier-authdaemon supervisor gamin amavisd-new spamassassin clamav clamav-daemon libnet-dns-perl libmail-spf-perl pyzor razor arj bzip2 cabextract cpio file gzip nomarch p7zip pax unzip zip zoo rsyslog --no-install-recommends +RUN DEBIAN_FRONTEND=noninteractive apt-get -y install vim postfix sasl2-bin courier-imap courier-imap-ssl courier-authdaemon supervisor gamin amavisd-new spamassassin clamav clamav-daemon libnet-dns-perl libmail-spf-perl pyzor razor arj bzip2 cabextract cpio file gzip nomarch p7zip pax unzip zip zoo rsyslog RUN apt-get autoclean # Configures Saslauthd From 51bf5662de42e6cfd6e45633108c577f92ce3514 Mon Sep 17 00:00:00 2001 From: Thomas Butter Date: Wed, 14 Oct 2015 16:50:57 +0200 Subject: [PATCH 060/155] forward only domains should be added to vhosts --- start-mailserver.sh | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/start-mailserver.sh b/start-mailserver.sh index a03d2fb9..89d84238 100644 --- a/start-mailserver.sh +++ b/start-mailserver.sh @@ -29,7 +29,6 @@ if [ -f /tmp/postfix/accounts.cf ]; then echo ${domain} >> /tmp/vhost.tmp done < /tmp/postfix/accounts.cf makeuserdb - cat /tmp/vhost.tmp | sort | uniq >> /etc/postfix/vhost && rm /tmp/vhost.tmp else echo "==> Warning: '/tmp/postfix/accounts.cf' is not provided. No mail account created." fi @@ -37,10 +36,20 @@ fi if [ -f /tmp/postfix/virtual ]; then # Copying virtual file cp /tmp/postfix/virtual /etc/postfix/virtual + while IFS=$' ' read from to + do + # Setting variables for better readability + domain=$(echo ${from} | cut -d @ -f2) + echo ${domain} >> /tmp/vhost.tmp + done < /tmp/postfix/virtual else echo "==> Warning: '/tmp/postfix/virtual' is not provided. No mail alias created." fi +if [ -f /tmp/vhost.tmp ]; then + cat /tmp/vhost.tmp | sort | uniq > /etc/postfix/vhost && rm /tmp/vhost.tmp +fi + echo "Postfix configurations" touch /etc/postfix/vmailbox && postmap /etc/postfix/vmailbox touch /etc/postfix/virtual && postmap /etc/postfix/virtual From 871057e58d030b0bb67fad32469a6c5c6251b1d6 Mon Sep 17 00:00:00 2001 From: GAVARD Ewann Date: Fri, 16 Oct 2015 14:42:37 +0200 Subject: [PATCH 061/155] Added docker subnet to avoid relay access denied --- postfix/main.cf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/postfix/main.cf b/postfix/main.cf index 261a71ce..0ead2587 100644 --- a/postfix/main.cf +++ b/postfix/main.cf @@ -11,7 +11,7 @@ alias_maps = hash:/etc/aliases alias_database = hash:/etc/aliases mydestination = localhost.localdomain, localhost relayhost = -mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128 +mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128 172.17.42.1/16 mailbox_size_limit = 0 recipient_delimiter = + inet_interfaces = all From d8a4f3b033f234b876b86afced60e4856d868d80 Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Sun, 18 Oct 2015 15:23:10 +0200 Subject: [PATCH 062/155] Fixed PR #27 with correct subnet --- postfix/main.cf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/postfix/main.cf b/postfix/main.cf index 0ead2587..7bedd2e8 100644 --- a/postfix/main.cf +++ b/postfix/main.cf @@ -11,7 +11,7 @@ alias_maps = hash:/etc/aliases alias_database = hash:/etc/aliases mydestination = localhost.localdomain, localhost relayhost = -mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128 172.17.42.1/16 +mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128 172.17.0.0/16 mailbox_size_limit = 0 recipient_delimiter = + inet_interfaces = all From 9bcced6f29bb33fa5f85f27bade81906d0e16aa4 Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Sun, 18 Oct 2015 21:02:46 +0200 Subject: [PATCH 063/155] Added integration testing - #28 --- .gitignore | 3 ++- .travis.yml | 6 ++++++ Dockerfile | 2 +- Makefile | 30 ++++++++++++++++++++++++++++++ postfix/main.cf | 2 +- test/accounts.cf | 2 ++ test/test.sh | 19 +++++++++++++++++++ test/virtual | 2 ++ 8 files changed, 63 insertions(+), 3 deletions(-) create mode 100644 .travis.yml create mode 100644 Makefile create mode 100644 test/accounts.cf create mode 100755 test/test.sh create mode 100644 test/virtual diff --git a/.gitignore b/.gitignore index 1c3101d7..97490340 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ .DS_Store docker-compose.yml -postfix/ssl/* \ No newline at end of file +postfix/ssl/* +assert.sh \ No newline at end of file diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 00000000..04835d1a --- /dev/null +++ b/.travis.yml @@ -0,0 +1,6 @@ +language: bash +sudo: required +services: + - docker +script: + - make all \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index e029caa4..ff1c1cb9 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,7 +4,7 @@ MAINTAINER Thomas VIAL # Packages RUN apt-get update -q --fix-missing RUN apt-get -y upgrade -RUN DEBIAN_FRONTEND=noninteractive apt-get -y install vim postfix sasl2-bin courier-imap courier-imap-ssl courier-authdaemon supervisor gamin amavisd-new spamassassin clamav clamav-daemon libnet-dns-perl libmail-spf-perl pyzor razor arj bzip2 cabextract cpio file gzip nomarch p7zip pax unzip zip zoo rsyslog +RUN DEBIAN_FRONTEND=noninteractive apt-get -y install vim postfix sasl2-bin courier-imap courier-imap-ssl courier-authdaemon supervisor gamin amavisd-new spamassassin clamav clamav-daemon libnet-dns-perl libmail-spf-perl pyzor razor arj bzip2 cabextract cpio file gzip nomarch p7zip pax unzip zip zoo rsyslog mailutils RUN apt-get autoclean # Configures Saslauthd diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..45ea6de8 --- /dev/null +++ b/Makefile @@ -0,0 +1,30 @@ +NAME = tvial/docker-mailserver +VERSION = travis + +all: build run prepare fixtures tests + +build: + docker build --no-cache -t $(NAME):$(VERSION) . + +run: + # Copy test files + cp test/accounts.cf postfix/ + cp test/virtual postfix/ + # Run container + docker run -d --name mail -v "`pwd`/postfix":/tmp/postfix -v "`pwd`/spamassassin":/tmp/spamassassin -h mail.my-domain.com -t $(NAME):$(VERSION) + sleep 15 + +prepare: + # Reinitialize logs + docker exec mail /bin/sh -c 'echo "" > /var/log/mail.log' + +fixtures: + docker exec mail /bin/sh -c 'echo "This is a test mail" | mail -s "TEST-001" user@localhost.localdomain' + docker exec mail /bin/sh -c 'echo "This is a test mail" | mail -s "TEST-002" nouser@localhost.localdomain' + docker exec mail /bin/sh -c 'echo "This is a test mail" | mail -s "TEST-003" alias1@localhost.localdomain' + docker exec mail /bin/sh -c 'echo "This is a test mail" | mail -s "TEST-004" alias2@localhost.localdomain' + +tests: + # Start tests + ./test/test.sh + diff --git a/postfix/main.cf b/postfix/main.cf index 7bedd2e8..87f23f8c 100644 --- a/postfix/main.cf +++ b/postfix/main.cf @@ -9,7 +9,7 @@ readme_directory = no # myhostname = alias_maps = hash:/etc/aliases alias_database = hash:/etc/aliases -mydestination = localhost.localdomain, localhost +mydestination = relayhost = mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128 172.17.0.0/16 mailbox_size_limit = 0 diff --git a/test/accounts.cf b/test/accounts.cf new file mode 100644 index 00000000..8f209cc6 --- /dev/null +++ b/test/accounts.cf @@ -0,0 +1,2 @@ +user1@localhost.localdomain|mypassword +user2@otherdomain.tld|mypassword diff --git a/test/test.sh b/test/test.sh new file mode 100755 index 00000000..75575a6c --- /dev/null +++ b/test/test.sh @@ -0,0 +1,19 @@ +#!/bin/bash + +# Set up test framework +# wget -q https://raw.github.com/lehmannro/assert.sh/master/assert.sh +source assert.sh + +# Testing user creation +assert "docker exec mail ls -A /var/mail/localhost.localdomain/user1" "cur\nnew\ntmp" +assert "docker exec mail ls /var/mail/otherdomain.tld/user2" "cur\nnew\ntmp" + +# Testing that mail is received for existing user +assert_raises "docker exec mail grep 'status=sent (delivered to maildir)' /var/log/mail.log" "false" +assert "docker exec mail ls -A /var/mail/localhost.localdomain/user1/new | wc -l" " 1" + +# Ending tests +assert_end + + + diff --git a/test/virtual b/test/virtual new file mode 100644 index 00000000..e93eb8fb --- /dev/null +++ b/test/virtual @@ -0,0 +1,2 @@ +alias1@localhost.localdomain user1@localhost.localdomain +alias2@localhost.localdomain external1@otherdomain.tld From e8163dc7285925076043adaf541e6b1474fd82db Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Sun, 18 Oct 2015 21:08:21 +0200 Subject: [PATCH 064/155] Added missing assert.sh --- test/test.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test.sh b/test/test.sh index 75575a6c..9562d8ba 100755 --- a/test/test.sh +++ b/test/test.sh @@ -1,7 +1,7 @@ #!/bin/bash # Set up test framework -# wget -q https://raw.github.com/lehmannro/assert.sh/master/assert.sh +wget -q https://raw.github.com/lehmannro/assert.sh/master/assert.sh source assert.sh # Testing user creation From 678329276e255711004e0d2a6038952c49b3265e Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Sun, 18 Oct 2015 21:30:53 +0200 Subject: [PATCH 065/155] Added new line when needed and fixed a test --- .gitignore | 2 +- .travis.yml | 2 +- Makefile | 1 - test/test.sh | 5 +---- 4 files changed, 3 insertions(+), 7 deletions(-) diff --git a/.gitignore b/.gitignore index 97490340..074b0b91 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ .DS_Store docker-compose.yml postfix/ssl/* -assert.sh \ No newline at end of file +assert.sh diff --git a/.travis.yml b/.travis.yml index 04835d1a..3d271e53 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,4 +3,4 @@ sudo: required services: - docker script: - - make all \ No newline at end of file + - make all diff --git a/Makefile b/Makefile index 45ea6de8..e33e4809 100644 --- a/Makefile +++ b/Makefile @@ -27,4 +27,3 @@ fixtures: tests: # Start tests ./test/test.sh - diff --git a/test/test.sh b/test/test.sh index 9562d8ba..37b308cf 100755 --- a/test/test.sh +++ b/test/test.sh @@ -10,10 +10,7 @@ assert "docker exec mail ls /var/mail/otherdomain.tld/user2" "cur\nnew\ntmp" # Testing that mail is received for existing user assert_raises "docker exec mail grep 'status=sent (delivered to maildir)' /var/log/mail.log" "false" -assert "docker exec mail ls -A /var/mail/localhost.localdomain/user1/new | wc -l" " 1" +assert "docker exec mail ls -A /var/mail/localhost.localdomain/user1/new | wc -l" "1" # Ending tests assert_end - - - From c6ad590457912eb78d8b2845603220e2a460001b Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Sun, 18 Oct 2015 21:38:22 +0200 Subject: [PATCH 066/155] Use TRAVIS env and updated README with Travis build status --- Makefile | 2 +- README.md | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index e33e4809..80bf968a 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ NAME = tvial/docker-mailserver -VERSION = travis +VERSION = $(TRAVIS_BUILD_ID) all: build run prepare fixtures tests diff --git a/README.md b/README.md index f02720af..82cf57b4 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # docker-mailserver +[![Build Status](https://travis-ci.org/tomav/docker-mailserver.svg)](https://travis-ci.org/tomav/docker-mailserver) + A fullstack but simple mail server (smtp, imap, antispam, antivirus...). Only configuration files, no SQL database. Keep it simple and versioned. Easy to deploy and upgrade. From 534b417800185ae2430e6907f61331bbe26f6683 Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Sun, 18 Oct 2015 22:02:47 +0200 Subject: [PATCH 067/155] Added test for crontab and services --- .gitignore | 2 +- test/test.sh | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 074b0b91..2fc3256c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ .DS_Store docker-compose.yml postfix/ssl/* -assert.sh +assert.sh* diff --git a/test/test.sh b/test/test.sh index 37b308cf..6cca8dcd 100755 --- a/test/test.sh +++ b/test/test.sh @@ -4,6 +4,12 @@ wget -q https://raw.github.com/lehmannro/assert.sh/master/assert.sh source assert.sh +# Testing that services are running +assert_raises "docker exec mail ps aux --forest | grep '/usr/lib/postfix/master'" "true" +assert_raises "docker exec mail ps aux --forest | grep '/usr/sbin/saslauthd'" "true" +assert_raises "docker exec mail ps aux --forest | grep '/usr/sbin/clamd'" "true" +assert_raises "docker exec mail ps aux --forest | grep '/usr/sbin/amavisd-new'" "true" + # Testing user creation assert "docker exec mail ls -A /var/mail/localhost.localdomain/user1" "cur\nnew\ntmp" assert "docker exec mail ls /var/mail/otherdomain.tld/user2" "cur\nnew\ntmp" @@ -12,5 +18,8 @@ assert "docker exec mail ls /var/mail/otherdomain.tld/user2" "cur\nnew\ntmp" assert_raises "docker exec mail grep 'status=sent (delivered to maildir)' /var/log/mail.log" "false" assert "docker exec mail ls -A /var/mail/localhost.localdomain/user1/new | wc -l" "1" +# Testing presence of freshclam CRON +assert "docker exec mail crontab -l" "0 1 * * * /usr/bin/freshclam --quiet" + # Ending tests assert_end From 7a8dd41c69f0924eb7da3d85c4a2a259260f30ac Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Sun, 18 Oct 2015 22:08:21 +0200 Subject: [PATCH 068/155] Added comment --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index 80bf968a..c7a0a323 100644 --- a/Makefile +++ b/Makefile @@ -19,6 +19,7 @@ prepare: docker exec mail /bin/sh -c 'echo "" > /var/log/mail.log' fixtures: + # Sending test mails docker exec mail /bin/sh -c 'echo "This is a test mail" | mail -s "TEST-001" user@localhost.localdomain' docker exec mail /bin/sh -c 'echo "This is a test mail" | mail -s "TEST-002" nouser@localhost.localdomain' docker exec mail /bin/sh -c 'echo "This is a test mail" | mail -s "TEST-003" alias1@localhost.localdomain' From 201dd220928daa1db4c3c98a87f4adb90d37847e Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Sun, 18 Oct 2015 22:29:32 +0200 Subject: [PATCH 069/155] Added information about Travis, Docker Hub and tests. --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 82cf57b4..c98641ea 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,8 @@ Why I created this image: [Simple mail server with Docker](http://tvi.al/simple- - antispam rules are managed in `./spamassassin/rules.cf` - files must be mounted to `/tmp` in your container (see `docker-compose.yml` template) - ssl is strongly recommended, you can provide a self-signed certificate, see below +- [includes integration tests](https://travis-ci.org/tomav/docker-mailserver) +- [builds automated on docker hub](https://hub.docker.com/r/tvial/docker-mailserver/) ## installation @@ -119,4 +121,4 @@ Feel free to improve this docker image. # wanna help? -Fork, improve and PR. ;-) +Fork, improve, add tests and PR. ;-) From dab9d59399300ea41623888b0bcbbe3e764cab39 Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Mon, 19 Oct 2015 12:06:11 +0200 Subject: [PATCH 070/155] Added tests on error logs --- test/test.sh | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) mode change 100755 => 100644 test/test.sh diff --git a/test/test.sh b/test/test.sh old mode 100755 new mode 100644 index 6cca8dcd..61b621c4 --- a/test/test.sh +++ b/test/test.sh @@ -12,7 +12,7 @@ assert_raises "docker exec mail ps aux --forest | grep '/usr/sbin/amavisd-new'" # Testing user creation assert "docker exec mail ls -A /var/mail/localhost.localdomain/user1" "cur\nnew\ntmp" -assert "docker exec mail ls /var/mail/otherdomain.tld/user2" "cur\nnew\ntmp" +assert "docker exec mail ls -A /var/mail/otherdomain.tld/user2" "cur\nnew\ntmp" # Testing that mail is received for existing user assert_raises "docker exec mail grep 'status=sent (delivered to maildir)' /var/log/mail.log" "false" @@ -21,5 +21,9 @@ assert "docker exec mail ls -A /var/mail/localhost.localdomain/user1/new | wc -l # Testing presence of freshclam CRON assert "docker exec mail crontab -l" "0 1 * * * /usr/bin/freshclam --quiet" +# Testing that log don't display errors +assert_raises "docker exec mail grep 'non-null host address bits in' /var/log/mail.log" "false" +assert_raises "docker exec mail grep ': error:' /var/log/mail.log" "false" + # Ending tests assert_end From c6ed9f16a4097a2e8f61e20b736f2b68095a149e Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Mon, 19 Oct 2015 12:55:53 +0200 Subject: [PATCH 071/155] Fixed Travis CI image for master branch only --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c98641ea..e2cf9268 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # docker-mailserver -[![Build Status](https://travis-ci.org/tomav/docker-mailserver.svg)](https://travis-ci.org/tomav/docker-mailserver) +[![Build Status](https://travis-ci.org/tomav/docker-mailserver.svg?branch=master)](https://travis-ci.org/tomav/docker-mailserver) A fullstack but simple mail server (smtp, imap, antispam, antivirus...). Only configuration files, no SQL database. Keep it simple and versioned. From 83e44cd9f89639490fcdfb0d7184b664346eaf04 Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Mon, 19 Oct 2015 15:41:31 +0200 Subject: [PATCH 072/155] Added netcat --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index ff1c1cb9..f57507cf 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,7 +4,7 @@ MAINTAINER Thomas VIAL # Packages RUN apt-get update -q --fix-missing RUN apt-get -y upgrade -RUN DEBIAN_FRONTEND=noninteractive apt-get -y install vim postfix sasl2-bin courier-imap courier-imap-ssl courier-authdaemon supervisor gamin amavisd-new spamassassin clamav clamav-daemon libnet-dns-perl libmail-spf-perl pyzor razor arj bzip2 cabextract cpio file gzip nomarch p7zip pax unzip zip zoo rsyslog mailutils +RUN DEBIAN_FRONTEND=noninteractive apt-get -y install vim postfix sasl2-bin courier-imap courier-imap-ssl courier-authdaemon supervisor gamin amavisd-new spamassassin clamav clamav-daemon libnet-dns-perl libmail-spf-perl pyzor razor arj bzip2 cabextract cpio file gzip nomarch p7zip pax unzip zip zoo rsyslog mailutils netcat RUN apt-get autoclean # Configures Saslauthd From 079898cc3a6374503bf016ff2f3df52a1ebc476a Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Mon, 19 Oct 2015 15:41:51 +0200 Subject: [PATCH 073/155] Testing with real emails --- Makefile | 15 ++++---- test/email-templates/amavis-spam.txt | 14 +++++++ test/email-templates/amavis-virus.txt | 33 +++++++++++++++++ .../existing-alias-external.txt | 12 ++++++ test/email-templates/existing-alias-local.txt | 12 ++++++ test/email-templates/existing-user.txt | 12 ++++++ test/email-templates/non-existing-user.txt | 12 ++++++ test/test.sh | 37 ++++++++++++++----- 8 files changed, 131 insertions(+), 16 deletions(-) create mode 100644 test/email-templates/amavis-spam.txt create mode 100644 test/email-templates/amavis-virus.txt create mode 100644 test/email-templates/existing-alias-external.txt create mode 100644 test/email-templates/existing-alias-local.txt create mode 100644 test/email-templates/existing-user.txt create mode 100644 test/email-templates/non-existing-user.txt mode change 100644 => 100755 test/test.sh diff --git a/Makefile b/Makefile index c7a0a323..e6a4aaa3 100644 --- a/Makefile +++ b/Makefile @@ -11,8 +11,8 @@ run: cp test/accounts.cf postfix/ cp test/virtual postfix/ # Run container - docker run -d --name mail -v "`pwd`/postfix":/tmp/postfix -v "`pwd`/spamassassin":/tmp/spamassassin -h mail.my-domain.com -t $(NAME):$(VERSION) - sleep 15 + docker run -d --name mail -v "`pwd`/postfix":/tmp/postfix -v "`pwd`/spamassassin":/tmp/spamassassin -v "`pwd`/test":/tmp/test -h mail.my-domain.com -t $(NAME):$(VERSION) + sleep 10 prepare: # Reinitialize logs @@ -20,11 +20,12 @@ prepare: fixtures: # Sending test mails - docker exec mail /bin/sh -c 'echo "This is a test mail" | mail -s "TEST-001" user@localhost.localdomain' - docker exec mail /bin/sh -c 'echo "This is a test mail" | mail -s "TEST-002" nouser@localhost.localdomain' - docker exec mail /bin/sh -c 'echo "This is a test mail" | mail -s "TEST-003" alias1@localhost.localdomain' - docker exec mail /bin/sh -c 'echo "This is a test mail" | mail -s "TEST-004" alias2@localhost.localdomain' + for file in test/email-templates/*.txt ; do \ + docker exec mail /bin/sh -c "nc 0.0.0.0 25 < /tmp/$$file" ; \ + done + # Wait for mails to be analyzed + sleep 10 tests: # Start tests - ./test/test.sh + /bin/bash ./test/test.sh diff --git a/test/email-templates/amavis-spam.txt b/test/email-templates/amavis-spam.txt new file mode 100644 index 00000000..15e72b15 --- /dev/null +++ b/test/email-templates/amavis-spam.txt @@ -0,0 +1,14 @@ +HELO mail.external.tld +MAIL FROM: spam@external.tld +RCPT TO: user1@localhost.localdomain +DATA +From: Docker Mail Server +To: Existing Local User +Date: Sat, 22 May 2010 07:43:25 -0400 +Subject: Test Message +This is a test mail. +XJS*C4JDBQADN1.NSBN3*2IDNEN*GTUBE-STANDARD-ANTI-UBE-TEST-EMAIL*C.34X + +. +QUIT + diff --git a/test/email-templates/amavis-virus.txt b/test/email-templates/amavis-virus.txt new file mode 100644 index 00000000..faa7d898 --- /dev/null +++ b/test/email-templates/amavis-virus.txt @@ -0,0 +1,33 @@ +HELO mail.external.tld +MAIL FROM: virus@external.tld +RCPT TO: user1@localhost.localdomain +DATA +From: Docker Mail Server +To: Existing Local User +Date: Sat, 22 May 2010 07:43:25 -0400 +Subject: Test Message + +Content-type: multipart/mixed; boundary="emailboundary" +MIME-version: 1.0 + +This is a multi-part message in MIME format. +--emailboundary +Content-type: text/plain + +This is the body of the message. + +--emailboundary +Content-type: application/octet-stream +Content-transfer-encoding: base64 + +UEsDBAoAAAAAAOCYuCg8z1FoRAAAAEQAAAAJAAAAZWljYXIuY29tWDVPIVAlQEFQ +WzRcUFpYNTQoUF4pN0NDKTd9JEVJQ0FSLVNUQU5EQVJELUFOVElWSVJVUy1URVNU +LUZJTEUhJEgrSCpQSwECFAAKAAAAAADgmLgoPM9RaEQAAABEAAAACQAAAAAAAAAB +ACAA/4EAAAAAZWljYXIuY29tUEsFBgAAAAABAAEANwAAAGsAAAAAAA== + + +--emailboundary-- + +. +QUIT + diff --git a/test/email-templates/existing-alias-external.txt b/test/email-templates/existing-alias-external.txt new file mode 100644 index 00000000..4ca818da --- /dev/null +++ b/test/email-templates/existing-alias-external.txt @@ -0,0 +1,12 @@ +HELO mail.external.tld +MAIL FROM: user@external.tld +RCPT TO: alias1@localhost.localdomain +DATA +From: Docker Mail Server +To: Existing Local User +Date: Sat, 22 May 2010 07:43:25 -0400 +Subject: Test Message +This is a test mail. + +. +QUIT \ No newline at end of file diff --git a/test/email-templates/existing-alias-local.txt b/test/email-templates/existing-alias-local.txt new file mode 100644 index 00000000..97321ebe --- /dev/null +++ b/test/email-templates/existing-alias-local.txt @@ -0,0 +1,12 @@ +HELO mail.external.tld +MAIL FROM: user@external.tld +RCPT TO: alias2@localhost.localdomain +DATA +From: Docker Mail Server +To: Existing Local User +Date: Sat, 22 May 2010 07:43:25 -0400 +Subject: Test Message +This is a test mail. + +. +QUIT \ No newline at end of file diff --git a/test/email-templates/existing-user.txt b/test/email-templates/existing-user.txt new file mode 100644 index 00000000..5a0302f3 --- /dev/null +++ b/test/email-templates/existing-user.txt @@ -0,0 +1,12 @@ +HELO mail.external.tld +MAIL FROM: user@external.tld +RCPT TO: user1@localhost.localdomain +DATA +From: Docker Mail Server +To: Existing Local User +Date: Sat, 22 May 2010 07:43:25 -0400 +Subject: Test Message +This is a test mail. + +. +QUIT \ No newline at end of file diff --git a/test/email-templates/non-existing-user.txt b/test/email-templates/non-existing-user.txt new file mode 100644 index 00000000..b734d282 --- /dev/null +++ b/test/email-templates/non-existing-user.txt @@ -0,0 +1,12 @@ +HELO mail.external.tld +MAIL FROM: user@external.tld +RCPT TO: nouser@localhost.localdomain +DATA +From: Docker Mail Server +To: Existing Local User +Date: Sat, 22 May 2010 07:43:25 -0400 +Subject: Test Message +This is a test mail. + +. +QUIT \ No newline at end of file diff --git a/test/test.sh b/test/test.sh old mode 100644 new mode 100755 index 61b621c4..f823316b --- a/test/test.sh +++ b/test/test.sh @@ -1,29 +1,48 @@ #!/bin/bash # Set up test framework -wget -q https://raw.github.com/lehmannro/assert.sh/master/assert.sh +wget -q https://raw.github.com/lehmannro/assert.sh/master/assert.sh -O assert.sh source assert.sh # Testing that services are running -assert_raises "docker exec mail ps aux --forest | grep '/usr/lib/postfix/master'" "true" -assert_raises "docker exec mail ps aux --forest | grep '/usr/sbin/saslauthd'" "true" -assert_raises "docker exec mail ps aux --forest | grep '/usr/sbin/clamd'" "true" -assert_raises "docker exec mail ps aux --forest | grep '/usr/sbin/amavisd-new'" "true" +assert_raises "docker exec mail ps aux --forest | grep '/usr/lib/postfix/master'" 0 +assert_raises "docker exec mail ps aux --forest | grep '/usr/sbin/saslauthd'" 0 +assert_raises "docker exec mail ps aux --forest | grep '/usr/sbin/clamd'" 0 +assert_raises "docker exec mail ps aux --forest | grep '/usr/sbin/amavisd-new'" 0 # Testing user creation +assert "docker exec mail sasldblistusers2" "user1@localhost.localdomain: userPassword\nuser2@otherdomain.tld: userPassword" assert "docker exec mail ls -A /var/mail/localhost.localdomain/user1" "cur\nnew\ntmp" assert "docker exec mail ls -A /var/mail/otherdomain.tld/user2" "cur\nnew\ntmp" +# Testing `vhost` creation +assert "docker exec mail cat /etc/postfix/vhost" "localhost.localdomain\notherdomain.tld" + # Testing that mail is received for existing user -assert_raises "docker exec mail grep 'status=sent (delivered to maildir)' /var/log/mail.log" "false" -assert "docker exec mail ls -A /var/mail/localhost.localdomain/user1/new | wc -l" "1" +assert_raises "docker exec mail grep 'status=sent (delivered to maildir)' /var/log/mail.log" 0 +assert "docker exec mail ls -A /var/mail/localhost.localdomain/user1/new | wc -l | sed -e 's/^[ \t]*//'" "2" + +# Testing that mail is rejected for non existing user +assert_raises "docker exec mail grep ': Recipient address rejected: User unknown in virtual mailbox table' /var/log/mail.log" 0 + +# Testing that mail is received for existing alias +assert_raises "docker exec mail grep 'to=, orig_to=' /var/log/mail.log | grep 'status=sent'" 0 + +# Testing that mail is redirected for external alias +assert_raises "docker exec mail grep -- '-> ' /var/log/mail.log" 0 + +# Testing that a SPAM is rejected +assert_raises "docker exec mail grep 'Blocked SPAM' /var/log/mail.log | grep spam@external.tld" + +# TODO: Testing that a Virus is rejected +assert_raises "docker exec mail grep 'Blocked INFECTED' /var/log/mail.log | grep virus@external.tld" # Testing presence of freshclam CRON assert "docker exec mail crontab -l" "0 1 * * * /usr/bin/freshclam --quiet" # Testing that log don't display errors -assert_raises "docker exec mail grep 'non-null host address bits in' /var/log/mail.log" "false" -assert_raises "docker exec mail grep ': error:' /var/log/mail.log" "false" +assert_raises "docker exec mail grep 'non-null host address bits in' /var/log/mail.log" 1 +assert_raises "docker exec mail grep ': error:' /var/log/mail.log" 1 # Ending tests assert_end From 74452917fb90fd4a257ebb701f20b3ad6e713f97 Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Mon, 19 Oct 2015 12:06:11 +0200 Subject: [PATCH 074/155] Added tests on error logs --- test/test.sh | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) mode change 100755 => 100644 test/test.sh diff --git a/test/test.sh b/test/test.sh old mode 100755 new mode 100644 index 6cca8dcd..61b621c4 --- a/test/test.sh +++ b/test/test.sh @@ -12,7 +12,7 @@ assert_raises "docker exec mail ps aux --forest | grep '/usr/sbin/amavisd-new'" # Testing user creation assert "docker exec mail ls -A /var/mail/localhost.localdomain/user1" "cur\nnew\ntmp" -assert "docker exec mail ls /var/mail/otherdomain.tld/user2" "cur\nnew\ntmp" +assert "docker exec mail ls -A /var/mail/otherdomain.tld/user2" "cur\nnew\ntmp" # Testing that mail is received for existing user assert_raises "docker exec mail grep 'status=sent (delivered to maildir)' /var/log/mail.log" "false" @@ -21,5 +21,9 @@ assert "docker exec mail ls -A /var/mail/localhost.localdomain/user1/new | wc -l # Testing presence of freshclam CRON assert "docker exec mail crontab -l" "0 1 * * * /usr/bin/freshclam --quiet" +# Testing that log don't display errors +assert_raises "docker exec mail grep 'non-null host address bits in' /var/log/mail.log" "false" +assert_raises "docker exec mail grep ': error:' /var/log/mail.log" "false" + # Ending tests assert_end From cc1715cb51056eebc0fbd4a79c4848ce29b18a8a Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Mon, 19 Oct 2015 15:41:31 +0200 Subject: [PATCH 075/155] Added netcat --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index ff1c1cb9..f57507cf 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,7 +4,7 @@ MAINTAINER Thomas VIAL # Packages RUN apt-get update -q --fix-missing RUN apt-get -y upgrade -RUN DEBIAN_FRONTEND=noninteractive apt-get -y install vim postfix sasl2-bin courier-imap courier-imap-ssl courier-authdaemon supervisor gamin amavisd-new spamassassin clamav clamav-daemon libnet-dns-perl libmail-spf-perl pyzor razor arj bzip2 cabextract cpio file gzip nomarch p7zip pax unzip zip zoo rsyslog mailutils +RUN DEBIAN_FRONTEND=noninteractive apt-get -y install vim postfix sasl2-bin courier-imap courier-imap-ssl courier-authdaemon supervisor gamin amavisd-new spamassassin clamav clamav-daemon libnet-dns-perl libmail-spf-perl pyzor razor arj bzip2 cabextract cpio file gzip nomarch p7zip pax unzip zip zoo rsyslog mailutils netcat RUN apt-get autoclean # Configures Saslauthd From 03b8614cab971bb3aae11756123a2f484c937ead Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Mon, 19 Oct 2015 15:41:51 +0200 Subject: [PATCH 076/155] Testing with real emails --- Makefile | 15 ++++---- test/email-templates/amavis-spam.txt | 14 +++++++ test/email-templates/amavis-virus.txt | 33 +++++++++++++++++ .../existing-alias-external.txt | 12 ++++++ test/email-templates/existing-alias-local.txt | 12 ++++++ test/email-templates/existing-user.txt | 12 ++++++ test/email-templates/non-existing-user.txt | 12 ++++++ test/test.sh | 37 ++++++++++++++----- 8 files changed, 131 insertions(+), 16 deletions(-) create mode 100644 test/email-templates/amavis-spam.txt create mode 100644 test/email-templates/amavis-virus.txt create mode 100644 test/email-templates/existing-alias-external.txt create mode 100644 test/email-templates/existing-alias-local.txt create mode 100644 test/email-templates/existing-user.txt create mode 100644 test/email-templates/non-existing-user.txt mode change 100644 => 100755 test/test.sh diff --git a/Makefile b/Makefile index c7a0a323..e6a4aaa3 100644 --- a/Makefile +++ b/Makefile @@ -11,8 +11,8 @@ run: cp test/accounts.cf postfix/ cp test/virtual postfix/ # Run container - docker run -d --name mail -v "`pwd`/postfix":/tmp/postfix -v "`pwd`/spamassassin":/tmp/spamassassin -h mail.my-domain.com -t $(NAME):$(VERSION) - sleep 15 + docker run -d --name mail -v "`pwd`/postfix":/tmp/postfix -v "`pwd`/spamassassin":/tmp/spamassassin -v "`pwd`/test":/tmp/test -h mail.my-domain.com -t $(NAME):$(VERSION) + sleep 10 prepare: # Reinitialize logs @@ -20,11 +20,12 @@ prepare: fixtures: # Sending test mails - docker exec mail /bin/sh -c 'echo "This is a test mail" | mail -s "TEST-001" user@localhost.localdomain' - docker exec mail /bin/sh -c 'echo "This is a test mail" | mail -s "TEST-002" nouser@localhost.localdomain' - docker exec mail /bin/sh -c 'echo "This is a test mail" | mail -s "TEST-003" alias1@localhost.localdomain' - docker exec mail /bin/sh -c 'echo "This is a test mail" | mail -s "TEST-004" alias2@localhost.localdomain' + for file in test/email-templates/*.txt ; do \ + docker exec mail /bin/sh -c "nc 0.0.0.0 25 < /tmp/$$file" ; \ + done + # Wait for mails to be analyzed + sleep 10 tests: # Start tests - ./test/test.sh + /bin/bash ./test/test.sh diff --git a/test/email-templates/amavis-spam.txt b/test/email-templates/amavis-spam.txt new file mode 100644 index 00000000..15e72b15 --- /dev/null +++ b/test/email-templates/amavis-spam.txt @@ -0,0 +1,14 @@ +HELO mail.external.tld +MAIL FROM: spam@external.tld +RCPT TO: user1@localhost.localdomain +DATA +From: Docker Mail Server +To: Existing Local User +Date: Sat, 22 May 2010 07:43:25 -0400 +Subject: Test Message +This is a test mail. +XJS*C4JDBQADN1.NSBN3*2IDNEN*GTUBE-STANDARD-ANTI-UBE-TEST-EMAIL*C.34X + +. +QUIT + diff --git a/test/email-templates/amavis-virus.txt b/test/email-templates/amavis-virus.txt new file mode 100644 index 00000000..faa7d898 --- /dev/null +++ b/test/email-templates/amavis-virus.txt @@ -0,0 +1,33 @@ +HELO mail.external.tld +MAIL FROM: virus@external.tld +RCPT TO: user1@localhost.localdomain +DATA +From: Docker Mail Server +To: Existing Local User +Date: Sat, 22 May 2010 07:43:25 -0400 +Subject: Test Message + +Content-type: multipart/mixed; boundary="emailboundary" +MIME-version: 1.0 + +This is a multi-part message in MIME format. +--emailboundary +Content-type: text/plain + +This is the body of the message. + +--emailboundary +Content-type: application/octet-stream +Content-transfer-encoding: base64 + +UEsDBAoAAAAAAOCYuCg8z1FoRAAAAEQAAAAJAAAAZWljYXIuY29tWDVPIVAlQEFQ +WzRcUFpYNTQoUF4pN0NDKTd9JEVJQ0FSLVNUQU5EQVJELUFOVElWSVJVUy1URVNU +LUZJTEUhJEgrSCpQSwECFAAKAAAAAADgmLgoPM9RaEQAAABEAAAACQAAAAAAAAAB +ACAA/4EAAAAAZWljYXIuY29tUEsFBgAAAAABAAEANwAAAGsAAAAAAA== + + +--emailboundary-- + +. +QUIT + diff --git a/test/email-templates/existing-alias-external.txt b/test/email-templates/existing-alias-external.txt new file mode 100644 index 00000000..4ca818da --- /dev/null +++ b/test/email-templates/existing-alias-external.txt @@ -0,0 +1,12 @@ +HELO mail.external.tld +MAIL FROM: user@external.tld +RCPT TO: alias1@localhost.localdomain +DATA +From: Docker Mail Server +To: Existing Local User +Date: Sat, 22 May 2010 07:43:25 -0400 +Subject: Test Message +This is a test mail. + +. +QUIT \ No newline at end of file diff --git a/test/email-templates/existing-alias-local.txt b/test/email-templates/existing-alias-local.txt new file mode 100644 index 00000000..97321ebe --- /dev/null +++ b/test/email-templates/existing-alias-local.txt @@ -0,0 +1,12 @@ +HELO mail.external.tld +MAIL FROM: user@external.tld +RCPT TO: alias2@localhost.localdomain +DATA +From: Docker Mail Server +To: Existing Local User +Date: Sat, 22 May 2010 07:43:25 -0400 +Subject: Test Message +This is a test mail. + +. +QUIT \ No newline at end of file diff --git a/test/email-templates/existing-user.txt b/test/email-templates/existing-user.txt new file mode 100644 index 00000000..5a0302f3 --- /dev/null +++ b/test/email-templates/existing-user.txt @@ -0,0 +1,12 @@ +HELO mail.external.tld +MAIL FROM: user@external.tld +RCPT TO: user1@localhost.localdomain +DATA +From: Docker Mail Server +To: Existing Local User +Date: Sat, 22 May 2010 07:43:25 -0400 +Subject: Test Message +This is a test mail. + +. +QUIT \ No newline at end of file diff --git a/test/email-templates/non-existing-user.txt b/test/email-templates/non-existing-user.txt new file mode 100644 index 00000000..b734d282 --- /dev/null +++ b/test/email-templates/non-existing-user.txt @@ -0,0 +1,12 @@ +HELO mail.external.tld +MAIL FROM: user@external.tld +RCPT TO: nouser@localhost.localdomain +DATA +From: Docker Mail Server +To: Existing Local User +Date: Sat, 22 May 2010 07:43:25 -0400 +Subject: Test Message +This is a test mail. + +. +QUIT \ No newline at end of file diff --git a/test/test.sh b/test/test.sh old mode 100644 new mode 100755 index 61b621c4..f823316b --- a/test/test.sh +++ b/test/test.sh @@ -1,29 +1,48 @@ #!/bin/bash # Set up test framework -wget -q https://raw.github.com/lehmannro/assert.sh/master/assert.sh +wget -q https://raw.github.com/lehmannro/assert.sh/master/assert.sh -O assert.sh source assert.sh # Testing that services are running -assert_raises "docker exec mail ps aux --forest | grep '/usr/lib/postfix/master'" "true" -assert_raises "docker exec mail ps aux --forest | grep '/usr/sbin/saslauthd'" "true" -assert_raises "docker exec mail ps aux --forest | grep '/usr/sbin/clamd'" "true" -assert_raises "docker exec mail ps aux --forest | grep '/usr/sbin/amavisd-new'" "true" +assert_raises "docker exec mail ps aux --forest | grep '/usr/lib/postfix/master'" 0 +assert_raises "docker exec mail ps aux --forest | grep '/usr/sbin/saslauthd'" 0 +assert_raises "docker exec mail ps aux --forest | grep '/usr/sbin/clamd'" 0 +assert_raises "docker exec mail ps aux --forest | grep '/usr/sbin/amavisd-new'" 0 # Testing user creation +assert "docker exec mail sasldblistusers2" "user1@localhost.localdomain: userPassword\nuser2@otherdomain.tld: userPassword" assert "docker exec mail ls -A /var/mail/localhost.localdomain/user1" "cur\nnew\ntmp" assert "docker exec mail ls -A /var/mail/otherdomain.tld/user2" "cur\nnew\ntmp" +# Testing `vhost` creation +assert "docker exec mail cat /etc/postfix/vhost" "localhost.localdomain\notherdomain.tld" + # Testing that mail is received for existing user -assert_raises "docker exec mail grep 'status=sent (delivered to maildir)' /var/log/mail.log" "false" -assert "docker exec mail ls -A /var/mail/localhost.localdomain/user1/new | wc -l" "1" +assert_raises "docker exec mail grep 'status=sent (delivered to maildir)' /var/log/mail.log" 0 +assert "docker exec mail ls -A /var/mail/localhost.localdomain/user1/new | wc -l | sed -e 's/^[ \t]*//'" "2" + +# Testing that mail is rejected for non existing user +assert_raises "docker exec mail grep ': Recipient address rejected: User unknown in virtual mailbox table' /var/log/mail.log" 0 + +# Testing that mail is received for existing alias +assert_raises "docker exec mail grep 'to=, orig_to=' /var/log/mail.log | grep 'status=sent'" 0 + +# Testing that mail is redirected for external alias +assert_raises "docker exec mail grep -- '-> ' /var/log/mail.log" 0 + +# Testing that a SPAM is rejected +assert_raises "docker exec mail grep 'Blocked SPAM' /var/log/mail.log | grep spam@external.tld" + +# TODO: Testing that a Virus is rejected +assert_raises "docker exec mail grep 'Blocked INFECTED' /var/log/mail.log | grep virus@external.tld" # Testing presence of freshclam CRON assert "docker exec mail crontab -l" "0 1 * * * /usr/bin/freshclam --quiet" # Testing that log don't display errors -assert_raises "docker exec mail grep 'non-null host address bits in' /var/log/mail.log" "false" -assert_raises "docker exec mail grep ': error:' /var/log/mail.log" "false" +assert_raises "docker exec mail grep 'non-null host address bits in' /var/log/mail.log" 1 +assert_raises "docker exec mail grep ': error:' /var/log/mail.log" 1 # Ending tests assert_end From e4b9dffb5db16b93bd4905da518fcf561e755897 Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Mon, 19 Oct 2015 17:25:47 +0200 Subject: [PATCH 077/155] Testing oneliner on for loop --- Makefile | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Makefile b/Makefile index e6a4aaa3..5cb017c4 100644 --- a/Makefile +++ b/Makefile @@ -20,9 +20,7 @@ prepare: fixtures: # Sending test mails - for file in test/email-templates/*.txt ; do \ - docker exec mail /bin/sh -c "nc 0.0.0.0 25 < /tmp/$$file" ; \ - done + for file in test/email-templates/*.txt ; do docker exec mail /bin/sh -c "nc 0.0.0.0 25 < /tmp/$$file" ; done # Wait for mails to be analyzed sleep 10 From 0959868233925d5eeb9284aae620dbd669abe098 Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Mon, 19 Oct 2015 18:01:23 +0200 Subject: [PATCH 078/155] Removed for loop from Makefile --- Makefile | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 5cb017c4..137f37fc 100644 --- a/Makefile +++ b/Makefile @@ -20,7 +20,12 @@ prepare: fixtures: # Sending test mails - for file in test/email-templates/*.txt ; do docker exec mail /bin/sh -c "nc 0.0.0.0 25 < /tmp/$$file" ; done + docker exec mail /bin/sh -c "nc 0.0.0.0 25 < /tmp/test/email-templates/amavis-spam.txt" + docker exec mail /bin/sh -c "nc 0.0.0.0 25 < /tmp/test/email-templates/amavis-virus.txt" + docker exec mail /bin/sh -c "nc 0.0.0.0 25 < /tmp/test/email-templates/existing-alias-external.txt" + docker exec mail /bin/sh -c "nc 0.0.0.0 25 < /tmp/test/email-templates/existing-alias-local.txt" + docker exec mail /bin/sh -c "nc 0.0.0.0 25 < /tmp/test/email-templates/existing-user.txt" + docker exec mail /bin/sh -c "nc 0.0.0.0 25 < /tmp/test/email-templates/non-existing-user.txt" # Wait for mails to be analyzed sleep 10 From 3949f546751b00110b617db1d2dcf103611c497c Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Mon, 19 Oct 2015 18:29:33 +0200 Subject: [PATCH 079/155] Increased sleep time --- Makefile | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/Makefile b/Makefile index 137f37fc..4cbf3c63 100644 --- a/Makefile +++ b/Makefile @@ -12,7 +12,7 @@ run: cp test/virtual postfix/ # Run container docker run -d --name mail -v "`pwd`/postfix":/tmp/postfix -v "`pwd`/spamassassin":/tmp/spamassassin -v "`pwd`/test":/tmp/test -h mail.my-domain.com -t $(NAME):$(VERSION) - sleep 10 + sleep 15 prepare: # Reinitialize logs @@ -20,12 +20,13 @@ prepare: fixtures: # Sending test mails - docker exec mail /bin/sh -c "nc 0.0.0.0 25 < /tmp/test/email-templates/amavis-spam.txt" - docker exec mail /bin/sh -c "nc 0.0.0.0 25 < /tmp/test/email-templates/amavis-virus.txt" - docker exec mail /bin/sh -c "nc 0.0.0.0 25 < /tmp/test/email-templates/existing-alias-external.txt" - docker exec mail /bin/sh -c "nc 0.0.0.0 25 < /tmp/test/email-templates/existing-alias-local.txt" - docker exec mail /bin/sh -c "nc 0.0.0.0 25 < /tmp/test/email-templates/existing-user.txt" - docker exec mail /bin/sh -c "nc 0.0.0.0 25 < /tmp/test/email-templates/non-existing-user.txt" + for file in test/email-templates/*.txt ; do docker exec mail /bin/sh -c "nc 0.0.0.0 25 < /tmp/$$file" ; done + # docker exec mail /bin/sh -c "nc 0.0.0.0 25 < /tmp/test/email-templates/amavis-spam.txt" + # docker exec mail /bin/sh -c "nc 0.0.0.0 25 < /tmp/test/email-templates/amavis-virus.txt" + # docker exec mail /bin/sh -c "nc 0.0.0.0 25 < /tmp/test/email-templates/existing-alias-external.txt" + # docker exec mail /bin/sh -c "nc 0.0.0.0 25 < /tmp/test/email-templates/existing-alias-local.txt" + # docker exec mail /bin/sh -c "nc 0.0.0.0 25 < /tmp/test/email-templates/existing-user.txt" + # docker exec mail /bin/sh -c "nc 0.0.0.0 25 < /tmp/test/email-templates/non-existing-user.txt" # Wait for mails to be analyzed sleep 10 From a43dab3e2e7602aab7b0c1b7f9c83f89b21e69e5 Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Mon, 19 Oct 2015 18:37:06 +0200 Subject: [PATCH 080/155] Removed comments --- Makefile | 6 ------ 1 file changed, 6 deletions(-) diff --git a/Makefile b/Makefile index 4cbf3c63..0e398c07 100644 --- a/Makefile +++ b/Makefile @@ -21,12 +21,6 @@ prepare: fixtures: # Sending test mails for file in test/email-templates/*.txt ; do docker exec mail /bin/sh -c "nc 0.0.0.0 25 < /tmp/$$file" ; done - # docker exec mail /bin/sh -c "nc 0.0.0.0 25 < /tmp/test/email-templates/amavis-spam.txt" - # docker exec mail /bin/sh -c "nc 0.0.0.0 25 < /tmp/test/email-templates/amavis-virus.txt" - # docker exec mail /bin/sh -c "nc 0.0.0.0 25 < /tmp/test/email-templates/existing-alias-external.txt" - # docker exec mail /bin/sh -c "nc 0.0.0.0 25 < /tmp/test/email-templates/existing-alias-local.txt" - # docker exec mail /bin/sh -c "nc 0.0.0.0 25 < /tmp/test/email-templates/existing-user.txt" - # docker exec mail /bin/sh -c "nc 0.0.0.0 25 < /tmp/test/email-templates/non-existing-user.txt" # Wait for mails to be analyzed sleep 10 From 465d5de166519a76bb989db551b76127f46bb866 Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Mon, 19 Oct 2015 19:37:49 +0200 Subject: [PATCH 081/155] Testing Travis config with nc commands --- Makefile | 7 ++++++- test/test.sh | 0 2 files changed, 6 insertions(+), 1 deletion(-) mode change 100755 => 100644 test/test.sh diff --git a/Makefile b/Makefile index 0e398c07..e049fd92 100644 --- a/Makefile +++ b/Makefile @@ -20,7 +20,12 @@ prepare: fixtures: # Sending test mails - for file in test/email-templates/*.txt ; do docker exec mail /bin/sh -c "nc 0.0.0.0 25 < /tmp/$$file" ; done + docker exec mail /bin/sh -c "nc 0.0.0.0 25 < /tmp/test/email-templates/amavis-spam.txt" + docker exec mail /bin/sh -c "nc 0.0.0.0 25 < /tmp/test/email-templates/amavis-virus.txt" + docker exec mail /bin/sh -c "nc 0.0.0.0 25 < /tmp/test/email-templates/existing-alias-external.txt" + docker exec mail /bin/sh -c "nc 0.0.0.0 25 < /tmp/test/email-templates/existing-alias-local.txt" + docker exec mail /bin/sh -c "nc 0.0.0.0 25 < /tmp/test/email-templates/existing-user.txt" + docker exec mail /bin/sh -c "nc 0.0.0.0 25 < /tmp/test/email-templates/non-existing-user.txt" # Wait for mails to be analyzed sleep 10 diff --git a/test/test.sh b/test/test.sh old mode 100755 new mode 100644 From 24024552671bb05f65126d84f94dc30701ba1aa1 Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Thu, 22 Oct 2015 16:38:27 +0200 Subject: [PATCH 082/155] Improved documentation to fix #31 --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index e2cf9268..be0cd640 100644 --- a/README.md +++ b/README.md @@ -79,7 +79,8 @@ You can easily generate a self-signed SSL certificate by using the following com # Press enter # Enter a password when needed # Fill information like Country, Organisation name - # Fill "mail.my-domain.com" as FQDN + # Fill "my-domain.com" as FQDN for CA, and "mail.my-domain.com" for the certificate. + # They HAVE to be different, otherwise you'll get a `TXT_DB error number 2` # Don't fill extras # Enter same password when needed # Sign the certificate? [y/n]:y From 3b55aa735d44388744e10e2c9fd8a5a3be9e4c14 Mon Sep 17 00:00:00 2001 From: Dimitri Kopriwa Date: Fri, 20 Nov 2015 17:31:47 +0100 Subject: [PATCH 083/155] added rm -rf /var/lib/apt/lists/* --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index f57507cf..2de9cfaa 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,7 +5,7 @@ MAINTAINER Thomas VIAL RUN apt-get update -q --fix-missing RUN apt-get -y upgrade RUN DEBIAN_FRONTEND=noninteractive apt-get -y install vim postfix sasl2-bin courier-imap courier-imap-ssl courier-authdaemon supervisor gamin amavisd-new spamassassin clamav clamav-daemon libnet-dns-perl libmail-spf-perl pyzor razor arj bzip2 cabextract cpio file gzip nomarch p7zip pax unzip zip zoo rsyslog mailutils netcat -RUN apt-get autoclean +RUN apt-get autoclean && rm -rf /var/lib/apt/lists/* # Configures Saslauthd RUN rm -rf /var/run/saslauthd && ln -s /var/spool/postfix/var/run/saslauthd /var/run/saslauthd From 4f1da4e8f2e747e7a670d5f938078c751fb1b5a8 Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Sun, 22 Nov 2015 01:39:09 +0100 Subject: [PATCH 084/155] Improved documentation requested in #33 --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index be0cd640..8dbb8155 100644 --- a/README.md +++ b/README.md @@ -94,6 +94,7 @@ You can easily generate a self-signed SSL certificate by using the following com # postfix/ssl/demoCA/cacert.pem (certificate authority) Note that the certificate will be generate for the container `fqdn`, that is passed as `-h` argument. +Check the following page for more information regarding [postfix and SSL/TLS configuration](http://www.mad-hacking.net/documentation/linux/applications/mail/using-ssl-tls-postfix-courier.xml). ## configure ssl certificate (convention over configuration) From d7ce15957f4f28421a40e33ec7d3ea14f53750ad Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Sun, 22 Nov 2015 01:48:19 +0100 Subject: [PATCH 085/155] Fixes #38 (authdeamon pseudo-issue) --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 2de9cfaa..df9160ec 100644 --- a/Dockerfile +++ b/Dockerfile @@ -13,7 +13,7 @@ RUN adduser postfix sasl RUN echo 'NAME="saslauthd"\nSTART=yes\nMECHANISMS="sasldb"\nTHREADS=0\nPWDIR=/var/spool/postfix/var/run/saslauthd\nPIDFILE="${PWDIR}/saslauthd.pid"\nOPTIONS="-n 0 -r -m /var/spool/postfix/var/run/saslauthd"' > /etc/default/saslauthd # Configures Courier -RUN sed -i -r 's/daemons=5/daemons=0/g' /etc/courier/authdaemonrc +RUN sed -i -r 's/daemons=5/daemons=1/g' /etc/courier/authdaemonrc RUN sed -i -r 's/authmodulelist="authpam"/authmodulelist="authuserdb"/g' /etc/courier/authdaemonrc # Enables Spamassassin and CRON updates From 07177f04cdb6c882f3c441d85e07734946f61164 Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Sun, 22 Nov 2015 01:57:52 +0100 Subject: [PATCH 086/155] Added IMAP connection integration test --- test/email-templates/test-imap.txt | 4 ++++ test/test.sh | 4 ++++ 2 files changed, 8 insertions(+) create mode 100644 test/email-templates/test-imap.txt diff --git a/test/email-templates/test-imap.txt b/test/email-templates/test-imap.txt new file mode 100644 index 00000000..90000864 --- /dev/null +++ b/test/email-templates/test-imap.txt @@ -0,0 +1,4 @@ +a1 LOGIN user1@localhost.localdomain mypassword +a3 EXAMINE INBOX +a4 FETCH 1 BODY[] +a5 LOGOUT diff --git a/test/test.sh b/test/test.sh index f823316b..8eeed27b 100644 --- a/test/test.sh +++ b/test/test.sh @@ -10,6 +10,10 @@ assert_raises "docker exec mail ps aux --forest | grep '/usr/sbin/saslauthd'" 0 assert_raises "docker exec mail ps aux --forest | grep '/usr/sbin/clamd'" 0 assert_raises "docker exec mail ps aux --forest | grep '/usr/sbin/amavisd-new'" 0 +# Testing IMAP server +assert_raises "docker exec mail nc -w 1 0.0.0.0 143 | grep '* OK' | grep 'STARTTLS' | grep 'Courier-IMAP ready'" 0 +assert_raises "docker exec mail /bin/sh -c 'nc -w 1 0.0.0.0 143 < /tmp/test/email-templates/test-imap.txt'" 0 + # Testing user creation assert "docker exec mail sasldblistusers2" "user1@localhost.localdomain: userPassword\nuser2@otherdomain.tld: userPassword" assert "docker exec mail ls -A /var/mail/localhost.localdomain/user1" "cur\nnew\ntmp" From e5719ceacbac682b298297219ba3375a898784a3 Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Sat, 5 Dec 2015 16:44:13 +0100 Subject: [PATCH 087/155] Begening configuration for Letsencrypt support --- .gitignore | 1 + README.md | 56 ++++++++---------------------------- SSL.md | 46 ++++++++++++++++++++++++++++++ start-mailserver.sh | 69 ++++++++++++++++++++++++++++++++------------- 4 files changed, 108 insertions(+), 64 deletions(-) create mode 100644 SSL.md diff --git a/.gitignore b/.gitignore index 2fc3256c..61e94224 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ docker-compose.yml postfix/ssl/* assert.sh* +letsencrypt/ \ No newline at end of file diff --git a/README.md b/README.md index 8dbb8155..c24c2fbf 100644 --- a/README.md +++ b/README.md @@ -68,53 +68,21 @@ Volumes allow to: docker-compose up -d mail -# configure ssl - -## generate self-signed ssl certificate - -You can easily generate a self-signed SSL certificate by using the following command: - - docker run -ti --rm -v "$(pwd)"/postfix/ssl:/ssl -h mail.my-domain.com -t tvial/docker-mailserver generate-ssl-certificate - - # Press enter - # Enter a password when needed - # Fill information like Country, Organisation name - # Fill "my-domain.com" as FQDN for CA, and "mail.my-domain.com" for the certificate. - # They HAVE to be different, otherwise you'll get a `TXT_DB error number 2` - # Don't fill extras - # Enter same password when needed - # Sign the certificate? [y/n]:y - # 1 out of 1 certificate requests certified, commit? [y/n]y - - # will generate: - # postfix/ssl/mail.my-domain.com-key.pem (used in postfix) - # postfix/ssl/mail.my-domain.com-req.pem (only used to generate other files) - # postfix/ssl/mail.my-domain.com-cert.pem (used in postfix) - # postfix/ssl/mail.my-domain.com-combined.pem (used in courier) - # postfix/ssl/demoCA/cacert.pem (certificate authority) - -Note that the certificate will be generate for the container `fqdn`, that is passed as `-h` argument. -Check the following page for more information regarding [postfix and SSL/TLS configuration](http://www.mad-hacking.net/documentation/linux/applications/mail/using-ssl-tls-postfix-courier.xml). - -## configure ssl certificate (convention over configuration) - -If a matching certificate (files listed above) is found in `postfix/ssl`, it will be automatically setup in postfix and courier-imap-ssl. You just have to place them in `postfix/ssl` folder. - # client configuration - # imap - username: - password: - server: - imap port: 143 or 993 with ssl (recommended) - imap path prefix: INBOX - auth method: md5 challenge-response + # imap + username: + password: + server: + imap port: 143 or 993 with ssl (recommended) + imap path prefix: INBOX + auth method: md5 challenge-response - # smtp - smtp port: 25 or 587 with ssl (recommended) - username: - password: - auth method: md5 challenge-response + # smtp + smtp port: 25 or 587 with ssl (recommended) + username: + password: + auth method: md5 challenge-response # todo diff --git a/SSL.md b/SSL.md new file mode 100644 index 00000000..0bb3e972 --- /dev/null +++ b/SSL.md @@ -0,0 +1,46 @@ +# docker-mailserver with ssl + +There are multiple options to enable SSL: + +* using [letsencrypt](https://letsencrypt.org/) +* using self-signed certificates with the provided tool + +## let's encrypt + +To enable Let's Encrypt on your mail server, you have to add en environment variable `DMS_SSL` with value `letsencrypt`. +You also have to mount your `letsencrypt` folder to `/etc/letsencrypt`. + + + +TO BE FINISHED WHEN IT WILL BE TESTED + + + +## self signed certificates + +You can easily generate a self-signed SSL certificate by using the following command: + + docker run -ti --rm -v "$(pwd)"/postfix/ssl:/ssl -h mail.my-domain.com -t tvial/docker-mailserver generate-ssl-certificate + + # Press enter + # Enter a password when needed + # Fill information like Country, Organisation name + # Fill "my-domain.com" as FQDN for CA, and "mail.my-domain.com" for the certificate. + # They HAVE to be different, otherwise you'll get a `TXT_DB error number 2` + # Don't fill extras + # Enter same password when needed + # Sign the certificate? [y/n]:y + # 1 out of 1 certificate requests certified, commit? [y/n]y + + # will generate: + # postfix/ssl/mail.my-domain.com-key.pem (used in postfix) + # postfix/ssl/mail.my-domain.com-req.pem (only used to generate other files) + # postfix/ssl/mail.my-domain.com-cert.pem (used in postfix) + # postfix/ssl/mail.my-domain.com-combined.pem (used in courier) + # postfix/ssl/demoCA/cacert.pem (certificate authority) + +Note that the certificate will be generate for the container `fqdn`, that is passed as `-h` argument. +Check the following page for more information regarding [postfix and SSL/TLS configuration](http://www.mad-hacking.net/documentation/linux/applications/mail/using-ssl-tls-postfix-courier.xml). + +If a matching certificate (files listed above) is found in `postfix/ssl`, it will be automatically setup in postfix and courier-imap-ssl. You just have to place them in `postfix/ssl` folder. + diff --git a/start-mailserver.sh b/start-mailserver.sh index 89d84238..ca5a7ecd 100644 --- a/start-mailserver.sh +++ b/start-mailserver.sh @@ -54,28 +54,57 @@ echo "Postfix configurations" touch /etc/postfix/vmailbox && postmap /etc/postfix/vmailbox touch /etc/postfix/virtual && postmap /etc/postfix/virtual -# Adding self-signed SSL certificate if provided in 'postfix/ssl' folder -if [ -e "/tmp/postfix/ssl/$(hostname)-cert.pem" ] \ -&& [ -e "/tmp/postfix/ssl/$(hostname)-key.pem" ] \ -&& [ -e "/tmp/postfix/ssl/$(hostname)-combined.pem" ] \ -&& [ -e "/tmp/postfix/ssl/demoCA/cacert.pem" ]; then - echo "Adding $(hostname) SSL certificate" - mkdir -p /etc/postfix/ssl - cp /tmp/postfix/ssl/$(hostname)-cert.pem /etc/postfix/ssl - cp /tmp/postfix/ssl/$(hostname)-key.pem /etc/postfix/ssl - cp /tmp/postfix/ssl/$(hostname)-combined.pem /etc/postfix/ssl - cp /tmp/postfix/ssl/demoCA/cacert.pem /etc/postfix/ssl +# SSL Configuration +case $DMS_SSL in + "letsencrypt" ) + # letsencrypt folders and files mounted in /etc/letsencrypt - # Postfix configuration - sed -i -r 's/smtpd_tls_cert_file=\/etc\/ssl\/certs\/ssl-cert-snakeoil.pem/smtpd_tls_cert_file=\/etc\/postfix\/ssl\/'$(hostname)'-cert.pem/g' /etc/postfix/main.cf - sed -i -r 's/smtpd_tls_key_file=\/etc\/ssl\/private\/ssl-cert-snakeoil.key/smtpd_tls_key_file=\/etc\/postfix\/ssl\/'$(hostname)'-key.pem/g' /etc/postfix/main.cf - sed -i -r 's/#smtpd_tls_CAfile=/smtpd_tls_CAfile=\/etc\/postfix\/ssl\/cacert.pem/g' /etc/postfix/main.cf - sed -i -r 's/#smtp_tls_CAfile=/smtp_tls_CAfile=\/etc\/postfix\/ssl\/cacert.pem/g' /etc/postfix/main.cf - ln -s /etc/postfix/ssl/cacert.pem /etc/ssl/certs/cacert-$(hostname).pem + # Adding certificates from Letsencrypt and IdenTrust + # curl https://letsencrypt.org/certs/isrgrootx1.pem -so /etc/ssl/certs/isrgrootx1.pem + # curl https://letsencrypt.org/certs/lets-encrypt-x1-cross-signed.pem -so /etc/ssl/certs/lets-encrypt-x1-cross-signed.pem + # curl https://letsencrypt.org/certs/lets-encrypt-x2-cross-signed.pem -so /etc/ssl/certs/lets-encrypt-x2-cross-signed.pem + # curl https://letsencrypt.org/certs/letsencryptauthorityx1.pem -so /etc/ssl/certs/letsencryptauthorityx1.pem + # curl https://letsencrypt.org/certs/letsencryptauthorityx2.pem -so /etc/ssl/certs/letsencryptauthorityx2.pem - # Courier configuration - sed -i -r 's/TLS_CERTFILE=\/etc\/courier\/imapd.pem/TLS_CERTFILE=\/etc\/postfix\/ssl\/'$(hostname)'-combined.pem/g' /etc/courier/imapd-ssl -fi + # Postfix configuration + sed -i -r 's/smtpd_tls_cert_file=\/etc\/ssl\/certs\/ssl-cert-snakeoil.pem/smtpd_tls_cert_file=\/etc\/letsencrypt\/live\/'$(hostname)'\/fullchain.pem/g' /etc/postfix/main.cf + sed -i -r 's/smtpd_tls_key_file=\/etc\/ssl\/private\/ssl-cert-snakeoil.key/smtpd_tls_key_file=\/etc\/letsencrypt\/live\/'$(hostname)'\/privkey.pem/g' /etc/postfix/main.cf + + # Courier configuration + cat /etc/letsencrypt/live/$(hostname)/privkey.pem /etc/letsencrypt/live/$(hostname)/cert.pem >> /etc/letsencrypt/live/$(hostname)/combined.pem + sed -i -r 's/TLS_CERTFILE=\/etc\/courier\/imapd.pem/TLS_CERTFILE=\/etc\/letsencrypt\/live\/'$(hostname)'\/combined.pem/g' /etc/courier/imapd-ssl + + echo "SSL configured with letsencrypt certificates" + + ;; + + "self-signed" ) + # Adding self-signed SSL certificate if provided in 'postfix/ssl' folder + if [ -e "/tmp/postfix/ssl/$(hostname)-cert.pem" ] \ + && [ -e "/tmp/postfix/ssl/$(hostname)-key.pem" ] \ + && [ -e "/tmp/postfix/ssl/$(hostname)-combined.pem" ] \ + && [ -e "/tmp/postfix/ssl/demoCA/cacert.pem" ]; then + echo "Adding $(hostname) SSL certificate" + mkdir -p /etc/postfix/ssl + cp /tmp/postfix/ssl/$(hostname)-cert.pem /etc/postfix/ssl + cp /tmp/postfix/ssl/$(hostname)-key.pem /etc/postfix/ssl + cp /tmp/postfix/ssl/$(hostname)-combined.pem /etc/postfix/ssl + cp /tmp/postfix/ssl/demoCA/cacert.pem /etc/postfix/ssl + + # Postfix configuration + sed -i -r 's/smtpd_tls_cert_file=\/etc\/ssl\/certs\/ssl-cert-snakeoil.pem/smtpd_tls_cert_file=\/etc\/postfix\/ssl\/'$(hostname)'-cert.pem/g' /etc/postfix/main.cf + sed -i -r 's/smtpd_tls_key_file=\/etc\/ssl\/private\/ssl-cert-snakeoil.key/smtpd_tls_key_file=\/etc\/postfix\/ssl\/'$(hostname)'-key.pem/g' /etc/postfix/main.cf + sed -i -r 's/#smtpd_tls_CAfile=/smtpd_tls_CAfile=\/etc\/postfix\/ssl\/cacert.pem/g' /etc/postfix/main.cf + sed -i -r 's/#smtp_tls_CAfile=/smtp_tls_CAfile=\/etc\/postfix\/ssl\/cacert.pem/g' /etc/postfix/main.cf + ln -s /etc/postfix/ssl/cacert.pem /etc/ssl/certs/cacert-$(hostname).pem + + # Courier configuration + sed -i -r 's/TLS_CERTFILE=\/etc\/courier\/imapd.pem/TLS_CERTFILE=\/etc\/postfix\/ssl\/'$(hostname)'-combined.pem/g' /etc/courier/imapd-ssl + fi + + ;; + +esac echo "Fixing permissions" chown -R 5000:5000 /var/mail From fe553506457a1dfb0dd788226c3c6978525b2b5f Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Sat, 5 Dec 2015 17:32:33 +0100 Subject: [PATCH 088/155] Cleaned code after live testing and improved documentation --- .gitignore | 2 +- README.md | 24 ++++++++++++------------ SSL.md | 28 ++++++++++++++++++++++------ docker-compose.yml.dist | 5 ++++- start-mailserver.sh | 7 ------- 5 files changed, 39 insertions(+), 27 deletions(-) diff --git a/.gitignore b/.gitignore index 61e94224..319c0355 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,4 @@ docker-compose.yml postfix/ssl/* assert.sh* -letsencrypt/ \ No newline at end of file +letsencrypt/ diff --git a/README.md b/README.md index c24c2fbf..0c6cac73 100644 --- a/README.md +++ b/README.md @@ -70,19 +70,19 @@ Volumes allow to: # client configuration - # imap - username: - password: - server: - imap port: 143 or 993 with ssl (recommended) - imap path prefix: INBOX - auth method: md5 challenge-response + # imap + username: + password: + server: + imap port: 143 or 993 with ssl (recommended) + imap path prefix: INBOX + auth method: md5 challenge-response - # smtp - smtp port: 25 or 587 with ssl (recommended) - username: - password: - auth method: md5 challenge-response + # smtp + smtp port: 25 or 587 with ssl (recommended) + username: + password: + auth method: md5 challenge-response # todo diff --git a/SSL.md b/SSL.md index 0bb3e972..023d208d 100644 --- a/SSL.md +++ b/SSL.md @@ -7,14 +7,30 @@ There are multiple options to enable SSL: ## let's encrypt -To enable Let's Encrypt on your mail server, you have to add en environment variable `DMS_SSL` with value `letsencrypt`. -You also have to mount your `letsencrypt` folder to `/etc/letsencrypt`. - - - -TO BE FINISHED WHEN IT WILL BE TESTED +To enable Let's Encrypt on your mail server, you have to add en environment variable `DMS_SSL` with value `letsencrypt` (see `docker-compose.yml.dist`) +You also have to mount your `letsencrypt` folder to `/etc/letsencrypt` and it should look like that: + ├── etc + │   └── letsencrypt + │   ├── accounts + │   ├── archive + │   │   └── mail.domain.com + │   │   ├── cert1.pem + │   │   ├── chain1.pem + │   │   ├── fullchain1.pem + │   │   └── privkey1.pem + │   ├── csr + │   ├── keys + │   ├── live + │   │   └── mail.domain.com + │   │   ├── cert.pem -> ../../archive/mail.domain.com/cert1.pem + │   │   ├── chain.pem -> ../../archive/mail.domain.com/chain1.pem + │   │   ├── combined.pem + │   │   ├── fullchain.pem -> ../../archive/mail.domain.com/fullchain1.pem + │   │   └── privkey.pem -> ../../archive/mail.domain.com/privkey1.pem + │   └── renewal +You don't have anything else to do. ## self signed certificates diff --git a/docker-compose.yml.dist b/docker-compose.yml.dist index 6f3ba3b4..f5d24f88 100644 --- a/docker-compose.yml.dist +++ b/docker-compose.yml.dist @@ -2,7 +2,7 @@ mail: # image: tvial/docker-mailserver build: . hostname: mail - domainname: my-domain.com + domainname: domain.com ports: - "25:25" - "143:143" @@ -11,3 +11,6 @@ mail: volumes: - ./spamassassin:/tmp/spamassassin/ - ./postfix:/tmp/postfix/ + - ./letsencrypt/etc:/etc/letsencrypt + environment: + - DMS_SSL=letsencrypt diff --git a/start-mailserver.sh b/start-mailserver.sh index ca5a7ecd..72345629 100644 --- a/start-mailserver.sh +++ b/start-mailserver.sh @@ -59,13 +59,6 @@ case $DMS_SSL in "letsencrypt" ) # letsencrypt folders and files mounted in /etc/letsencrypt - # Adding certificates from Letsencrypt and IdenTrust - # curl https://letsencrypt.org/certs/isrgrootx1.pem -so /etc/ssl/certs/isrgrootx1.pem - # curl https://letsencrypt.org/certs/lets-encrypt-x1-cross-signed.pem -so /etc/ssl/certs/lets-encrypt-x1-cross-signed.pem - # curl https://letsencrypt.org/certs/lets-encrypt-x2-cross-signed.pem -so /etc/ssl/certs/lets-encrypt-x2-cross-signed.pem - # curl https://letsencrypt.org/certs/letsencryptauthorityx1.pem -so /etc/ssl/certs/letsencryptauthorityx1.pem - # curl https://letsencrypt.org/certs/letsencryptauthorityx2.pem -so /etc/ssl/certs/letsencryptauthorityx2.pem - # Postfix configuration sed -i -r 's/smtpd_tls_cert_file=\/etc\/ssl\/certs\/ssl-cert-snakeoil.pem/smtpd_tls_cert_file=\/etc\/letsencrypt\/live\/'$(hostname)'\/fullchain.pem/g' /etc/postfix/main.cf sed -i -r 's/smtpd_tls_key_file=\/etc\/ssl\/private\/ssl-cert-snakeoil.key/smtpd_tls_key_file=\/etc\/letsencrypt\/live\/'$(hostname)'\/privkey.pem/g' /etc/postfix/main.cf From 9a869919ecd3e6f80fea79a5138de62d968f8cd0 Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Sat, 5 Dec 2015 18:01:58 +0100 Subject: [PATCH 089/155] Simplified documentation. Ready to go. --- SSL.md | 69 ++++++++++++++++++++++++---------------------------------- 1 file changed, 28 insertions(+), 41 deletions(-) diff --git a/SSL.md b/SSL.md index 023d208d..13fa91df 100644 --- a/SSL.md +++ b/SSL.md @@ -2,61 +2,48 @@ There are multiple options to enable SSL: -* using [letsencrypt](https://letsencrypt.org/) +* using [letsencrypt](https://letsencrypt.org/) (recommended) * using self-signed certificates with the provided tool -## let's encrypt +After installation, you can test your setup with [checktls.com](https://www.checktls.com/TestReceiver). -To enable Let's Encrypt on your mail server, you have to add en environment variable `DMS_SSL` with value `letsencrypt` (see `docker-compose.yml.dist`) -You also have to mount your `letsencrypt` folder to `/etc/letsencrypt` and it should look like that: +## let's encrypt (recommended) - ├── etc - │   └── letsencrypt - │   ├── accounts - │   ├── archive - │   │   └── mail.domain.com - │   │   ├── cert1.pem - │   │   ├── chain1.pem - │   │   ├── fullchain1.pem - │   │   └── privkey1.pem - │   ├── csr - │   ├── keys - │   ├── live - │   │   └── mail.domain.com - │   │   ├── cert.pem -> ../../archive/mail.domain.com/cert1.pem - │   │   ├── chain.pem -> ../../archive/mail.domain.com/chain1.pem - │   │   ├── combined.pem - │   │   ├── fullchain.pem -> ../../archive/mail.domain.com/fullchain1.pem - │   │   └── privkey.pem -> ../../archive/mail.domain.com/privkey1.pem - │   └── renewal +To enable Let's Encrypt on your mail server, you have to: -You don't have anything else to do. +* get your certificate using [letsencrypt client](https://github.com/letsencrypt/letsencrypt) +* add an environment variable `DMS_SSL` with value `letsencrypt` (see `docker-compose.yml.dist`) +* mount your `letsencrypt` folder to `/etc/letsencrypt` + +You don't have anything else to do. Enjoy. ## self signed certificates You can easily generate a self-signed SSL certificate by using the following command: - docker run -ti --rm -v "$(pwd)"/postfix/ssl:/ssl -h mail.my-domain.com -t tvial/docker-mailserver generate-ssl-certificate + docker run -ti --rm -v "$(pwd)"/postfix/ssl:/ssl -h mail.my-domain.com -t tvial/docker-mailserver generate-ssl-certificate - # Press enter - # Enter a password when needed - # Fill information like Country, Organisation name - # Fill "my-domain.com" as FQDN for CA, and "mail.my-domain.com" for the certificate. - # They HAVE to be different, otherwise you'll get a `TXT_DB error number 2` - # Don't fill extras - # Enter same password when needed - # Sign the certificate? [y/n]:y - # 1 out of 1 certificate requests certified, commit? [y/n]y + # Press enter + # Enter a password when needed + # Fill information like Country, Organisation name + # Fill "my-domain.com" as FQDN for CA, and "mail.my-domain.com" for the certificate. + # They HAVE to be different, otherwise you'll get a `TXT_DB error number 2` + # Don't fill extras + # Enter same password when needed + # Sign the certificate? [y/n]:y + # 1 out of 1 certificate requests certified, commit? [y/n]y - # will generate: - # postfix/ssl/mail.my-domain.com-key.pem (used in postfix) - # postfix/ssl/mail.my-domain.com-req.pem (only used to generate other files) - # postfix/ssl/mail.my-domain.com-cert.pem (used in postfix) - # postfix/ssl/mail.my-domain.com-combined.pem (used in courier) - # postfix/ssl/demoCA/cacert.pem (certificate authority) + # will generate: + # postfix/ssl/mail.my-domain.com-key.pem (used in postfix) + # postfix/ssl/mail.my-domain.com-req.pem (only used to generate other files) + # postfix/ssl/mail.my-domain.com-cert.pem (used in postfix) + # postfix/ssl/mail.my-domain.com-combined.pem (used in courier) + # postfix/ssl/demoCA/cacert.pem (certificate authority) Note that the certificate will be generate for the container `fqdn`, that is passed as `-h` argument. Check the following page for more information regarding [postfix and SSL/TLS configuration](http://www.mad-hacking.net/documentation/linux/applications/mail/using-ssl-tls-postfix-courier.xml). -If a matching certificate (files listed above) is found in `postfix/ssl`, it will be automatically setup in postfix and courier-imap-ssl. You just have to place them in `postfix/ssl` folder. +To use the certificate: +* add an `DMS_SSL=self-signed` to your container environment variables +* if a matching certificate (files listed above) is found in `postfix/ssl`, it will be automatically setup in postfix and courier-imap-ssl. You just have to place them in `postfix/ssl` folder. From b7e9221ffa192e4f3260b9677b205f2e14616814 Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Sat, 5 Dec 2015 19:08:39 +0100 Subject: [PATCH 090/155] Fixed error reported by jderusse --- bin/generate-ssl-certificate | 2 +- start-mailserver.sh | 2 +- test/test.sh | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bin/generate-ssl-certificate b/bin/generate-ssl-certificate index 682b07d4..aee67906 100644 --- a/bin/generate-ssl-certificate +++ b/bin/generate-ssl-certificate @@ -10,5 +10,5 @@ openssl req -new -nodes -keyout /ssl/$FQDN-key.pem -out /ssl/$FQDN-req.pem -days # Sign the public key certificate with CA certificate openssl ca -out /ssl/$FQDN-cert.pem -infiles /ssl/$FQDN-req.pem # Combine certificates for courier -cat /ssl/$FQDN-key.pem /ssl/$FQDN-cert.pem >> /ssl/$FQDN-combined.pem +cat /ssl/$FQDN-key.pem /ssl/$FQDN-cert.pem > /ssl/$FQDN-combined.pem diff --git a/start-mailserver.sh b/start-mailserver.sh index 72345629..ce82eb33 100644 --- a/start-mailserver.sh +++ b/start-mailserver.sh @@ -64,7 +64,7 @@ case $DMS_SSL in sed -i -r 's/smtpd_tls_key_file=\/etc\/ssl\/private\/ssl-cert-snakeoil.key/smtpd_tls_key_file=\/etc\/letsencrypt\/live\/'$(hostname)'\/privkey.pem/g' /etc/postfix/main.cf # Courier configuration - cat /etc/letsencrypt/live/$(hostname)/privkey.pem /etc/letsencrypt/live/$(hostname)/cert.pem >> /etc/letsencrypt/live/$(hostname)/combined.pem + cat /etc/letsencrypt/live/$(hostname)/privkey.pem /etc/letsencrypt/live/$(hostname)/cert.pem > /etc/letsencrypt/live/$(hostname)/combined.pem sed -i -r 's/TLS_CERTFILE=\/etc\/courier\/imapd.pem/TLS_CERTFILE=\/etc\/letsencrypt\/live\/'$(hostname)'\/combined.pem/g' /etc/courier/imapd-ssl echo "SSL configured with letsencrypt certificates" diff --git a/test/test.sh b/test/test.sh index 8eeed27b..43bce4f1 100644 --- a/test/test.sh +++ b/test/test.sh @@ -38,7 +38,7 @@ assert_raises "docker exec mail grep -- '-> ' /var/lo # Testing that a SPAM is rejected assert_raises "docker exec mail grep 'Blocked SPAM' /var/log/mail.log | grep spam@external.tld" -# TODO: Testing that a Virus is rejected +# Testing that a Virus is rejected assert_raises "docker exec mail grep 'Blocked INFECTED' /var/log/mail.log | grep virus@external.tld" # Testing presence of freshclam CRON From 550d66936e018379028340d5832dacb317c5df4c Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Sun, 6 Dec 2015 20:53:22 +0100 Subject: [PATCH 091/155] Fixed #42 - No more weak ciphers. --- postfix/main.cf | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/postfix/main.cf b/postfix/main.cf index 87f23f8c..b4114b1f 100644 --- a/postfix/main.cf +++ b/postfix/main.cf @@ -29,6 +29,15 @@ smtpd_recipient_restrictions = permit_sasl_authenticated, permit_mynetworks, rej smtpd_client_restrictions = permit_mynetworks, permit_sasl_authenticated, reject_unauth_destination smtpd_sender_restrictions = permit_mynetworks smtp_tls_security_level = may +smtp_tls_loglevel = 1 +smtpd_tls_auth_only = yes +tls_ssl_options = NO_COMPRESSION +tls_high_cipherlist=EDH+CAMELLIA:EDH+aRSA:EECDH+aRSA+AESGCM:EECDH+aRSA+SHA384:EECDH+aRSA+SHA256:EECDH:+CAMELLIA256:+AES256:+CAMELLIA128:+AES128:+SSLv3:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP:!PSK:!DSS:!RC4:!SEED:!ECDSA:CAMELLIA256-SHA:AES256-SHA:CAMELLIA128-SHA:AES128-SHA +smtpd_tls_protocols=!SSLv2,!SSLv3 +smtp_tls_protocols=!SSLv2,!SSLv3 +smtpd_tls_mandatory_ciphers = high +smtpd_tls_mandatory_protocols = !SSLv2, !SSLv3 +smtpd_tls_exclude_ciphers = aNULL, LOW, EXP, MEDIUM, ADH, AECDH, MD5, DSS, ECDSA, CAMELLIA128, 3DES, CAMELLIA256, RSA+AES, eNULL # SASL smtpd_sasl_auth_enable = yes From 0e4058d70fea494c4dcdada4c8d38be1e6c3a541 Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Sun, 6 Dec 2015 21:12:32 +0100 Subject: [PATCH 092/155] Improved documentation and added link to SSL.md --- README.md | 39 ++++++++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 0c6cac73..8bc438f4 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ Why I created this image: [Simple mail server with Docker](http://tvi.al/simple- - aliases and fowards/redirects are managed in `./postfix/virtual` - antispam rules are managed in `./spamassassin/rules.cf` - files must be mounted to `/tmp` in your container (see `docker-compose.yml` template) -- ssl is strongly recommended, you can provide a self-signed certificate, see below +- ssl is strongly recommended, read [SSL.md](SSL.md) to use LetsEncrypt or Self-Signed Certificates - [includes integration tests](https://travis-ci.org/tomav/docker-mailserver) - [builds automated on docker hub](https://hub.docker.com/r/tvial/docker-mailserver/) @@ -40,23 +40,32 @@ Why I created this image: [Simple mail server with Docker](http://tvi.al/simple- ## run - docker run --name mail -v "$(pwd)/postfix":/tmp/postfix -v "$(pwd)/spamassassin":/tmp/spamassassin -p "25:25" -p "143:143" -p "587:587" -p "993:993" -h mail.my-domain.com -t tvial/docker-mailserver + docker run --name mail \ + -v "$(pwd)/postfix":/tmp/postfix \ + -v "$(pwd)/spamassassin":/tmp/spamassassin \ + -v "$(pwd)/letsencrypt/etc":/etc/letsencrypt \ + -p "25:25" -p "143:143" -p "587:587" -p "993:993" \ + -e DMS_SSL=letsencrypt \ + -h mail.domain.com \ + -t tvial/docker-mailserver ## docker-compose template (recommended) - mail: - # image: tvial/docker-mailserver - build: . - hostname: mail - domainname: my-domain.com - ports: - - "25:25" - - "143:143" - - "587:587" - - "993:993" - volumes: - - ./spamassassin:/tmp/spamassassin/ - - ./postfix:/tmp/postfix/ + mail: + image: tvial/docker-mailserver + hostname: mail + domainname: domain.com + ports: + - "25:25" + - "143:143" + - "587:587" + - "993:993" + volumes: + - ./spamassassin:/tmp/spamassassin/ + - ./postfix:/tmp/postfix/ + - ./letsencrypt/etc:/etc/letsencrypt + environment: + - DMS_SSL=letsencrypt Volumes allow to: From d5c6167dd300966d9ba1ef0110b5d91be71a210c Mon Sep 17 00:00:00 2001 From: Ian Andrews Date: Fri, 8 Jan 2016 11:52:06 -0500 Subject: [PATCH 093/155] Added SMTP and IMAP ports --- Dockerfile | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index df9160ec..6f94a855 100644 --- a/Dockerfile +++ b/Dockerfile @@ -40,5 +40,13 @@ RUN chmod +x /usr/local/bin/generate-ssl-certificate # Start-mailserver script ADD start-mailserver.sh /usr/local/bin/start-mailserver.sh RUN chmod +x /usr/local/bin/start-mailserver.sh -CMD /usr/local/bin/start-mailserver.sh +# SMTP ports +EXPOSE 25 +EXPOSE 587 + +# IMAP ports +EXPOSE 143 +EXPOSE 993 + +CMD /usr/local/bin/start-mailserver.sh From 18b63c36b62f7f2fbbd3a8f822b842004e18066b Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Tue, 12 Jan 2016 01:00:18 +0100 Subject: [PATCH 094/155] Added assert.sh in the project to avoid eternal dependency --- assert.sh | 186 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 186 insertions(+) create mode 100644 assert.sh diff --git a/assert.sh b/assert.sh new file mode 100644 index 00000000..ffd2b955 --- /dev/null +++ b/assert.sh @@ -0,0 +1,186 @@ +#!/bin/bash +# assert.sh 1.1 - bash unit testing framework +# Copyright (C) 2009-2015 Robert Lehmann +# +# http://github.com/lehmannro/assert.sh +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program. If not, see . + +export DISCOVERONLY=${DISCOVERONLY:-} +export DEBUG=${DEBUG:-} +export STOP=${STOP:-} +export INVARIANT=${INVARIANT:-} +export CONTINUE=${CONTINUE:-} + +args="$(getopt -n "$0" -l \ + verbose,help,stop,discover,invariant,continue vhxdic $*)" \ +|| exit -1 +for arg in $args; do + case "$arg" in + -h) + echo "$0 [-vxidc]" \ + "[--verbose] [--stop] [--invariant] [--discover] [--continue]" + echo "`sed 's/./ /g' <<< "$0"` [-h] [--help]" + exit 0;; + --help) + cat < [stdin] + (( tests_ran++ )) || : + [[ -z "$DISCOVERONLY" ]] || return + expected=$(echo -ne "${2:-}") + result="$(eval 2>/dev/null $1 <<< ${3:-})" || true + if [[ "$result" == "$expected" ]]; then + [[ -z "$DEBUG" ]] || echo -n . + return + fi + result="$(sed -e :a -e '$!N;s/\n/\\n/;ta' <<< "$result")" + [[ -z "$result" ]] && result="nothing" || result="\"$result\"" + [[ -z "$2" ]] && expected="nothing" || expected="\"$2\"" + _assert_fail "expected $expected${_indent}got $result" "$1" "$3" +} + +assert_raises() { + # assert_raises [stdin] + (( tests_ran++ )) || : + [[ -z "$DISCOVERONLY" ]] || return + status=0 + (eval $1 <<< ${3:-}) > /dev/null 2>&1 || status=$? + expected=${2:-0} + if [[ "$status" -eq "$expected" ]]; then + [[ -z "$DEBUG" ]] || echo -n . + return + fi + _assert_fail "program terminated with code $status instead of $expected" "$1" "$3" +} + +_assert_fail() { + # _assert_fail + [[ -n "$DEBUG" ]] && echo -n X + report="test #$tests_ran \"$2${3:+ <<< $3}\" failed:${_indent}$1" + if [[ -n "$STOP" ]]; then + [[ -n "$DEBUG" ]] && echo + echo "$report" + exit 1 + fi + tests_errors[$tests_failed]="$report" + (( tests_failed++ )) || : +} + +skip_if() { + # skip_if + (eval $@) > /dev/null 2>&1 && status=0 || status=$? + [[ "$status" -eq 0 ]] || return + skip +} + +skip() { + # skip (no arguments) + shopt -q extdebug && tests_extdebug=0 || tests_extdebug=1 + shopt -q -o errexit && tests_errexit=0 || tests_errexit=1 + # enable extdebug so returning 1 in a DEBUG trap handler skips next command + shopt -s extdebug + # disable errexit (set -e) so we can safely return 1 without causing exit + set +o errexit + tests_trapped=0 + trap _skip DEBUG +} +_skip() { + if [[ $tests_trapped -eq 0 ]]; then + # DEBUG trap for command we want to skip. Do not remove the handler + # yet because *after* the command we need to reset extdebug/errexit (in + # another DEBUG trap.) + tests_trapped=1 + [[ -z "$DEBUG" ]] || echo -n s + return 1 + else + trap - DEBUG + [[ $tests_extdebug -eq 0 ]] || shopt -u extdebug + [[ $tests_errexit -eq 1 ]] || set -o errexit + return 0 + fi +} + + +_assert_reset +: ${tests_suite_status:=0} # remember if any of the tests failed so far +_assert_cleanup() { + local status=$? + # modify exit code if it's not already non-zero + [[ $status -eq 0 && -z $CONTINUE ]] && exit $tests_suite_status +} +trap _assert_cleanup EXIT From f07a9ba85266f9c3011cafe45011a7d9f45f9b7e Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Tue, 12 Jan 2016 01:02:47 +0100 Subject: [PATCH 095/155] Fix for #44 and #47, also enabling plain and login mechs. --- .gitignore | 1 - Dockerfile | 2 +- Makefile | 2 +- postfix/main.cf | 2 +- postfix/master.cf | 2 +- postfix/sasl/smtpd.conf | 5 +++-- start-mailserver.sh | 1 + test/test.sh | 4 ++++ 8 files changed, 12 insertions(+), 7 deletions(-) diff --git a/.gitignore b/.gitignore index 319c0355..1ad63838 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,4 @@ .DS_Store docker-compose.yml postfix/ssl/* -assert.sh* letsencrypt/ diff --git a/Dockerfile b/Dockerfile index 6f94a855..5f53147d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -10,7 +10,7 @@ RUN apt-get autoclean && rm -rf /var/lib/apt/lists/* # Configures Saslauthd RUN rm -rf /var/run/saslauthd && ln -s /var/spool/postfix/var/run/saslauthd /var/run/saslauthd RUN adduser postfix sasl -RUN echo 'NAME="saslauthd"\nSTART=yes\nMECHANISMS="sasldb"\nTHREADS=0\nPWDIR=/var/spool/postfix/var/run/saslauthd\nPIDFILE="${PWDIR}/saslauthd.pid"\nOPTIONS="-n 0 -r -m /var/spool/postfix/var/run/saslauthd"' > /etc/default/saslauthd +RUN echo 'NAME="saslauthd"\nSTART=yes\nMECHANISMS="sasldb"\nTHREADS=0\nPWDIR=/var/spool/postfix/var/run/saslauthd\nPIDFILE="${PWDIR}/saslauthd.pid"\nOPTIONS="-n 0 -c -m /var/spool/postfix/var/run/saslauthd"' > /etc/default/saslauthd # Configures Courier RUN sed -i -r 's/daemons=5/daemons=1/g' /etc/courier/authdaemonrc diff --git a/Makefile b/Makefile index e049fd92..a019057e 100644 --- a/Makefile +++ b/Makefile @@ -12,7 +12,7 @@ run: cp test/virtual postfix/ # Run container docker run -d --name mail -v "`pwd`/postfix":/tmp/postfix -v "`pwd`/spamassassin":/tmp/spamassassin -v "`pwd`/test":/tmp/test -h mail.my-domain.com -t $(NAME):$(VERSION) - sleep 15 + sleep 25 prepare: # Reinitialize logs diff --git a/postfix/main.cf b/postfix/main.cf index b4114b1f..32ba810e 100644 --- a/postfix/main.cf +++ b/postfix/main.cf @@ -43,7 +43,7 @@ smtpd_tls_exclude_ciphers = aNULL, LOW, EXP, MEDIUM, ADH, AECDH, MD5, DSS, ECDSA smtpd_sasl_auth_enable = yes smtpd_sasl_path = smtpd smtpd_sasl_type = cyrus -smtpd_sasl_security_options = noanonymous, noplaintext +smtpd_sasl_security_options = noanonymous smtpd_sasl_local_domain = $myhostname cyrus_sasl_config_path = /etc/postfix/sasl broken_sasl_auth_clients = yes diff --git a/postfix/master.cf b/postfix/master.cf index c782b3da..8804f632 100644 --- a/postfix/master.cf +++ b/postfix/master.cf @@ -73,7 +73,7 @@ smtp-amavis unix - - - - 2 smtp -o disable_dns_lookups=yes -o max_use=20 -127.0.0.1:10025 inet n - - - - smtpd +127.0.0.1:10025 inet n - n - - smtpd -o content_filter= -o local_recipient_maps= -o relay_recipient_maps= diff --git a/postfix/sasl/smtpd.conf b/postfix/sasl/smtpd.conf index 75293ec9..f02eb91d 100644 --- a/postfix/sasl/smtpd.conf +++ b/postfix/sasl/smtpd.conf @@ -1,3 +1,4 @@ pwcheck_method: auxprop -mech_list: digest-md5 cram-md5 -log_level: 7 \ No newline at end of file +auxprop_plugin: sasldb +mech_list: PLAIN LOGIN CRAM-MD5 DIGEST-MD5 +log_level: 7 diff --git a/start-mailserver.sh b/start-mailserver.sh index ce82eb33..117ce5c8 100644 --- a/start-mailserver.sh +++ b/start-mailserver.sh @@ -102,6 +102,7 @@ esac echo "Fixing permissions" chown -R 5000:5000 /var/mail mkdir -p /var/log/clamav && chown -R clamav:root /var/log/clamav +chown postfix.sasl /etc/sasldb2 echo "Creating /etc/mailname" echo $(hostname -d) > /etc/mailname diff --git a/test/test.sh b/test/test.sh index 43bce4f1..13a648ee 100644 --- a/test/test.sh +++ b/test/test.sh @@ -14,6 +14,10 @@ assert_raises "docker exec mail ps aux --forest | grep '/usr/sbin/amavisd-new'" assert_raises "docker exec mail nc -w 1 0.0.0.0 143 | grep '* OK' | grep 'STARTTLS' | grep 'Courier-IMAP ready'" 0 assert_raises "docker exec mail /bin/sh -c 'nc -w 1 0.0.0.0 143 < /tmp/test/email-templates/test-imap.txt'" 0 +# Testing SASL +assert_raises "docker exec mail testsaslauthd -u user2 -r otherdomain.tld -p mypassword | grep 'OK \"Success.\"'" 0 +assert_raises "docker exec mail testsaslauthd -u user2 -r otherdomain.tld -p BADPASSWORD | grep 'NO \"authentication failed\"'" 0 + # Testing user creation assert "docker exec mail sasldblistusers2" "user1@localhost.localdomain: userPassword\nuser2@otherdomain.tld: userPassword" assert "docker exec mail ls -A /var/mail/localhost.localdomain/user1" "cur\nnew\ntmp" From a6fbef98355da91530768cc63fa24c907b528a94 Mon Sep 17 00:00:00 2001 From: Jonas Kalderstam Date: Tue, 8 Dec 2015 01:59:45 +0100 Subject: [PATCH 096/155] Do not create dir if it exists --- start-mailserver.sh | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/start-mailserver.sh b/start-mailserver.sh index ce82eb33..8b9c89b5 100644 --- a/start-mailserver.sh +++ b/start-mailserver.sh @@ -25,7 +25,12 @@ if [ -f /tmp/postfix/accounts.cf ]; then echo "${pass}" | userdbpw -md5 | userdb ${login} set systempw echo "${pass}" | saslpasswd2 -p -c -u ${domain} ${login} mkdir -p /var/mail/${domain} - maildirmake /var/mail/${domain}/${user} + if [ -d "/var/mail/${domain}/${user}" ]; then + # Directory already present + echo "Directory present" + else + maildirmake "/var/mail/${domain}/${user}" + fi echo ${domain} >> /tmp/vhost.tmp done < /tmp/postfix/accounts.cf makeuserdb From a14f4879aafcd6ac24cf62b551d6ca1b42f114fb Mon Sep 17 00:00:00 2001 From: Jonas Kalderstam Date: Sat, 16 Jan 2016 00:54:51 +0100 Subject: [PATCH 097/155] Remove redundant print --- start-mailserver.sh | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/start-mailserver.sh b/start-mailserver.sh index 8b9c89b5..22ecdc53 100644 --- a/start-mailserver.sh +++ b/start-mailserver.sh @@ -25,10 +25,7 @@ if [ -f /tmp/postfix/accounts.cf ]; then echo "${pass}" | userdbpw -md5 | userdb ${login} set systempw echo "${pass}" | saslpasswd2 -p -c -u ${domain} ${login} mkdir -p /var/mail/${domain} - if [ -d "/var/mail/${domain}/${user}" ]; then - # Directory already present - echo "Directory present" - else + if [ ! -d "/var/mail/${domain}/${user}" ]; then maildirmake "/var/mail/${domain}/${user}" fi echo ${domain} >> /tmp/vhost.tmp From 5176ac03b56e955bd680c67f81a510bc766698ae Mon Sep 17 00:00:00 2001 From: bilak Date: Wed, 20 Jan 2016 16:41:34 +0100 Subject: [PATCH 098/155] - added DKIM support --- .gitignore | 1 + Dockerfile | 13 ++++++++- Makefile | 8 +++++- README.md | 3 ++ postfix/TrustedHosts | 2 ++ postfix/default-opendkim | 12 ++++++++ postfix/main.cf | 5 ++++ postfix/opendkim.conf | 21 ++++++++++++++ start-mailserver.sh | 62 +++++++++++++++++++++++++++++++++++----- 9 files changed, 118 insertions(+), 9 deletions(-) create mode 100644 postfix/TrustedHosts create mode 100644 postfix/default-opendkim create mode 100644 postfix/opendkim.conf diff --git a/.gitignore b/.gitignore index 1ad63838..b7eb58c0 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ docker-compose.yml postfix/ssl/* letsencrypt/ +.idea diff --git a/Dockerfile b/Dockerfile index 5f53147d..31394985 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,7 +4,10 @@ MAINTAINER Thomas VIAL # Packages RUN apt-get update -q --fix-missing RUN apt-get -y upgrade -RUN DEBIAN_FRONTEND=noninteractive apt-get -y install vim postfix sasl2-bin courier-imap courier-imap-ssl courier-authdaemon supervisor gamin amavisd-new spamassassin clamav clamav-daemon libnet-dns-perl libmail-spf-perl pyzor razor arj bzip2 cabextract cpio file gzip nomarch p7zip pax unzip zip zoo rsyslog mailutils netcat +RUN DEBIAN_FRONTEND=noninteractive apt-get -y install vim postfix sasl2-bin courier-imap courier-imap-ssl \ + courier-authdaemon supervisor gamin amavisd-new spamassassin clamav clamav-daemon libnet-dns-perl libmail-spf-perl \ + pyzor razor arj bzip2 cabextract cpio file gzip nomarch p7zip pax unzip zip zoo rsyslog mailutils netcat \ + opendkim opendkim-tools RUN apt-get autoclean && rm -rf /var/lib/apt/lists/* # Configures Saslauthd @@ -30,6 +33,14 @@ RUN chmod 644 /etc/clamav/freshclam.conf RUN (crontab -l ; echo "0 1 * * * /usr/bin/freshclam --quiet") | sort - | uniq - | crontab - RUN freshclam +# Configure DKIM (opendkim) +RUN mkdir -p /etc/opendkim/keys +ADD postfix/TrustedHosts /etc/opendkim/TrustedHosts +# DKIM config files +ADD postfix/opendkim.conf /etc/opendkim.conf +ADD postfix/default-opendkim /etc/default/opendkim + + # Configures Postfix ADD postfix/main.cf /etc/postfix/main.cf ADD postfix/master.cf /etc/postfix/master.cf diff --git a/Makefile b/Makefile index a019057e..0d420a4e 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,13 @@ run: cp test/accounts.cf postfix/ cp test/virtual postfix/ # Run container - docker run -d --name mail -v "`pwd`/postfix":/tmp/postfix -v "`pwd`/spamassassin":/tmp/spamassassin -v "`pwd`/test":/tmp/test -h mail.my-domain.com -t $(NAME):$(VERSION) + docker run -d --name mail \ + -v "`pwd`/postfix":/tmp/postfix \ + -v "`pwd`/spamassassin":/tmp/spamassassin \ + -v "`pwd`/test":/tmp/test \ + -h mail.my-domain.com \ + -e domainname=my-domain.com \ + -t $(NAME):$(VERSION) sleep 25 prepare: diff --git a/README.md b/README.md index 8bc438f4..69649dae 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,7 @@ Includes: - amavis - spamassasin - clamav with automatic updates +- opendkim Why I created this image: [Simple mail server with Docker](http://tvi.al/simple-mail-server-with-docker/) @@ -29,6 +30,7 @@ Why I created this image: [Simple mail server with Docker](http://tvi.al/simple- - ssl is strongly recommended, read [SSL.md](SSL.md) to use LetsEncrypt or Self-Signed Certificates - [includes integration tests](https://travis-ci.org/tomav/docker-mailserver) - [builds automated on docker hub](https://hub.docker.com/r/tvial/docker-mailserver/) +- dkim public key will be echoed to log. If you have your previous configuration, you cant mount volume with it `-v "$(pwd)/opendkim":/etc/opendkim"` ## installation @@ -46,6 +48,7 @@ Why I created this image: [Simple mail server with Docker](http://tvi.al/simple- -v "$(pwd)/letsencrypt/etc":/etc/letsencrypt \ -p "25:25" -p "143:143" -p "587:587" -p "993:993" \ -e DMS_SSL=letsencrypt \ + -e domainname=domain.com \ -h mail.domain.com \ -t tvial/docker-mailserver diff --git a/postfix/TrustedHosts b/postfix/TrustedHosts new file mode 100644 index 00000000..0587f890 --- /dev/null +++ b/postfix/TrustedHosts @@ -0,0 +1,2 @@ +127.0.0.1 +localhost \ No newline at end of file diff --git a/postfix/default-opendkim b/postfix/default-opendkim new file mode 100644 index 00000000..20ead7e4 --- /dev/null +++ b/postfix/default-opendkim @@ -0,0 +1,12 @@ +# Command-line options specified here will override the contents of +# /etc/opendkim.conf. See opendkim(8) for a complete list of options. +#DAEMON_OPTS="" +# +# Uncomment to specify an alternate socket +# Note that setting this will override any Socket value in opendkim.conf +#SOCKET="local:/var/run/opendkim/opendkim.sock" # default +#SOCKET="inet:54321" # listen on all interfaces on port 54321 +#SOCKET="inet:12345@localhost" # listen on loopback on port 12345 +#SOCKET="inet:12345@192.0.2.1" # listen on 192.0.2.1 on port 12345 + +SOCKET="inet:12301@localhost" \ No newline at end of file diff --git a/postfix/main.cf b/postfix/main.cf index 32ba810e..8c3ce2fd 100644 --- a/postfix/main.cf +++ b/postfix/main.cf @@ -59,3 +59,8 @@ virtual_gid_maps = static:5000 # Additional option for filtering content_filter = smtp-amavis:[127.0.0.1]:10024 +# Milters used by DKIM +milter_protocol = 2 +milter_default_action = accept +smtpd_milters = inet:localhost:12301 +non_smtpd_milters = inet:localhost:12301 diff --git a/postfix/opendkim.conf b/postfix/opendkim.conf new file mode 100644 index 00000000..05c9d340 --- /dev/null +++ b/postfix/opendkim.conf @@ -0,0 +1,21 @@ +AutoRestart Yes +AutoRestartRate 10/1h +UMask 002 +Syslog yes +SyslogSuccess Yes +LogWhy Yes + +Canonicalization relaxed/simple + +ExternalIgnoreList refile:/etc/opendkim/TrustedHosts +InternalHosts refile:/etc/opendkim/TrustedHosts +KeyTable refile:/etc/opendkim/KeyTable +SigningTable refile:/etc/opendkim/SigningTable + +Mode sv +PidFile /var/run/opendkim/opendkim.pid +SignatureAlgorithm rsa-sha256 + +UserID opendkim:opendkim + +Socket inet:12301@localhost \ No newline at end of file diff --git a/start-mailserver.sh b/start-mailserver.sh index 8edb783b..042bb764 100644 --- a/start-mailserver.sh +++ b/start-mailserver.sh @@ -1,10 +1,55 @@ -#!/bin/sh +#!/bin/bash die () { echo >&2 "$@" exit 1 } +# DKIM Setup +mkdir -p /etc/opendkim/keys/$domainname +if [ ! -f "/etc/opendkim/keys/$domainname/mail.private" ]; then + echo "Creating DKIM private key /etc/opendkim/keys/$domainname/mail.private" + pushd /etc/opendkim/keys/$domainname + opendkim-genkey --subdomains --domain=$domainname --selector=mail + popd + echo "" + echo "DKIM PUBLIC KEY ################################################################" + cat /etc/opendkim/keys/$domainname/mail.txt + echo "################################################################################" +fi +# Write to KeyTable if necessary +if [ ! -f "/etc/opendkim/KeyTable" ]; then + echo "Creating DKIM KeyTable" + echo "mail._domainkey.$domainname $domainname:mail:/etc/opendkim/keys/$domainname/mail.private" > /etc/opendkim/KeyTable +fi +# Write to SigningTable if necessary +if [ ! -f "/etc/opendkim/SigningTable" ]; then + echo "Creating DKIM SigningTable" + echo "*@$domainname mail._domainkey.$domainname" > /etc/opendkim/SigningTable +fi +echo "Changing permissions on /etc/opendkim" +# chown entire directory +chown -R opendkim:opendkim /etc/opendkim/ +# And make sure permissions are right +chmod -R 0700 /etc/opendkim/keys/ + +# Opendkim: +echo "" +echo "opendkim.conf" +cat /etc/opendkim.conf +echo "" +echo "TrustedHosts" +cat /etc/opendkim/TrustedHosts +echo "" +echo "SigningTable" +cat /etc/opendkim/SigningTable +echo "" +echo "KeyTable" +cat /etc/opendkim/KeyTable +echo "" + + + if [ -f /tmp/postfix/accounts.cf ]; then echo "Regenerating postfix 'vmailbox' and 'virtual' for given users" echo "# WARNING: this file is auto-generated. Modify accounts.cf in postfix directory on host" > /etc/postfix/vmailbox @@ -66,7 +111,7 @@ case $DMS_SSL in sed -i -r 's/smtpd_tls_key_file=\/etc\/ssl\/private\/ssl-cert-snakeoil.key/smtpd_tls_key_file=\/etc\/letsencrypt\/live\/'$(hostname)'\/privkey.pem/g' /etc/postfix/main.cf # Courier configuration - cat /etc/letsencrypt/live/$(hostname)/privkey.pem /etc/letsencrypt/live/$(hostname)/cert.pem > /etc/letsencrypt/live/$(hostname)/combined.pem + cat "/etc/letsencrypt/live/$(hostname)/privkey.pem" "/etc/letsencrypt/live/$(hostname)/cert.pem" > "/etc/letsencrypt/live/$(hostname)/combined.pem" sed -i -r 's/TLS_CERTFILE=\/etc\/courier\/imapd.pem/TLS_CERTFILE=\/etc\/letsencrypt\/live\/'$(hostname)'\/combined.pem/g' /etc/courier/imapd-ssl echo "SSL configured with letsencrypt certificates" @@ -75,15 +120,15 @@ case $DMS_SSL in "self-signed" ) # Adding self-signed SSL certificate if provided in 'postfix/ssl' folder - if [ -e "/tmp/postfix/ssl/$(hostname)-cert.pem" ] \ + if [ -e "/tmp/postfix/ssl/$(hostname)-cert.pem" ] \ && [ -e "/tmp/postfix/ssl/$(hostname)-key.pem" ] \ && [ -e "/tmp/postfix/ssl/$(hostname)-combined.pem" ] \ && [ -e "/tmp/postfix/ssl/demoCA/cacert.pem" ]; then echo "Adding $(hostname) SSL certificate" mkdir -p /etc/postfix/ssl - cp /tmp/postfix/ssl/$(hostname)-cert.pem /etc/postfix/ssl - cp /tmp/postfix/ssl/$(hostname)-key.pem /etc/postfix/ssl - cp /tmp/postfix/ssl/$(hostname)-combined.pem /etc/postfix/ssl + cp "/tmp/postfix/ssl/$(hostname)-cert.pem" /etc/postfix/ssl + cp "/tmp/postfix/ssl/$(hostname)-key.pem" /etc/postfix/ssl + cp "/tmp/postfix/ssl/$(hostname)-combined.pem" /etc/postfix/ssl cp /tmp/postfix/ssl/demoCA/cacert.pem /etc/postfix/ssl # Postfix configuration @@ -91,10 +136,12 @@ case $DMS_SSL in sed -i -r 's/smtpd_tls_key_file=\/etc\/ssl\/private\/ssl-cert-snakeoil.key/smtpd_tls_key_file=\/etc\/postfix\/ssl\/'$(hostname)'-key.pem/g' /etc/postfix/main.cf sed -i -r 's/#smtpd_tls_CAfile=/smtpd_tls_CAfile=\/etc\/postfix\/ssl\/cacert.pem/g' /etc/postfix/main.cf sed -i -r 's/#smtp_tls_CAfile=/smtp_tls_CAfile=\/etc\/postfix\/ssl\/cacert.pem/g' /etc/postfix/main.cf - ln -s /etc/postfix/ssl/cacert.pem /etc/ssl/certs/cacert-$(hostname).pem + ln -s /etc/postfix/ssl/cacert.pem "/etc/ssl/certs/cacert-$(hostname).pem" # Courier configuration sed -i -r 's/TLS_CERTFILE=\/etc\/courier\/imapd.pem/TLS_CERTFILE=\/etc\/postfix\/ssl\/'$(hostname)'-combined.pem/g' /etc/courier/imapd-ssl + + echo "SSL configured with self-signed/custom certificates" fi ;; @@ -126,6 +173,7 @@ cron /etc/init.d/spamassassin start /etc/init.d/clamav-daemon start /etc/init.d/amavis start +/etc/init.d/opendkim start /etc/init.d/postfix start echo "Listing SASL users" From 77f4a61412668084a82a5d00902f1a999062a507 Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Wed, 20 Jan 2016 17:46:43 +0100 Subject: [PATCH 099/155] Added information about "from" and "to" separator which MUST be a space --- postfix/virtual | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/postfix/virtual b/postfix/virtual index 03991098..7d6adf3b 100644 --- a/postfix/virtual +++ b/postfix/virtual @@ -1,7 +1,7 @@ # -# ALIAS => from alias@domain.tld (alias) to user@domain.tld (real account) +# ALIAS => from alias@domain.tld (alias) to user@domain.tld (real account), space separated # alias@domain.tld user@domain.tld # -# FORWARD => from redirect@domain.tld to a list of internal/external email addresses +# FORWARD => from redirect@domain.tld to a list of internal/external email addresses, space separated # redirect@domain.tld otheruser@domain.tld otheruser@otherdomain.tld # \ No newline at end of file From 8518a3c52affa760a2df8f3d135563b741deb519 Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Wed, 20 Jan 2016 17:50:39 +0100 Subject: [PATCH 100/155] Added missing new line --- postfix/virtual | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/postfix/virtual b/postfix/virtual index 7d6adf3b..ca220715 100644 --- a/postfix/virtual +++ b/postfix/virtual @@ -4,4 +4,4 @@ # # FORWARD => from redirect@domain.tld to a list of internal/external email addresses, space separated # redirect@domain.tld otheruser@domain.tld otheruser@otherdomain.tld -# \ No newline at end of file +# From 796699f0f18fcb778a449d522eb1e4e99acc5970 Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Fri, 22 Jan 2016 15:02:25 +0100 Subject: [PATCH 101/155] Fixes #39 with a basic backup script --- README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/README.md b/README.md index 8bc438f4..7c294b5c 100644 --- a/README.md +++ b/README.md @@ -93,6 +93,16 @@ Volumes allow to: password: auth method: md5 challenge-response +# backups + +Assuming that you use `docker-compose` and a data volume container named `maildata`, you can backup your user mails like this: + + docker run --rm \ + --volumes-from maildata_1 \ + -v "$(pwd)":/backups \ + -ti tvial/docker-mailserver \ + tar cvzf /backups/docker-mailserver-`date +%y%m%d-%H%M%S`.tgz /var/mail + # todo Things to do or to improve are stored on [Github](https://github.com/tomav/docker-mailserver/issues), some open by myself. From e97ce868ebdc49ee7726052a2c65212daf7fcce6 Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Fri, 22 Jan 2016 17:51:58 +0100 Subject: [PATCH 102/155] Added tests for SMTP auth --- postfix/main.cf | 4 ++- .../test-imap.txt => auth/imap-auth.txt} | 0 test/auth/smtp-auth-cram-md5.txt | 26 +++++++++++++++++++ test/auth/smtp-auth-login.txt | 4 +++ test/auth/smtp-auth-plain.txt | 3 +++ test/test.sh | 5 ++-- 6 files changed, 39 insertions(+), 3 deletions(-) rename test/{email-templates/test-imap.txt => auth/imap-auth.txt} (100%) create mode 100644 test/auth/smtp-auth-cram-md5.txt create mode 100644 test/auth/smtp-auth-login.txt create mode 100644 test/auth/smtp-auth-plain.txt diff --git a/postfix/main.cf b/postfix/main.cf index 32ba810e..68eca62a 100644 --- a/postfix/main.cf +++ b/postfix/main.cf @@ -30,7 +30,6 @@ smtpd_client_restrictions = permit_mynetworks, permit_sasl_authenticated, reject smtpd_sender_restrictions = permit_mynetworks smtp_tls_security_level = may smtp_tls_loglevel = 1 -smtpd_tls_auth_only = yes tls_ssl_options = NO_COMPRESSION tls_high_cipherlist=EDH+CAMELLIA:EDH+aRSA:EECDH+aRSA+AESGCM:EECDH+aRSA+SHA384:EECDH+aRSA+SHA256:EECDH:+CAMELLIA256:+AES256:+CAMELLIA128:+AES128:+SSLv3:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP:!PSK:!DSS:!RC4:!SEED:!ECDSA:CAMELLIA256-SHA:AES256-SHA:CAMELLIA128-SHA:AES128-SHA smtpd_tls_protocols=!SSLv2,!SSLv3 @@ -40,6 +39,9 @@ smtpd_tls_mandatory_protocols = !SSLv2, !SSLv3 smtpd_tls_exclude_ciphers = aNULL, LOW, EXP, MEDIUM, ADH, AECDH, MD5, DSS, ECDSA, CAMELLIA128, 3DES, CAMELLIA256, RSA+AES, eNULL # SASL +smtp_sasl_auth_enable = yes +smtp_sasl_type = cyrus +smtp_sasl_security_options = noanonymous smtpd_sasl_auth_enable = yes smtpd_sasl_path = smtpd smtpd_sasl_type = cyrus diff --git a/test/email-templates/test-imap.txt b/test/auth/imap-auth.txt similarity index 100% rename from test/email-templates/test-imap.txt rename to test/auth/imap-auth.txt diff --git a/test/auth/smtp-auth-cram-md5.txt b/test/auth/smtp-auth-cram-md5.txt new file mode 100644 index 00000000..5707eecd --- /dev/null +++ b/test/auth/smtp-auth-cram-md5.txt @@ -0,0 +1,26 @@ +# This is the output of a manual test. +# CRAM-MD5 is not (yet) testable with telnet. +# +# # telnet localhost 25 +# Trying ::1... +# Connected to localhost. +# Escape character is '^]'. +# 220 mail.my-domain.com ESMTP Postfix (Ubuntu) +# ehlo test +# 250-mail.my-domain.com +# 250-PIPELINING +# 250-SIZE 10240000 +# 250-VRFY +# 250-ETRN +# 250-STARTTLS +# 250-AUTH PLAIN LOGIN CRAM-MD5 DIGEST-MD5 +# 250-AUTH=PLAIN LOGIN CRAM-MD5 DIGEST-MD5 +# 250-ENHANCEDSTATUSCODES +# 250-8BITMIME +# 250 DSN +# AUTH CRAM-MD5 +# 334 PDIxMDMyODkzMTMuMTA2Mzg2MjhAbWFpbC5teS1kb21haW4uY29tPg== +# dXNlcjFAbG9jYWxob3N0LmxvY2FsZG9tYWluIGJlYjUxNzg4OGE5ZWI0OGM1NjQ2MTYwZGY3NTY1ZWNh +# 235 2.7.0 Authentication successful +# QUIT +# 221 2.0.0 Bye \ No newline at end of file diff --git a/test/auth/smtp-auth-login.txt b/test/auth/smtp-auth-login.txt new file mode 100644 index 00000000..50ff99f3 --- /dev/null +++ b/test/auth/smtp-auth-login.txt @@ -0,0 +1,4 @@ +EHLO mail +AUTH LOGIN dXNlcjFAbG9jYWxob3N0LmxvY2FsZG9tYWlu +bXlwYXNzd29yZA== +QUIT diff --git a/test/auth/smtp-auth-plain.txt b/test/auth/smtp-auth-plain.txt new file mode 100644 index 00000000..2e60fdc3 --- /dev/null +++ b/test/auth/smtp-auth-plain.txt @@ -0,0 +1,3 @@ +EHLO mail +AUTH PLAIN dXNlcjFAbG9jYWxob3N0LmxvY2FsZG9tYWluAHVzZXIxQGxvY2FsaG9zdC5sb2NhbGRvbWFpbgBteXBhc3N3b3Jk +QUIT diff --git a/test/test.sh b/test/test.sh index 13a648ee..555338b2 100644 --- a/test/test.sh +++ b/test/test.sh @@ -1,7 +1,6 @@ #!/bin/bash # Set up test framework -wget -q https://raw.github.com/lehmannro/assert.sh/master/assert.sh -O assert.sh source assert.sh # Testing that services are running @@ -12,11 +11,13 @@ assert_raises "docker exec mail ps aux --forest | grep '/usr/sbin/amavisd-new'" # Testing IMAP server assert_raises "docker exec mail nc -w 1 0.0.0.0 143 | grep '* OK' | grep 'STARTTLS' | grep 'Courier-IMAP ready'" 0 -assert_raises "docker exec mail /bin/sh -c 'nc -w 1 0.0.0.0 143 < /tmp/test/email-templates/test-imap.txt'" 0 +assert_raises "docker exec mail /bin/sh -c 'nc -w 1 0.0.0.0 143 < /tmp/test/auth/imap-auth.txt'" 0 # Testing SASL assert_raises "docker exec mail testsaslauthd -u user2 -r otherdomain.tld -p mypassword | grep 'OK \"Success.\"'" 0 assert_raises "docker exec mail testsaslauthd -u user2 -r otherdomain.tld -p BADPASSWORD | grep 'NO \"authentication failed\"'" 0 +assert_raises "docker exec mail /bin/sh -c 'nc -w 1 0.0.0.0 25 < /tmp/test/auth/smtp-auth-plain.txt' | grep 'Authentication successful'" +assert_raises "docker exec mail /bin/sh -c 'nc -w 1 0.0.0.0 25 < /tmp/test/auth/smtp-auth-login.txt' | grep 'Authentication successful'" # Testing user creation assert "docker exec mail sasldblistusers2" "user1@localhost.localdomain: userPassword\nuser2@otherdomain.tld: userPassword" From 8eeda6f2a7f5822ad87918bacf09803371929d10 Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Fri, 22 Jan 2016 18:47:43 +0100 Subject: [PATCH 103/155] Fixed tests --- Makefile | 4 ++++ postfix/main.cf | 3 --- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index a019057e..3e97440a 100644 --- a/Makefile +++ b/Makefile @@ -32,3 +32,7 @@ fixtures: tests: # Start tests /bin/bash ./test/test.sh + +clean: + # Get default files back + git checkout postfix/accounts.cf postfix/virtual diff --git a/postfix/main.cf b/postfix/main.cf index 68eca62a..38b4bedc 100644 --- a/postfix/main.cf +++ b/postfix/main.cf @@ -39,9 +39,6 @@ smtpd_tls_mandatory_protocols = !SSLv2, !SSLv3 smtpd_tls_exclude_ciphers = aNULL, LOW, EXP, MEDIUM, ADH, AECDH, MD5, DSS, ECDSA, CAMELLIA128, 3DES, CAMELLIA256, RSA+AES, eNULL # SASL -smtp_sasl_auth_enable = yes -smtp_sasl_type = cyrus -smtp_sasl_security_options = noanonymous smtpd_sasl_auth_enable = yes smtpd_sasl_path = smtpd smtpd_sasl_type = cyrus From 426f87d916c0c95747d603270984d40fc468a1f4 Mon Sep 17 00:00:00 2001 From: bilak Date: Sat, 23 Jan 2016 18:38:21 +0100 Subject: [PATCH 104/155] - reworked dkim (configuring for all domains based on postfix/vhost) --- Makefile | 1 - README.md | 3 +- start-mailserver.sh | 87 ++++++++++++++++++++++----------------------- 3 files changed, 43 insertions(+), 48 deletions(-) diff --git a/Makefile b/Makefile index 0d420a4e..521d87e9 100644 --- a/Makefile +++ b/Makefile @@ -16,7 +16,6 @@ run: -v "`pwd`/spamassassin":/tmp/spamassassin \ -v "`pwd`/test":/tmp/test \ -h mail.my-domain.com \ - -e domainname=my-domain.com \ -t $(NAME):$(VERSION) sleep 25 diff --git a/README.md b/README.md index 69649dae..9e969aa0 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ Why I created this image: [Simple mail server with Docker](http://tvi.al/simple- - ssl is strongly recommended, read [SSL.md](SSL.md) to use LetsEncrypt or Self-Signed Certificates - [includes integration tests](https://travis-ci.org/tomav/docker-mailserver) - [builds automated on docker hub](https://hub.docker.com/r/tvial/docker-mailserver/) -- dkim public key will be echoed to log. If you have your previous configuration, you cant mount volume with it `-v "$(pwd)/opendkim":/etc/opendkim"` +- dkim public key will be echoed to log. If you have your previous configuration, you can mount volume with it `-v "$(pwd)/opendkim":/etc/opendkim"` ## installation @@ -48,7 +48,6 @@ Why I created this image: [Simple mail server with Docker](http://tvi.al/simple- -v "$(pwd)/letsencrypt/etc":/etc/letsencrypt \ -p "25:25" -p "143:143" -p "587:587" -p "993:993" \ -e DMS_SSL=letsencrypt \ - -e domainname=domain.com \ -h mail.domain.com \ -t tvial/docker-mailserver diff --git a/start-mailserver.sh b/start-mailserver.sh index 042bb764..e470141b 100644 --- a/start-mailserver.sh +++ b/start-mailserver.sh @@ -5,51 +5,6 @@ die () { exit 1 } -# DKIM Setup -mkdir -p /etc/opendkim/keys/$domainname -if [ ! -f "/etc/opendkim/keys/$domainname/mail.private" ]; then - echo "Creating DKIM private key /etc/opendkim/keys/$domainname/mail.private" - pushd /etc/opendkim/keys/$domainname - opendkim-genkey --subdomains --domain=$domainname --selector=mail - popd - echo "" - echo "DKIM PUBLIC KEY ################################################################" - cat /etc/opendkim/keys/$domainname/mail.txt - echo "################################################################################" -fi -# Write to KeyTable if necessary -if [ ! -f "/etc/opendkim/KeyTable" ]; then - echo "Creating DKIM KeyTable" - echo "mail._domainkey.$domainname $domainname:mail:/etc/opendkim/keys/$domainname/mail.private" > /etc/opendkim/KeyTable -fi -# Write to SigningTable if necessary -if [ ! -f "/etc/opendkim/SigningTable" ]; then - echo "Creating DKIM SigningTable" - echo "*@$domainname mail._domainkey.$domainname" > /etc/opendkim/SigningTable -fi -echo "Changing permissions on /etc/opendkim" -# chown entire directory -chown -R opendkim:opendkim /etc/opendkim/ -# And make sure permissions are right -chmod -R 0700 /etc/opendkim/keys/ - -# Opendkim: -echo "" -echo "opendkim.conf" -cat /etc/opendkim.conf -echo "" -echo "TrustedHosts" -cat /etc/opendkim/TrustedHosts -echo "" -echo "SigningTable" -cat /etc/opendkim/SigningTable -echo "" -echo "KeyTable" -cat /etc/opendkim/KeyTable -echo "" - - - if [ -f /tmp/postfix/accounts.cf ]; then echo "Regenerating postfix 'vmailbox' and 'virtual' for given users" echo "# WARNING: this file is auto-generated. Modify accounts.cf in postfix directory on host" > /etc/postfix/vmailbox @@ -101,6 +56,48 @@ echo "Postfix configurations" touch /etc/postfix/vmailbox && postmap /etc/postfix/vmailbox touch /etc/postfix/virtual && postmap /etc/postfix/virtual +# DKIM +grep -vE '^(\s*$|#)' /etc/postfix/vhost | while read domainname; do + mkdir -p /etc/opendkim/keys/$domainname + if [ ! -f "/etc/opendkim/keys/$domainname/mail.private" ]; then + echo "Creating DKIM private key /etc/opendkim/keys/$domainname/mail.private" + pushd /etc/opendkim/keys/$domainname + opendkim-genkey --subdomains --domain=$domainname --selector=mail + popd + echo "" + echo "DKIM PUBLIC KEY ################################################################" + cat /etc/opendkim/keys/$domainname/mail.txt + echo "################################################################################" + fi + # Write to KeyTable if necessary + keytableentry="mail._domainkey.$domainname $domainname:mail:/etc/opendkim/keys/$domainname/mail.private" + if [ ! -f "/etc/opendkim/KeyTable" ]; then + echo "Creating DKIM KeyTable" + echo "mail._domainkey.$domainname $domainname:mail:/etc/opendkim/keys/$domainname/mail.private" > /etc/opendkim/KeyTable + else + if ! grep -q "$keytableentry" "/etc/opendkim/KeyTable" ; then + echo $keytableentry >> /etc/opendkim/KeyTable + fi + fi + # Write to SigningTable if necessary + signingtableentry="*@$domainname mail._domainkey.$domainname" + if [ ! -f "/etc/opendkim/SigningTable" ]; then + echo "Creating DKIM SigningTable" + echo "*@$domainname mail._domainkey.$domainname" > /etc/opendkim/SigningTable + else + if ! grep -q "$signingtableentry" "/etc/opendkim/SigningTable" ; then + echo $signingtableentry >> /etc/opendkim/SigningTable + fi + fi +done + +echo "Changing permissions on /etc/opendkim" +# chown entire directory +chown -R opendkim:opendkim /etc/opendkim/ +# And make sure permissions are right +chmod -R 0700 /etc/opendkim/keys/ + + # SSL Configuration case $DMS_SSL in "letsencrypt" ) From 9a80374bc3f4fb6b4fefb64f83d4228f27239e97 Mon Sep 17 00:00:00 2001 From: Christian Musa Date: Sat, 23 Jan 2016 19:51:09 -0300 Subject: [PATCH 105/155] Add pop3 support --- Dockerfile | 6 +++++- Makefile | 4 +++- start-mailserver.sh | 17 +++++++++++++++++ test/auth/pop3-auth.txt | 4 ++++ test/test.sh | 14 +++++++++++++- 5 files changed, 42 insertions(+), 3 deletions(-) create mode 100644 test/auth/pop3-auth.txt diff --git a/Dockerfile b/Dockerfile index 5f53147d..fad746f6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,7 +4,7 @@ MAINTAINER Thomas VIAL # Packages RUN apt-get update -q --fix-missing RUN apt-get -y upgrade -RUN DEBIAN_FRONTEND=noninteractive apt-get -y install vim postfix sasl2-bin courier-imap courier-imap-ssl courier-authdaemon supervisor gamin amavisd-new spamassassin clamav clamav-daemon libnet-dns-perl libmail-spf-perl pyzor razor arj bzip2 cabextract cpio file gzip nomarch p7zip pax unzip zip zoo rsyslog mailutils netcat +RUN DEBIAN_FRONTEND=noninteractive apt-get -y install vim postfix sasl2-bin courier-imap courier-imap-ssl courier-pop courier-pop-ssl courier-authdaemon supervisor gamin amavisd-new spamassassin clamav clamav-daemon libnet-dns-perl libmail-spf-perl pyzor razor arj bzip2 cabextract cpio file gzip nomarch p7zip pax unzip zip zoo rsyslog mailutils netcat RUN apt-get autoclean && rm -rf /var/lib/apt/lists/* # Configures Saslauthd @@ -49,4 +49,8 @@ EXPOSE 587 EXPOSE 143 EXPOSE 993 +# POP3 ports +EXPOSE 110 +EXPOSE 995 + CMD /usr/local/bin/start-mailserver.sh diff --git a/Makefile b/Makefile index 3e97440a..93cb6314 100644 --- a/Makefile +++ b/Makefile @@ -10,13 +10,15 @@ run: # Copy test files cp test/accounts.cf postfix/ cp test/virtual postfix/ - # Run container + # Run containers docker run -d --name mail -v "`pwd`/postfix":/tmp/postfix -v "`pwd`/spamassassin":/tmp/spamassassin -v "`pwd`/test":/tmp/test -h mail.my-domain.com -t $(NAME):$(VERSION) + docker run -d --name mail_pop3 -v "`pwd`/postfix":/tmp/postfix -v "`pwd`/spamassassin":/tmp/spamassassin -v "`pwd`/test":/tmp/test -e ENABLE_POP3=1 -h mail.my-domain.com -t $(NAME):$(VERSION) sleep 25 prepare: # Reinitialize logs docker exec mail /bin/sh -c 'echo "" > /var/log/mail.log' + docker exec mail_pop3 /bin/sh -c 'echo "" > /var/log/mail.log' fixtures: # Sending test mails diff --git a/start-mailserver.sh b/start-mailserver.sh index 8edb783b..2a9c7371 100644 --- a/start-mailserver.sh +++ b/start-mailserver.sh @@ -69,6 +69,12 @@ case $DMS_SSL in cat /etc/letsencrypt/live/$(hostname)/privkey.pem /etc/letsencrypt/live/$(hostname)/cert.pem > /etc/letsencrypt/live/$(hostname)/combined.pem sed -i -r 's/TLS_CERTFILE=\/etc\/courier\/imapd.pem/TLS_CERTFILE=\/etc\/letsencrypt\/live\/'$(hostname)'\/combined.pem/g' /etc/courier/imapd-ssl + # POP3 courier configuration + sed -i -r 's/POP3_TLS_REQUIRED=0/POP3_TLS_REQUIRED=1/g' /etc/courier/pop3d-ssl + sed -i -r 's/TLS_CERTFILE=\/etc\/courier\/pop3d.pem/TLS_CERTFILE=\/etc\/letsencrypt\/live\/'$(hostname)'-combined.pem/g' /etc/courier/pop3d-ssl + # needed to support gmail + sed -i -r 's/TLS_TRUSTCERTS=\/etc\/ssl\/certs/TLS_TRUSTCERTS=\/etc\/letsencrypt\/live\/'$(hostname)'-fullchain.pem/g' /etc/courier/pop3d-ssl + echo "SSL configured with letsencrypt certificates" ;; @@ -95,6 +101,10 @@ case $DMS_SSL in # Courier configuration sed -i -r 's/TLS_CERTFILE=\/etc\/courier\/imapd.pem/TLS_CERTFILE=\/etc\/postfix\/ssl\/'$(hostname)'-combined.pem/g' /etc/courier/imapd-ssl + + # POP3 courier configuration + sed -i -r 's/POP3_TLS_REQUIRED=0/POP3_TLS_REQUIRED=1/g' /etc/courier/pop3d-ssl + sed -i -r 's/TLS_CERTFILE=\/etc\/courier\/pop3d.pem/TLS_CERTFILE=\/etc\/postfix\/ssl\/'$(hostname)'-combined.pem/g' /etc/courier/pop3d-ssl fi ;; @@ -123,6 +133,13 @@ cron /etc/init.d/courier-authdaemon start /etc/init.d/courier-imap start /etc/init.d/courier-imap-ssl start + +if [ "$ENABLE_POP3" = 1 ]; then + echo "Starting POP3 services" + /etc/init.d/courier-pop start + /etc/init.d/courier-pop-ssl start +fi + /etc/init.d/spamassassin start /etc/init.d/clamav-daemon start /etc/init.d/amavis start diff --git a/test/auth/pop3-auth.txt b/test/auth/pop3-auth.txt new file mode 100644 index 00000000..34cdcd56 --- /dev/null +++ b/test/auth/pop3-auth.txt @@ -0,0 +1,4 @@ +USER user1@localhost.localdomain +PASS mypassword +LIST +quit diff --git a/test/test.sh b/test/test.sh index 555338b2..609845be 100644 --- a/test/test.sh +++ b/test/test.sh @@ -3,16 +3,24 @@ # Set up test framework source assert.sh -# Testing that services are running +# Testing that services are running and pop3 is disabled assert_raises "docker exec mail ps aux --forest | grep '/usr/lib/postfix/master'" 0 assert_raises "docker exec mail ps aux --forest | grep '/usr/sbin/saslauthd'" 0 assert_raises "docker exec mail ps aux --forest | grep '/usr/sbin/clamd'" 0 assert_raises "docker exec mail ps aux --forest | grep '/usr/sbin/amavisd-new'" 0 +assert_raises "docker exec mail ps aux --forest | grep '/usr/lib/courier/courier/courierpop3d'" 1 + +# Testing services of pop3 container +assert_raises "docker exec mail_pop3 ps aux --forest | grep '/usr/lib/courier/courier/courierpop3d'" 0 # Testing IMAP server assert_raises "docker exec mail nc -w 1 0.0.0.0 143 | grep '* OK' | grep 'STARTTLS' | grep 'Courier-IMAP ready'" 0 assert_raises "docker exec mail /bin/sh -c 'nc -w 1 0.0.0.0 143 < /tmp/test/auth/imap-auth.txt'" 0 +# Testing POP3 server on pop3 container +assert_raises "docker exec mail_pop3 nc -w 1 0.0.0.0 110 | grep '+OK'" 0 +assert_raises "docker exec mail_pop3 /bin/sh -c 'nc -w 1 0.0.0.0 110 < /tmp/test/auth/pop3-auth.txt'" 0 + # Testing SASL assert_raises "docker exec mail testsaslauthd -u user2 -r otherdomain.tld -p mypassword | grep 'OK \"Success.\"'" 0 assert_raises "docker exec mail testsaslauthd -u user2 -r otherdomain.tld -p BADPASSWORD | grep 'NO \"authentication failed\"'" 0 @@ -53,5 +61,9 @@ assert "docker exec mail crontab -l" "0 1 * * * /usr/bin/freshclam --quiet" assert_raises "docker exec mail grep 'non-null host address bits in' /var/log/mail.log" 1 assert_raises "docker exec mail grep ': error:' /var/log/mail.log" 1 +# Testing that pop3 container log don't display errors +assert_raises "docker exec mail_pop3 grep 'non-null host address bits in' /var/log/mail.log" 1 +assert_raises "docker exec mail_pop3 grep ': error:' /var/log/mail.log" 1 + # Ending tests assert_end From 25d457dae7e60926b3f53ee51440866d5acfde0c Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Mon, 25 Jan 2016 18:23:35 +0100 Subject: [PATCH 106/155] Fixes #65 and improves SSL documentation about LetsEncrypt. --- SSL.md | 1 + 1 file changed, 1 insertion(+) diff --git a/SSL.md b/SSL.md index 13fa91df..e8dd801f 100644 --- a/SSL.md +++ b/SSL.md @@ -14,6 +14,7 @@ To enable Let's Encrypt on your mail server, you have to: * get your certificate using [letsencrypt client](https://github.com/letsencrypt/letsencrypt) * add an environment variable `DMS_SSL` with value `letsencrypt` (see `docker-compose.yml.dist`) * mount your `letsencrypt` folder to `/etc/letsencrypt` +* the folder name must be the `fqdn` that is passed as `-h` argument (or concatenation of `hostname` and `domainname` is you are using `docker-compose`) You don't have anything else to do. Enjoy. From 0cf4b9eadb9fccea13c678c246403b5fc1f2196e Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Tue, 26 Jan 2016 17:05:07 +0100 Subject: [PATCH 107/155] Improves #55 and #56 with OpenDKIM tests --- test/test.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/test.sh b/test/test.sh index 609845be..afe9f260 100644 --- a/test/test.sh +++ b/test/test.sh @@ -9,6 +9,7 @@ assert_raises "docker exec mail ps aux --forest | grep '/usr/sbin/saslauthd'" 0 assert_raises "docker exec mail ps aux --forest | grep '/usr/sbin/clamd'" 0 assert_raises "docker exec mail ps aux --forest | grep '/usr/sbin/amavisd-new'" 0 assert_raises "docker exec mail ps aux --forest | grep '/usr/lib/courier/courier/courierpop3d'" 1 +assert_raises "docker exec mail ps aux --forest | grep '/usr/sbin/opendkim'" 0 # Testing services of pop3 container assert_raises "docker exec mail_pop3 ps aux --forest | grep '/usr/lib/courier/courier/courierpop3d'" 0 @@ -65,5 +66,8 @@ assert_raises "docker exec mail grep ': error:' /var/log/mail.log" 1 assert_raises "docker exec mail_pop3 grep 'non-null host address bits in' /var/log/mail.log" 1 assert_raises "docker exec mail_pop3 grep ': error:' /var/log/mail.log" 1 +# Testing OpenDKIM +assert "docker exec mail cat /etc/opendkim/KeyTable | wc -l | sed -e 's/^[ \t]*//'" "2" + # Ending tests assert_end From 07ec823f45c2a72a04a489e7abe48b6c362322cb Mon Sep 17 00:00:00 2001 From: bilak Date: Tue, 26 Jan 2016 18:26:50 +0100 Subject: [PATCH 108/155] - added DMARC (opendmarc) support with basic setup --- Dockerfile | 6 +++++- README.md | 1 + postfix/default-opendmarc | 11 +++++++++++ postfix/main.cf | 4 ++-- postfix/opendmarc.conf | 8 ++++++++ start-mailserver.sh | 15 +++++++++++++++ 6 files changed, 42 insertions(+), 3 deletions(-) create mode 100644 postfix/default-opendmarc create mode 100644 postfix/opendmarc.conf diff --git a/Dockerfile b/Dockerfile index f4437048..d7dd15a9 100644 --- a/Dockerfile +++ b/Dockerfile @@ -7,7 +7,7 @@ RUN apt-get -y upgrade RUN DEBIAN_FRONTEND=noninteractive apt-get -y install vim postfix sasl2-bin courier-imap courier-imap-ssl \ courier-pop courier-pop-ssl courier-authdaemon supervisor gamin amavisd-new spamassassin clamav clamav-daemon libnet-dns-perl libmail-spf-perl \ pyzor razor arj bzip2 cabextract cpio file gzip nomarch p7zip pax unzip zip zoo rsyslog mailutils netcat \ - opendkim opendkim-tools + opendkim opendkim-tools opendmarc RUN apt-get autoclean && rm -rf /var/lib/apt/lists/* # Configures Saslauthd @@ -40,6 +40,10 @@ ADD postfix/TrustedHosts /etc/opendkim/TrustedHosts ADD postfix/opendkim.conf /etc/opendkim.conf ADD postfix/default-opendkim /etc/default/opendkim +# Configure DMARC (opendmarc) +ADD postfix/opendmarc.conf /etc/opendmarc.conf +ADD postfix/default-opendmarc /etc/default/opendmarc + # Configures Postfix ADD postfix/main.cf /etc/postfix/main.cf diff --git a/README.md b/README.md index d54d3b66..5c206942 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,7 @@ Includes: - spamassasin - clamav with automatic updates - opendkim +- opendmarc (basic setup) - [LetsEncrypt](https://letsencrypt.org/) and self-signed certificates - optional pop3 server (add `-e ENABLE_POP3=1` to enable pop3 server) diff --git a/postfix/default-opendmarc b/postfix/default-opendmarc new file mode 100644 index 00000000..896f5839 --- /dev/null +++ b/postfix/default-opendmarc @@ -0,0 +1,11 @@ +# Command-line options specified here will override the contents of +# /etc/opendmarc.conf. See opendmarc(8) for a complete list of options. +#DAEMON_OPTS="" +# +# Uncomment to specify an alternate socket +# Note that setting this will override any Socket value in opendkim.conf +#SOCKET="local:/var/run/opendmarc/opendmarc.sock" # default +#SOCKET="inet:54321" # listen on all interfaces on port 54321 +#SOCKET="inet:12345@localhost" # listen on loopback on port 12345 +#SOCKET="inet:12345@192.0.2.1" # listen on 192.0.2.1 on port 12345 +SOCKET="inet:54321@localhost" \ No newline at end of file diff --git a/postfix/main.cf b/postfix/main.cf index c0fbc9e6..593b6394 100644 --- a/postfix/main.cf +++ b/postfix/main.cf @@ -61,5 +61,5 @@ content_filter = smtp-amavis:[127.0.0.1]:10024 # Milters used by DKIM milter_protocol = 2 milter_default_action = accept -smtpd_milters = inet:localhost:12301 -non_smtpd_milters = inet:localhost:12301 +smtpd_milters = inet:localhost:12301,inet:localhost:54321 +non_smtpd_milters = inet:localhost:12301,inet:localhost:54321 diff --git a/postfix/opendmarc.conf b/postfix/opendmarc.conf new file mode 100644 index 00000000..89bce44d --- /dev/null +++ b/postfix/opendmarc.conf @@ -0,0 +1,8 @@ + +PidFile /var/run/opendmarc.pid +RejectFailures false +Syslog true +UMask 0002 +UserID opendmarc:opendmarc +IgnoreHosts /etc/opendmarc/ignore.hosts +HistoryFile /var/run/opendmarc/opendmarc.dat \ No newline at end of file diff --git a/start-mailserver.sh b/start-mailserver.sh index 29e85cf8..9fa9c260 100644 --- a/start-mailserver.sh +++ b/start-mailserver.sh @@ -97,6 +97,20 @@ chown -R opendkim:opendkim /etc/opendkim/ # And make sure permissions are right chmod -R 0700 /etc/opendkim/keys/ +# DMARC +# if ther is no AuthservID create it +if [ `cat /etc/opendmarc.conf | grep AuthservID | wc -l` -gt 0 ]; then + echo "AuthservID $hostname" >> /etc/opendmarc.conf +fi +if [ `cat /etc/opendmarc.conf | grep TrustedAuthservIDs | wc -l` -gt 0 ]; then + echo "TrustedAuthservIDs $hostname" >> /etc/opendmarc.conf +fi +if [ ! -f "/etc/opendmarc/ignore.hosts" ]; then + mkdir -p /etc/opendmarc/ + echo "localhost" >> /etc/opendmarc/ignore.hosts +fi + + # SSL Configuration case $DMS_SSL in @@ -188,6 +202,7 @@ fi /etc/init.d/clamav-daemon start /etc/init.d/amavis start /etc/init.d/opendkim start +/etc/init.d/opendmarc start /etc/init.d/postfix start echo "Listing SASL users" From b73e602e3ebaeb51a828d07adb5c02d01b2cad74 Mon Sep 17 00:00:00 2001 From: bilak Date: Tue, 26 Jan 2016 18:53:57 +0100 Subject: [PATCH 109/155] - fixed equal sign --- start-mailserver.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/start-mailserver.sh b/start-mailserver.sh index 9fa9c260..d35f712d 100644 --- a/start-mailserver.sh +++ b/start-mailserver.sh @@ -99,10 +99,10 @@ chmod -R 0700 /etc/opendkim/keys/ # DMARC # if ther is no AuthservID create it -if [ `cat /etc/opendmarc.conf | grep AuthservID | wc -l` -gt 0 ]; then +if [ `cat /etc/opendmarc.conf | grep AuthservID | wc -l` -eq 0 ]; then echo "AuthservID $hostname" >> /etc/opendmarc.conf fi -if [ `cat /etc/opendmarc.conf | grep TrustedAuthservIDs | wc -l` -gt 0 ]; then +if [ `cat /etc/opendmarc.conf | grep TrustedAuthservIDs | wc -l` -eq 0 ]; then echo "TrustedAuthservIDs $hostname" >> /etc/opendmarc.conf fi if [ ! -f "/etc/opendmarc/ignore.hosts" ]; then From cc7270a22bf84025e70eb3607c1beda4b492885f Mon Sep 17 00:00:00 2001 From: bilak Date: Tue, 26 Jan 2016 19:03:12 +0100 Subject: [PATCH 110/155] - improved searching strings inside file (seraching for whole words) --- start-mailserver.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/start-mailserver.sh b/start-mailserver.sh index d35f712d..e5f25489 100644 --- a/start-mailserver.sh +++ b/start-mailserver.sh @@ -99,10 +99,10 @@ chmod -R 0700 /etc/opendkim/keys/ # DMARC # if ther is no AuthservID create it -if [ `cat /etc/opendmarc.conf | grep AuthservID | wc -l` -eq 0 ]; then +if [ `cat /etc/opendmarc.conf | grep -w AuthservID | wc -l` -eq 0 ]; then echo "AuthservID $hostname" >> /etc/opendmarc.conf fi -if [ `cat /etc/opendmarc.conf | grep TrustedAuthservIDs | wc -l` -eq 0 ]; then +if [ `cat /etc/opendmarc.conf | grep -w TrustedAuthservIDs | wc -l` -eq 0 ]; then echo "TrustedAuthservIDs $hostname" >> /etc/opendmarc.conf fi if [ ! -f "/etc/opendmarc/ignore.hosts" ]; then From 9e81e1cae763dd16095d8541cba30fa08423008c Mon Sep 17 00:00:00 2001 From: bilak Date: Thu, 28 Jan 2016 12:00:31 +0100 Subject: [PATCH 111/155] - fixed crash of opendmarc --- postfix/opendmarc.conf | 2 +- start-mailserver.sh | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/postfix/opendmarc.conf b/postfix/opendmarc.conf index 89bce44d..8ff5ad16 100644 --- a/postfix/opendmarc.conf +++ b/postfix/opendmarc.conf @@ -5,4 +5,4 @@ Syslog true UMask 0002 UserID opendmarc:opendmarc IgnoreHosts /etc/opendmarc/ignore.hosts -HistoryFile /var/run/opendmarc/opendmarc.dat \ No newline at end of file +HistoryFile /var/run/opendmarc/opendmarc.dat diff --git a/start-mailserver.sh b/start-mailserver.sh index e5f25489..4da87c74 100644 --- a/start-mailserver.sh +++ b/start-mailserver.sh @@ -100,10 +100,10 @@ chmod -R 0700 /etc/opendkim/keys/ # DMARC # if ther is no AuthservID create it if [ `cat /etc/opendmarc.conf | grep -w AuthservID | wc -l` -eq 0 ]; then - echo "AuthservID $hostname" >> /etc/opendmarc.conf + echo "AuthservID $(hostname)" >> /etc/opendmarc.conf fi if [ `cat /etc/opendmarc.conf | grep -w TrustedAuthservIDs | wc -l` -eq 0 ]; then - echo "TrustedAuthservIDs $hostname" >> /etc/opendmarc.conf + echo "TrustedAuthservIDs $(hostname)" >> /etc/opendmarc.conf fi if [ ! -f "/etc/opendmarc/ignore.hosts" ]; then mkdir -p /etc/opendmarc/ From 23ef4ae2eefe265924abd2a31b8f7fa3950c77bb Mon Sep 17 00:00:00 2001 From: bilak Date: Thu, 28 Jan 2016 20:56:15 +0100 Subject: [PATCH 112/155] - added test for opendkim --- test/test.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/test.sh b/test/test.sh index afe9f260..be7b4c74 100644 --- a/test/test.sh +++ b/test/test.sh @@ -69,5 +69,9 @@ assert_raises "docker exec mail_pop3 grep ': error:' /var/log/mail.log" 1 # Testing OpenDKIM assert "docker exec mail cat /etc/opendkim/KeyTable | wc -l | sed -e 's/^[ \t]*//'" "2" +# Testing OpenDMARC +assert "docker exec mail cat /etc/opendmarc.conf | grep ^AuthservID | wc -l" "1" +assert "docker exec mail cat /etc/opendmarc.conf | grep ^TrustedAuthservID | wc -l" "1" + # Ending tests assert_end From 5c4a5fee92d98076b323da7500c29b8b4964aa24 Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Mon, 1 Feb 2016 15:05:29 +0100 Subject: [PATCH 113/155] Simplified README and linked to FAQ. --- README.md | 118 +++++++++++++++++----------------------- docker-compose.yml.dist | 5 +- 2 files changed, 52 insertions(+), 71 deletions(-) diff --git a/README.md b/README.md index 5c206942..5232578e 100644 --- a/README.md +++ b/README.md @@ -11,55 +11,30 @@ Includes: - postfix with smtp auth - courier-imap with ssl support - amavis -- spamassasin +- spamassasin supporting custom rules - clamav with automatic updates - opendkim -- opendmarc (basic setup) +- opendmarc - [LetsEncrypt](https://letsencrypt.org/) and self-signed certificates -- optional pop3 server (add `-e ENABLE_POP3=1` to enable pop3 server) +- optional pop3 server +- [integration tests](https://travis-ci.org/tomav/docker-mailserver) +- [automated builds on docker hub](https://hub.docker.com/r/tvial/docker-mailserver/) Why I created this image: [Simple mail server with Docker](http://tvi.al/simple-mail-server-with-docker/) -## informations: +Before you open an issue, please have a look this `README`, the [FAQ](wiki/FAQ) and Postfix documentation. -- only config files, no *sql database required -- mails are stored in `/var/mail/${domain}/${username}` -- you should use a data volume container for `/var/mail` for data persistence -- email login are full email address (`username1@my-domain.com`) -- user accounts are managed in `./postfix/accounts.cf` -- aliases and fowards/redirects are managed in `./postfix/virtual` -- antispam rules are managed in `./spamassassin/rules.cf` -- files must be mounted to `/tmp` in your container (see `docker-compose.yml` template) -- ssl is strongly recommended, read [SSL.md](SSL.md) to use LetsEncrypt or Self-Signed Certificates -- [includes integration tests](https://travis-ci.org/tomav/docker-mailserver) -- [builds automated on docker hub](https://hub.docker.com/r/tvial/docker-mailserver/) -- dkim public key will be echoed to log. If you have your previous configuration, you can mount volume with it `-v "$(pwd)/opendkim":/etc/opendkim"` +## Usage -## installation - - docker pull tvial/docker-mailserver - -## build - - docker build -t tvial/docker-mailserver . - -## run - - docker run --name mail \ - -v "$(pwd)/postfix":/tmp/postfix \ - -v "$(pwd)/spamassassin":/tmp/spamassassin \ - -v "$(pwd)/letsencrypt/etc":/etc/letsencrypt \ - -p "25:25" -p "143:143" -p "587:587" -p "993:993" \ - -e DMS_SSL=letsencrypt \ - -h mail.domain.com \ - -t tvial/docker-mailserver - -## docker-compose template (recommended) + # get latest image + docker pull tvial/docker-mailserver + # create a "docker-compose.yml" file containing: mail: image: tvial/docker-mailserver hostname: mail domainname: domain.com + # your FQDN will be 'mail.domain.com' ports: - "25:25" - "143:143" @@ -68,51 +43,60 @@ Why I created this image: [Simple mail server with Docker](http://tvi.al/simple- volumes: - ./spamassassin:/tmp/spamassassin/ - ./postfix:/tmp/postfix/ - - ./letsencrypt/etc:/etc/letsencrypt - environment: - - DMS_SSL=letsencrypt -Volumes allow to: + # start he container + docker-compose up -d mail -- Insert custom antispam rules -- Manage mail users, passwords and aliases -- Manage SSL certificates +## Managing users and aliases -# usage +### Users - docker-compose up -d mail +Users are managed in `postfix/accounts.cf`. +Just add the full email address and its password separated by a pipe. -# client configuration +Example: - # imap - username: - password: - server: - imap port: 143 or 993 with ssl (recommended) - imap path prefix: INBOX - auth method: md5 challenge-response + user1@domain.tld|mypassword + user2@otherdomain.tld|myotherpassword - # smtp - smtp port: 25 or 587 with ssl (recommended) - username: - password: - auth method: md5 challenge-response +### Aliases -# backups +Please first read [Postfix documentation on virtual aliases](http://www.postfix.org/VIRTUAL_README.html#virtual_alias). -Assuming that you use `docker-compose` and a data volume container named `maildata`, you can backup your user mails like this: +Aliases are managed in `postfix/virtual`. +An alias is a full email address that will be: +* delivered to an existing account in `postfix/accounts.cf` +* redirected to one or more other email adresses - docker run --rm \ - --volumes-from maildata_1 \ - -v "$(pwd)":/backups \ - -ti tvial/docker-mailserver \ - tar cvzf /backups/docker-mailserver-`date +%y%m%d-%H%M%S`.tgz /var/mail +Alias and target are space separated. -# todo +Example: + + # Alias to existing account + alias1@domain.tld user1@domain.tld + + # Forward to external email address + alias2@domain.tld external@gmail.com + +## Environment variables + +* DMS_SSL + * *empty* (default) => SSL disabled + * letsencrypt => Enables Let's Encrypt certificates + * self-signed => Enables self-signed certificates +* ENABLE_POP3 + * *empty* (default) => POP3 service disabled + * 1 => Enables POP3 service + +## SSL + +Please read [SSL.md](SSL.md) for more information. + +## Todo Things to do or to improve are stored on [Github](https://github.com/tomav/docker-mailserver/issues), some open by myself. Feel free to improve this docker image. -# wanna help? +## Wanna help? Fork, improve, add tests and PR. ;-) diff --git a/docker-compose.yml.dist b/docker-compose.yml.dist index f5d24f88..69501fc4 100644 --- a/docker-compose.yml.dist +++ b/docker-compose.yml.dist @@ -1,6 +1,5 @@ mail: - # image: tvial/docker-mailserver - build: . + image: tvial/docker-mailserver hostname: mail domainname: domain.com ports: @@ -11,6 +10,4 @@ mail: volumes: - ./spamassassin:/tmp/spamassassin/ - ./postfix:/tmp/postfix/ - - ./letsencrypt/etc:/etc/letsencrypt environment: - - DMS_SSL=letsencrypt From 1c3b86dc41d572f696c200286dcd4c5705d23e79 Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Mon, 1 Feb 2016 15:06:39 +0100 Subject: [PATCH 114/155] Fixed FAQ url --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5232578e..56d0ee0a 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ Includes: Why I created this image: [Simple mail server with Docker](http://tvi.al/simple-mail-server-with-docker/) -Before you open an issue, please have a look this `README`, the [FAQ](wiki/FAQ) and Postfix documentation. +Before you open an issue, please have a look this `README`, the [FAQ](https://github.com/tomav/docker-mailserver/wiki/FAQ) and Postfix documentation. ## Usage From 97a495ae1d2133ee20d2c9673ef703127a027462 Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Wed, 3 Feb 2016 22:45:11 +0100 Subject: [PATCH 115/155] Added tests and simplified some of them --- Makefile | 11 ++++------- README.md | 2 ++ test/test.sh | 15 ++++++++++----- 3 files changed, 16 insertions(+), 12 deletions(-) diff --git a/Makefile b/Makefile index 93cb6314..1b178117 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,8 @@ NAME = tvial/docker-mailserver VERSION = $(TRAVIS_BUILD_ID) -all: build run prepare fixtures tests +all: build run fixtures tests clean +all-no-build: run fixtures tests clean build: docker build --no-cache -t $(NAME):$(VERSION) . @@ -13,12 +14,7 @@ run: # Run containers docker run -d --name mail -v "`pwd`/postfix":/tmp/postfix -v "`pwd`/spamassassin":/tmp/spamassassin -v "`pwd`/test":/tmp/test -h mail.my-domain.com -t $(NAME):$(VERSION) docker run -d --name mail_pop3 -v "`pwd`/postfix":/tmp/postfix -v "`pwd`/spamassassin":/tmp/spamassassin -v "`pwd`/test":/tmp/test -e ENABLE_POP3=1 -h mail.my-domain.com -t $(NAME):$(VERSION) - sleep 25 - -prepare: - # Reinitialize logs - docker exec mail /bin/sh -c 'echo "" > /var/log/mail.log' - docker exec mail_pop3 /bin/sh -c 'echo "" > /var/log/mail.log' + sleep 60 fixtures: # Sending test mails @@ -38,3 +34,4 @@ tests: clean: # Get default files back git checkout postfix/accounts.cf postfix/virtual + docker rm -f mail mail_pop3 \ No newline at end of file diff --git a/README.md b/README.md index 56d0ee0a..9bdf89ff 100644 --- a/README.md +++ b/README.md @@ -88,6 +88,8 @@ Example: * *empty* (default) => POP3 service disabled * 1 => Enables POP3 service +Please read [how the container starts](https://github.com/tomav/docker-mailserver/blob/master/start-mailserver.sh) to understand what's expected. + ## SSL Please read [SSL.md](SSL.md) for more information. diff --git a/test/test.sh b/test/test.sh index be7b4c74..49a2de27 100644 --- a/test/test.sh +++ b/test/test.sh @@ -8,8 +8,9 @@ assert_raises "docker exec mail ps aux --forest | grep '/usr/lib/postfix/master' assert_raises "docker exec mail ps aux --forest | grep '/usr/sbin/saslauthd'" 0 assert_raises "docker exec mail ps aux --forest | grep '/usr/sbin/clamd'" 0 assert_raises "docker exec mail ps aux --forest | grep '/usr/sbin/amavisd-new'" 0 -assert_raises "docker exec mail ps aux --forest | grep '/usr/lib/courier/courier/courierpop3d'" 1 assert_raises "docker exec mail ps aux --forest | grep '/usr/sbin/opendkim'" 0 +assert_raises "docker exec mail ps aux --forest | grep '/usr/sbin/opendmarc'" 0 +assert_raises "docker exec mail ps aux --forest | grep '/usr/lib/courier/courier/courierpop3d'" 1 # Testing services of pop3 container assert_raises "docker exec mail_pop3 ps aux --forest | grep '/usr/lib/courier/courier/courierpop3d'" 0 @@ -38,7 +39,7 @@ assert "docker exec mail cat /etc/postfix/vhost" "localhost.localdomain\notherdo # Testing that mail is received for existing user assert_raises "docker exec mail grep 'status=sent (delivered to maildir)' /var/log/mail.log" 0 -assert "docker exec mail ls -A /var/mail/localhost.localdomain/user1/new | wc -l | sed -e 's/^[ \t]*//'" "2" +assert "docker exec mail ls -A /var/mail/localhost.localdomain/user1/new | wc -l" "2" # Testing that mail is rejected for non existing user assert_raises "docker exec mail grep ': Recipient address rejected: User unknown in virtual mailbox table' /var/log/mail.log" 0 @@ -50,10 +51,10 @@ assert_raises "docker exec mail grep 'to=, orig_to= assert_raises "docker exec mail grep -- '-> ' /var/log/mail.log" 0 # Testing that a SPAM is rejected -assert_raises "docker exec mail grep 'Blocked SPAM' /var/log/mail.log | grep spam@external.tld" +assert_raises "docker exec mail grep 'Blocked SPAM' /var/log/mail.log | grep spam@external.tld" 0 # Testing that a Virus is rejected -assert_raises "docker exec mail grep 'Blocked INFECTED' /var/log/mail.log | grep virus@external.tld" +assert_raises "docker exec mail grep 'Blocked INFECTED' /var/log/mail.log | grep virus@external.tld" 0 # Testing presence of freshclam CRON assert "docker exec mail crontab -l" "0 1 * * * /usr/bin/freshclam --quiet" @@ -67,11 +68,15 @@ assert_raises "docker exec mail_pop3 grep 'non-null host address bits in' /var/l assert_raises "docker exec mail_pop3 grep ': error:' /var/log/mail.log" 1 # Testing OpenDKIM -assert "docker exec mail cat /etc/opendkim/KeyTable | wc -l | sed -e 's/^[ \t]*//'" "2" +assert "docker exec mail cat /etc/opendkim/KeyTable | wc -l" "2" +assert "docker exec mail ls -l /etc/opendkim/keys/ | grep '^d' | wc -l" "2" # Testing OpenDMARC assert "docker exec mail cat /etc/opendmarc.conf | grep ^AuthservID | wc -l" "1" assert "docker exec mail cat /etc/opendmarc.conf | grep ^TrustedAuthservID | wc -l" "1" +# Testing hostname config +assert "docker exec mail cat /etc/mailname" "my-domain.com" + # Ending tests assert_end From a13cbcb9aa91fc0560314ef00d130fdca82608d4 Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Thu, 4 Feb 2016 08:51:07 +0100 Subject: [PATCH 116/155] Improved documentation --- Makefile | 2 ++ README.md | 9 +++++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 1b178117..f96bc3c9 100644 --- a/Makefile +++ b/Makefile @@ -14,6 +14,7 @@ run: # Run containers docker run -d --name mail -v "`pwd`/postfix":/tmp/postfix -v "`pwd`/spamassassin":/tmp/spamassassin -v "`pwd`/test":/tmp/test -h mail.my-domain.com -t $(NAME):$(VERSION) docker run -d --name mail_pop3 -v "`pwd`/postfix":/tmp/postfix -v "`pwd`/spamassassin":/tmp/spamassassin -v "`pwd`/test":/tmp/test -e ENABLE_POP3=1 -h mail.my-domain.com -t $(NAME):$(VERSION) + # Wait for containers to fully start sleep 60 fixtures: @@ -34,4 +35,5 @@ tests: clean: # Get default files back git checkout postfix/accounts.cf postfix/virtual + # Remove running test containers docker rm -f mail mail_pop3 \ No newline at end of file diff --git a/README.md b/README.md index 9bdf89ff..114bdafb 100644 --- a/README.md +++ b/README.md @@ -99,6 +99,11 @@ Please read [SSL.md](SSL.md) for more information. Things to do or to improve are stored on [Github](https://github.com/tomav/docker-mailserver/issues), some open by myself. Feel free to improve this docker image. -## Wanna help? +## Contribute -Fork, improve, add tests and PR. ;-) +- Fork +- Improve +- Add integration tests in `test/test.sh` +- Build image and run tests using `make` +- Document your improvements +- Commit, push and make a pull-request From 6cf6a5df5d4a0217e4582d441fd10de7349e31e2 Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Mon, 8 Feb 2016 23:47:42 +0100 Subject: [PATCH 117/155] Added test on default ssl certs and added letsencrypt X1 and X2 certificates --- Dockerfile | 7 +++++-- SSL.md | 10 ++++++++++ test/test.sh | 7 +++++++ 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index d7dd15a9..bf4ab16d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -7,7 +7,7 @@ RUN apt-get -y upgrade RUN DEBIAN_FRONTEND=noninteractive apt-get -y install vim postfix sasl2-bin courier-imap courier-imap-ssl \ courier-pop courier-pop-ssl courier-authdaemon supervisor gamin amavisd-new spamassassin clamav clamav-daemon libnet-dns-perl libmail-spf-perl \ pyzor razor arj bzip2 cabextract cpio file gzip nomarch p7zip pax unzip zip zoo rsyslog mailutils netcat \ - opendkim opendkim-tools opendmarc + opendkim opendkim-tools opendmarc curl RUN apt-get autoclean && rm -rf /var/lib/apt/lists/* # Configures Saslauthd @@ -44,7 +44,6 @@ ADD postfix/default-opendkim /etc/default/opendkim ADD postfix/opendmarc.conf /etc/opendmarc.conf ADD postfix/default-opendmarc /etc/default/opendmarc - # Configures Postfix ADD postfix/main.cf /etc/postfix/main.cf ADD postfix/master.cf /etc/postfix/master.cf @@ -52,6 +51,10 @@ ADD postfix/sasl/smtpd.conf /etc/postfix/sasl/smtpd.conf ADD bin/generate-ssl-certificate /usr/local/bin/generate-ssl-certificate RUN chmod +x /usr/local/bin/generate-ssl-certificate +# Get LetsEncrypt signed certificate +RUN curl https://letsencrypt.org/certs/lets-encrypt-x1-cross-signed.pem > /etc/ssl/certs/lets-encrypt-x1-cross-signed.pem +RUN curl https://letsencrypt.org/certs/lets-encrypt-x2-cross-signed.pem > /etc/ssl/certs/lets-encrypt-x2-cross-signed.pem + # Start-mailserver script ADD start-mailserver.sh /usr/local/bin/start-mailserver.sh RUN chmod +x /usr/local/bin/start-mailserver.sh diff --git a/SSL.md b/SSL.md index e8dd801f..c43b5361 100644 --- a/SSL.md +++ b/SSL.md @@ -48,3 +48,13 @@ To use the certificate: * add an `DMS_SSL=self-signed` to your container environment variables * if a matching certificate (files listed above) is found in `postfix/ssl`, it will be automatically setup in postfix and courier-imap-ssl. You just have to place them in `postfix/ssl` folder. + +### Testing certificate + +From your host: + + docker exec mail openssl s_client -connect 0.0.0.0:587 -starttls smtp -CApath /etc/ssl/certs/ + +And you should see the certificate chain, the server certificate and: + + Verify return code: 0 (ok) \ No newline at end of file diff --git a/test/test.sh b/test/test.sh index 49a2de27..a6cc6efa 100644 --- a/test/test.sh +++ b/test/test.sh @@ -78,5 +78,12 @@ assert "docker exec mail cat /etc/opendmarc.conf | grep ^TrustedAuthservID | wc # Testing hostname config assert "docker exec mail cat /etc/mailname" "my-domain.com" +# Testing presence of LetsEncrypt signed certs +assert_raises "docker exec mail grep 'BEGIN CERTIFICATE' /etc/ssl/certs/lets-encrypt-x1-cross-signed.pem" "0" +assert_raises "docker exec mail grep 'BEGIN CERTIFICATE' /etc/ssl/certs/lets-encrypt-x2-cross-signed.pem" "0" + +# Testing generated ssl certs +assert_raises "docker exec mail openssl s_client -connect 0.0.0.0:587 -starttls smtp -CApath /etc/ssl/certs/ | grep 'Verify return code: 0 (ok)'" "0" + # Ending tests assert_end From 37d6871f1bcd5356615253a435430bddd319d2b8 Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Tue, 9 Feb 2016 13:03:00 +0100 Subject: [PATCH 118/155] Fixed combined.pem --- start-mailserver.sh | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/start-mailserver.sh b/start-mailserver.sh index 4da87c74..20766af5 100644 --- a/start-mailserver.sh +++ b/start-mailserver.sh @@ -110,8 +110,6 @@ if [ ! -f "/etc/opendmarc/ignore.hosts" ]; then echo "localhost" >> /etc/opendmarc/ignore.hosts fi - - # SSL Configuration case $DMS_SSL in "letsencrypt" ) @@ -122,7 +120,7 @@ case $DMS_SSL in sed -i -r 's/smtpd_tls_key_file=\/etc\/ssl\/private\/ssl-cert-snakeoil.key/smtpd_tls_key_file=\/etc\/letsencrypt\/live\/'$(hostname)'\/privkey.pem/g' /etc/postfix/main.cf # Courier configuration - cat "/etc/letsencrypt/live/$(hostname)/privkey.pem" "/etc/letsencrypt/live/$(hostname)/cert.pem" > "/etc/letsencrypt/live/$(hostname)/combined.pem" + cat "/etc/letsencrypt/live/$(hostname)/cert.pem" "/etc/letsencrypt/live/$(hostname)/chain.pem" "/etc/letsencrypt/live/$(hostname)/privkey.pem" > "/etc/letsencrypt/live/$(hostname)/combined.pem" sed -i -r 's/TLS_CERTFILE=\/etc\/courier\/imapd.pem/TLS_CERTFILE=\/etc\/letsencrypt\/live\/'$(hostname)'\/combined.pem/g' /etc/courier/imapd-ssl # POP3 courier configuration From fc36bce383db08136f4a24db054a6fe1a6407107 Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Tue, 9 Feb 2016 13:13:52 +0100 Subject: [PATCH 119/155] Removed whitespace --- start-mailserver.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/start-mailserver.sh b/start-mailserver.sh index 20766af5..17ec186b 100644 --- a/start-mailserver.sh +++ b/start-mailserver.sh @@ -120,7 +120,7 @@ case $DMS_SSL in sed -i -r 's/smtpd_tls_key_file=\/etc\/ssl\/private\/ssl-cert-snakeoil.key/smtpd_tls_key_file=\/etc\/letsencrypt\/live\/'$(hostname)'\/privkey.pem/g' /etc/postfix/main.cf # Courier configuration - cat "/etc/letsencrypt/live/$(hostname)/cert.pem" "/etc/letsencrypt/live/$(hostname)/chain.pem" "/etc/letsencrypt/live/$(hostname)/privkey.pem" > "/etc/letsencrypt/live/$(hostname)/combined.pem" + cat "/etc/letsencrypt/live/$(hostname)/cert.pem" "/etc/letsencrypt/live/$(hostname)/chain.pem" "/etc/letsencrypt/live/$(hostname)/privkey.pem" > "/etc/letsencrypt/live/$(hostname)/combined.pem" sed -i -r 's/TLS_CERTFILE=\/etc\/courier\/imapd.pem/TLS_CERTFILE=\/etc\/letsencrypt\/live\/'$(hostname)'\/combined.pem/g' /etc/courier/imapd-ssl # POP3 courier configuration From dfd3a486d1e488b897969e024d5f0785cbbb0783 Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Wed, 10 Feb 2016 09:53:51 +0100 Subject: [PATCH 120/155] Moved SSL doc to the Wiki --- README.md | 2 +- SSL.md | 60 ------------------------------------------------------- 2 files changed, 1 insertion(+), 61 deletions(-) delete mode 100644 SSL.md diff --git a/README.md b/README.md index 114bdafb..86811707 100644 --- a/README.md +++ b/README.md @@ -92,7 +92,7 @@ Please read [how the container starts](https://github.com/tomav/docker-mailserve ## SSL -Please read [SSL.md](SSL.md) for more information. +Please read [the SSL page in the wiki](https://github.com/tomav/docker-mailserver/wiki/SSL) for more information. ## Todo diff --git a/SSL.md b/SSL.md deleted file mode 100644 index c43b5361..00000000 --- a/SSL.md +++ /dev/null @@ -1,60 +0,0 @@ -# docker-mailserver with ssl - -There are multiple options to enable SSL: - -* using [letsencrypt](https://letsencrypt.org/) (recommended) -* using self-signed certificates with the provided tool - -After installation, you can test your setup with [checktls.com](https://www.checktls.com/TestReceiver). - -## let's encrypt (recommended) - -To enable Let's Encrypt on your mail server, you have to: - -* get your certificate using [letsencrypt client](https://github.com/letsencrypt/letsencrypt) -* add an environment variable `DMS_SSL` with value `letsencrypt` (see `docker-compose.yml.dist`) -* mount your `letsencrypt` folder to `/etc/letsencrypt` -* the folder name must be the `fqdn` that is passed as `-h` argument (or concatenation of `hostname` and `domainname` is you are using `docker-compose`) - -You don't have anything else to do. Enjoy. - -## self signed certificates - -You can easily generate a self-signed SSL certificate by using the following command: - - docker run -ti --rm -v "$(pwd)"/postfix/ssl:/ssl -h mail.my-domain.com -t tvial/docker-mailserver generate-ssl-certificate - - # Press enter - # Enter a password when needed - # Fill information like Country, Organisation name - # Fill "my-domain.com" as FQDN for CA, and "mail.my-domain.com" for the certificate. - # They HAVE to be different, otherwise you'll get a `TXT_DB error number 2` - # Don't fill extras - # Enter same password when needed - # Sign the certificate? [y/n]:y - # 1 out of 1 certificate requests certified, commit? [y/n]y - - # will generate: - # postfix/ssl/mail.my-domain.com-key.pem (used in postfix) - # postfix/ssl/mail.my-domain.com-req.pem (only used to generate other files) - # postfix/ssl/mail.my-domain.com-cert.pem (used in postfix) - # postfix/ssl/mail.my-domain.com-combined.pem (used in courier) - # postfix/ssl/demoCA/cacert.pem (certificate authority) - -Note that the certificate will be generate for the container `fqdn`, that is passed as `-h` argument. -Check the following page for more information regarding [postfix and SSL/TLS configuration](http://www.mad-hacking.net/documentation/linux/applications/mail/using-ssl-tls-postfix-courier.xml). - -To use the certificate: - -* add an `DMS_SSL=self-signed` to your container environment variables -* if a matching certificate (files listed above) is found in `postfix/ssl`, it will be automatically setup in postfix and courier-imap-ssl. You just have to place them in `postfix/ssl` folder. - -### Testing certificate - -From your host: - - docker exec mail openssl s_client -connect 0.0.0.0:587 -starttls smtp -CApath /etc/ssl/certs/ - -And you should see the certificate chain, the server certificate and: - - Verify return code: 0 (ok) \ No newline at end of file From aa2ae98b2aee55345bd691f50e946b27868bcee5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Picado=20Ladr=C3=B3n=20de=20Guevara?= Date: Thu, 11 Feb 2016 14:00:59 +0100 Subject: [PATCH 121/155] Default imap folders Create default imap folders for Trash, Drafts and Sent. --- start-mailserver.sh | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/start-mailserver.sh b/start-mailserver.sh index 17ec186b..050b9e06 100644 --- a/start-mailserver.sh +++ b/start-mailserver.sh @@ -27,6 +27,12 @@ if [ -f /tmp/postfix/accounts.cf ]; then mkdir -p /var/mail/${domain} if [ ! -d "/var/mail/${domain}/${user}" ]; then maildirmake "/var/mail/${domain}/${user}" + maildirmake "/var/mail/${domain}/${user}/.Sent" + maildirmake "/var/mail/${domain}/${user}/.Trash" + maildirmake "/var/mail/${domain}/${user}/.Drafts" + echo -e "INBOX\nINBOX.Sent\nINBOX.Trash\nInbox.Drafts" >> "/var/mail/${domain}/${user}/courierimapsubscribed" + touch "/var/mail/${domain}/${user}/.Sent/maildirfolder" + fi echo ${domain} >> /tmp/vhost.tmp done < /tmp/postfix/accounts.cf From 7ce4b8c7d90df9733e179a833b4c69360f5df28e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Picado=20Ladr=C3=B3n=20de=20Guevara?= Date: Thu, 11 Feb 2016 18:36:08 +0100 Subject: [PATCH 122/155] Update test.sh --- test/test.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/test.sh b/test/test.sh index a6cc6efa..107e0dcd 100644 --- a/test/test.sh +++ b/test/test.sh @@ -31,8 +31,8 @@ assert_raises "docker exec mail /bin/sh -c 'nc -w 1 0.0.0.0 25 < /tmp/test/auth/ # Testing user creation assert "docker exec mail sasldblistusers2" "user1@localhost.localdomain: userPassword\nuser2@otherdomain.tld: userPassword" -assert "docker exec mail ls -A /var/mail/localhost.localdomain/user1" "cur\nnew\ntmp" -assert "docker exec mail ls -A /var/mail/otherdomain.tld/user2" "cur\nnew\ntmp" +assert "docker exec mail ls -A /var/mail/localhost.localdomain/user1" ".Drafts\n.Sent\n.Trash\ncourierimapsubscribed\ncur\nnew\ntmp" +assert "docker exec mail ls -A /var/mail/otherdomain.tld/user2" ".Drafts\n.Sent\n.Trash\ncourierimapsubscribed\ncur\nnew\ntmp" # Testing `vhost` creation assert "docker exec mail cat /etc/postfix/vhost" "localhost.localdomain\notherdomain.tld" From 7e7c34a256bbdb37e890f284e68297b5be1e6b33 Mon Sep 17 00:00:00 2001 From: Dominik Winter Date: Fri, 12 Feb 2016 00:19:21 +0100 Subject: [PATCH 123/155] added fail2ban --- Dockerfile | 2 +- docker-compose.yml.dist | 1 + start-mailserver.sh | 17 +++++++++++++++++ 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index bf4ab16d..4c893e81 100644 --- a/Dockerfile +++ b/Dockerfile @@ -7,7 +7,7 @@ RUN apt-get -y upgrade RUN DEBIAN_FRONTEND=noninteractive apt-get -y install vim postfix sasl2-bin courier-imap courier-imap-ssl \ courier-pop courier-pop-ssl courier-authdaemon supervisor gamin amavisd-new spamassassin clamav clamav-daemon libnet-dns-perl libmail-spf-perl \ pyzor razor arj bzip2 cabextract cpio file gzip nomarch p7zip pax unzip zip zoo rsyslog mailutils netcat \ - opendkim opendkim-tools opendmarc curl + opendkim opendkim-tools opendmarc curl fail2ban RUN apt-get autoclean && rm -rf /var/lib/apt/lists/* # Configures Saslauthd diff --git a/docker-compose.yml.dist b/docker-compose.yml.dist index 69501fc4..15e07908 100644 --- a/docker-compose.yml.dist +++ b/docker-compose.yml.dist @@ -2,6 +2,7 @@ mail: image: tvial/docker-mailserver hostname: mail domainname: domain.com + privileged: true ports: - "25:25" - "143:143" diff --git a/start-mailserver.sh b/start-mailserver.sh index 050b9e06..f52cd5cb 100644 --- a/start-mailserver.sh +++ b/start-mailserver.sh @@ -188,6 +188,22 @@ echo "required_score 5" >> /etc/mail/spamassassin/local.cf echo "rewrite_header Subject ***SPAM***" >> /etc/mail/spamassassin/local.cf cp /tmp/spamassassin/rules.cf /etc/spamassassin/ + +echo "Configuring fail2ban" +# enable filters +perl -i -0pe 's/(\[postfix\]\n\n).*\n/\1enabled = true\n/' /etc/fail2ban/jail.conf +perl -i -0pe 's/(\[couriersmtp\]\n\n).*\n/\1enabled = true\n/' /etc/fail2ban/jail.conf +perl -i -0pe 's/(\[courierauth\]\n\n).*\n/\1enabled = true\n/' /etc/fail2ban/jail.conf +perl -i -0pe 's/(\[sasl\]\n\n).*\n/\1enabled = true\n/' /etc/fail2ban/jail.conf + +# increase ban time and find time to 3h +sed -i "/^bantime *=/c\bantime = 10800" /etc/fail2ban/jail.conf +sed -i "/^findtime *=/c\findtime = 10800" /etc/fail2ban/jail.conf + +# avoid warning on startup +echo "ignoreregex =" >> /etc/fail2ban/filter.d/postfix-sasl.conf + + echo "Starting daemons" cron /etc/init.d/rsyslog start @@ -208,6 +224,7 @@ fi /etc/init.d/opendkim start /etc/init.d/opendmarc start /etc/init.d/postfix start +/etc/init.d/fail2ban start echo "Listing SASL users" sasldblistusers2 From 25b09928a3ce320351602730430915fda81af42a Mon Sep 17 00:00:00 2001 From: Dominik Winter Date: Sat, 13 Feb 2016 01:40:36 +0100 Subject: [PATCH 124/155] add NET_ADMIN container capabilities instead of all privileges --- docker-compose.yml.dist | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docker-compose.yml.dist b/docker-compose.yml.dist index 15e07908..752794dc 100644 --- a/docker-compose.yml.dist +++ b/docker-compose.yml.dist @@ -2,7 +2,8 @@ mail: image: tvial/docker-mailserver hostname: mail domainname: domain.com - privileged: true + cap_add: + - NET_ADMIN ports: - "25:25" - "143:143" From 5d157dcecaff591a99cce9fc623112b77ddafcea Mon Sep 17 00:00:00 2001 From: Dominik Winter Date: Sat, 13 Feb 2016 04:43:57 +0100 Subject: [PATCH 125/155] added fail2ban tests --- test/auth/smtp-auth-login-wrong.txt | 4 ++++ test/test.sh | 35 +++++++++++++++++++++-------- 2 files changed, 30 insertions(+), 9 deletions(-) create mode 100644 test/auth/smtp-auth-login-wrong.txt diff --git a/test/auth/smtp-auth-login-wrong.txt b/test/auth/smtp-auth-login-wrong.txt new file mode 100644 index 00000000..39b4f01c --- /dev/null +++ b/test/auth/smtp-auth-login-wrong.txt @@ -0,0 +1,4 @@ +EHLO mail +AUTH LOGIN dXNlcjFAbG9jYWxob3N0LmxvY2FsZG9tYWlu +Bn3JKisq4HQ2RO== +QUIT diff --git a/test/test.sh b/test/test.sh index 107e0dcd..e7be5319 100644 --- a/test/test.sh +++ b/test/test.sh @@ -4,16 +4,17 @@ source assert.sh # Testing that services are running and pop3 is disabled -assert_raises "docker exec mail ps aux --forest | grep '/usr/lib/postfix/master'" 0 -assert_raises "docker exec mail ps aux --forest | grep '/usr/sbin/saslauthd'" 0 -assert_raises "docker exec mail ps aux --forest | grep '/usr/sbin/clamd'" 0 -assert_raises "docker exec mail ps aux --forest | grep '/usr/sbin/amavisd-new'" 0 -assert_raises "docker exec mail ps aux --forest | grep '/usr/sbin/opendkim'" 0 -assert_raises "docker exec mail ps aux --forest | grep '/usr/sbin/opendmarc'" 0 -assert_raises "docker exec mail ps aux --forest | grep '/usr/lib/courier/courier/courierpop3d'" 1 +assert_raises "docker exec mail ps aux --forest | grep -v grep | grep '/usr/lib/postfix/master'" 0 +assert_raises "docker exec mail ps aux --forest | grep -v grep | grep '/usr/sbin/saslauthd'" 0 +assert_raises "docker exec mail ps aux --forest | grep -v grep | grep '/usr/sbin/clamd'" 0 +assert_raises "docker exec mail ps aux --forest | grep -v grep | grep '/usr/sbin/amavisd-new'" 0 +assert_raises "docker exec mail ps aux --forest | grep -v grep | grep '/usr/sbin/opendkim'" 0 +assert_raises "docker exec mail ps aux --forest | grep -v grep | grep '/usr/sbin/opendmarc'" 0 +assert_raises "docker exec mail ps aux --forest | grep -v grep | grep '/usr/lib/courier/courier/courierpop3d'" 1 +assert_raises "docker exec mail ps aux --forest | grep -v grep | grep '/usr/bin/python /usr/bin/fail2ban-server'" 0 # Testing services of pop3 container -assert_raises "docker exec mail_pop3 ps aux --forest | grep '/usr/lib/courier/courier/courierpop3d'" 0 +assert_raises "docker exec mail_pop3 ps aux --forest | grep -v grep | grep '/usr/lib/courier/courier/courierpop3d'" 0 # Testing IMAP server assert_raises "docker exec mail nc -w 1 0.0.0.0 143 | grep '* OK' | grep 'STARTTLS' | grep 'Courier-IMAP ready'" 0 @@ -85,5 +86,21 @@ assert_raises "docker exec mail grep 'BEGIN CERTIFICATE' /etc/ssl/certs/lets-enc # Testing generated ssl certs assert_raises "docker exec mail openssl s_client -connect 0.0.0.0:587 -starttls smtp -CApath /etc/ssl/certs/ | grep 'Verify return code: 0 (ok)'" "0" +# Testing fail2ban +assert_raises "docker exec mail fail2ban-client status sasl | grep 'IP list:\s*127.0.0.1'" 1 + +docker exec mail fail2ban-client set sasl delignoreip 127.0.0.1/8 &> /dev/null + +docker exec mail /bin/sh -c 'nc -w 1 0.0.0.0 25 < /tmp/test/auth/smtp-auth-login-wrong.txt' &> /dev/null +docker exec mail /bin/sh -c 'nc -w 1 0.0.0.0 25 < /tmp/test/auth/smtp-auth-login-wrong.txt' &> /dev/null +docker exec mail /bin/sh -c 'nc -w 1 0.0.0.0 25 < /tmp/test/auth/smtp-auth-login-wrong.txt' &> /dev/null + +assert_raises "docker exec mail fail2ban-client status sasl | grep 'IP list:\s*127.0.0.1'" 0 + +docker exec mail fail2ban-client set sasl addignoreip 127.0.0.1/8 &> /dev/null +docker exec mail fail2ban-client set sasl unbanip 127.0.0.1 &> /dev/null + +assert_raises "docker exec mail fail2ban-client status sasl | grep 'IP list:\s*127.0.0.1'" 1 + # Ending tests -assert_end +assert_end From b54bce7b7762f014e5a819d053120e5bdb6612c6 Mon Sep 17 00:00:00 2001 From: Dominik Winter Date: Sat, 13 Feb 2016 05:37:06 +0100 Subject: [PATCH 126/155] fixed timing problem for fail2ban test --- test/test.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/test.sh b/test/test.sh index e7be5319..d855fc00 100644 --- a/test/test.sh +++ b/test/test.sh @@ -95,11 +95,13 @@ docker exec mail /bin/sh -c 'nc -w 1 0.0.0.0 25 < /tmp/test/auth/smtp-auth-login docker exec mail /bin/sh -c 'nc -w 1 0.0.0.0 25 < /tmp/test/auth/smtp-auth-login-wrong.txt' &> /dev/null docker exec mail /bin/sh -c 'nc -w 1 0.0.0.0 25 < /tmp/test/auth/smtp-auth-login-wrong.txt' &> /dev/null +sleep 10 assert_raises "docker exec mail fail2ban-client status sasl | grep 'IP list:\s*127.0.0.1'" 0 docker exec mail fail2ban-client set sasl addignoreip 127.0.0.1/8 &> /dev/null docker exec mail fail2ban-client set sasl unbanip 127.0.0.1 &> /dev/null +sleep 10 assert_raises "docker exec mail fail2ban-client status sasl | grep 'IP list:\s*127.0.0.1'" 1 # Ending tests From f77e2e9ffa4b2ccfcfc27086dc8e7ec70177ca12 Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Sat, 13 Feb 2016 12:20:15 +0100 Subject: [PATCH 127/155] Added fail2ban to features list --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 86811707..5d8b767d 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,7 @@ Includes: - clamav with automatic updates - opendkim - opendmarc +- fail2ban - [LetsEncrypt](https://letsencrypt.org/) and self-signed certificates - optional pop3 server - [integration tests](https://travis-ci.org/tomav/docker-mailserver) From 24e3b1286ec7e83d5deb9c72747ec4ba7a52ed50 Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Wed, 17 Feb 2016 22:51:57 +0100 Subject: [PATCH 128/155] Fixes #79 and spamassassin default configuration --- start-mailserver.sh | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/start-mailserver.sh b/start-mailserver.sh index f52cd5cb..359ef8b5 100644 --- a/start-mailserver.sh +++ b/start-mailserver.sh @@ -182,10 +182,9 @@ echo "Creating /etc/mailname" echo $(hostname -d) > /etc/mailname echo "Configuring Spamassassin" -echo "required_hits 5.0" >> /etc/mail/spamassassin/local.cf -echo "report_safe 0" >> /etc/mail/spamassassin/local.cf -echo "required_score 5" >> /etc/mail/spamassassin/local.cf -echo "rewrite_header Subject ***SPAM***" >> /etc/mail/spamassassin/local.cf +echo "required_score 5" >> /etc/spamassassin/local.cf +echo "report_safe 0" >> /etc/spamassassin/local.cf +echo "rewrite_header Subject ***SPAM***" >> /etc/spamassassin/local.cf cp /tmp/spamassassin/rules.cf /etc/spamassassin/ From 59a6649f0e297f4113a4fa9e03f917aa71c146c6 Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Thu, 18 Feb 2016 22:11:24 +0100 Subject: [PATCH 129/155] Fixes #79 and add spamassassin configuration variables (see README.md) --- Makefile | 19 +++++++++++++++---- README.md | 6 ++++++ start-mailserver.sh | 7 +++---- test/test.sh | 8 ++++++++ 4 files changed, 32 insertions(+), 8 deletions(-) diff --git a/Makefile b/Makefile index f96bc3c9..c83e9fad 100644 --- a/Makefile +++ b/Makefile @@ -1,19 +1,30 @@ NAME = tvial/docker-mailserver -VERSION = $(TRAVIS_BUILD_ID) all: build run fixtures tests clean all-no-build: run fixtures tests clean build: - docker build --no-cache -t $(NAME):$(VERSION) . + docker build --no-cache -t $(NAME) . run: # Copy test files cp test/accounts.cf postfix/ cp test/virtual postfix/ # Run containers - docker run -d --name mail -v "`pwd`/postfix":/tmp/postfix -v "`pwd`/spamassassin":/tmp/spamassassin -v "`pwd`/test":/tmp/test -h mail.my-domain.com -t $(NAME):$(VERSION) - docker run -d --name mail_pop3 -v "`pwd`/postfix":/tmp/postfix -v "`pwd`/spamassassin":/tmp/spamassassin -v "`pwd`/test":/tmp/test -e ENABLE_POP3=1 -h mail.my-domain.com -t $(NAME):$(VERSION) + docker run -d --name mail \ + -v "`pwd`/postfix":/tmp/postfix \ + -v "`pwd`/spamassassin":/tmp/spamassassin \ + -v "`pwd`/test":/tmp/test \ + -e SA_TAG=1.0 \ + -e SA_TAG2=2.0 \ + -e SA_KILL=3.0 \ + -h mail.my-domain.com -t $(NAME) + docker run -d --name mail_pop3 \ + -v "`pwd`/postfix":/tmp/postfix \ + -v "`pwd`/spamassassin":/tmp/spamassassin \ + -v "`pwd`/test":/tmp/test \ + -e ENABLE_POP3=1 \ + -h mail.my-domain.com -t $(NAME) # Wait for containers to fully start sleep 60 diff --git a/README.md b/README.md index 5d8b767d..66337e5a 100644 --- a/README.md +++ b/README.md @@ -88,6 +88,12 @@ Example: * ENABLE_POP3 * *empty* (default) => POP3 service disabled * 1 => Enables POP3 service +* SA_TAG + * *2.0* (default) => add spam info headers if at, or above that level +* SA_TAG2 + * *6.31* (default) => add 'spam detected' headers at that level +* SA_KILL + * *6.31* (default) => triggers spam evasive actions) Please read [how the container starts](https://github.com/tomav/docker-mailserver/blob/master/start-mailserver.sh) to understand what's expected. diff --git a/start-mailserver.sh b/start-mailserver.sh index 359ef8b5..2e640822 100644 --- a/start-mailserver.sh +++ b/start-mailserver.sh @@ -182,12 +182,11 @@ echo "Creating /etc/mailname" echo $(hostname -d) > /etc/mailname echo "Configuring Spamassassin" -echo "required_score 5" >> /etc/spamassassin/local.cf -echo "report_safe 0" >> /etc/spamassassin/local.cf -echo "rewrite_header Subject ***SPAM***" >> /etc/spamassassin/local.cf +SA_TAG=${SA_TAG:="2.0"} && sed -i -r 's/^\$sa_tag_level_deflt (.*);/\$sa_tag_level_deflt = '$SA_TAG';/g' /etc/amavis/conf.d/20-debian_defaults +SA_TAG2=${SA_TAG2:="6.31"} && sed -i -r 's/^\$sa_tag2_level_deflt (.*);/\$sa_tag2_level_deflt = '$SA_TAG2';/g' /etc/amavis/conf.d/20-debian_defaults +SA_KILL=${SA_KILL:="6.31"} && sed -i -r 's/^\$sa_kill_level_deflt (.*);/\$sa_kill_level_deflt = '$SA_KILL';/g' /etc/amavis/conf.d/20-debian_defaults cp /tmp/spamassassin/rules.cf /etc/spamassassin/ - echo "Configuring fail2ban" # enable filters perl -i -0pe 's/(\[postfix\]\n\n).*\n/\1enabled = true\n/' /etc/fail2ban/jail.conf diff --git a/test/test.sh b/test/test.sh index d855fc00..b6530b9d 100644 --- a/test/test.sh +++ b/test/test.sh @@ -68,6 +68,14 @@ assert_raises "docker exec mail grep ': error:' /var/log/mail.log" 1 assert_raises "docker exec mail_pop3 grep 'non-null host address bits in' /var/log/mail.log" 1 assert_raises "docker exec mail_pop3 grep ': error:' /var/log/mail.log" 1 +# Testing Spamssassin config in Amavis +assert_raises "docker exec mail_pop3 grep '\$sa_tag_level_deflt' /etc/amavis/conf.d/20-debian_defaults | grep '= 2.0'" 0 +assert_raises "docker exec mail_pop3 grep '\$sa_tag2_level_deflt' /etc/amavis/conf.d/20-debian_defaults | grep '= 6.31'" 0 +assert_raises "docker exec mail_pop3 grep '\$sa_kill_level_deflt' /etc/amavis/conf.d/20-debian_defaults | grep '= 6.31'" 0 +assert_raises "docker exec mail grep '\$sa_tag_level_deflt' /etc/amavis/conf.d/20-debian_defaults | grep '= 1.0'" 0 +assert_raises "docker exec mail grep '\$sa_tag2_level_deflt' /etc/amavis/conf.d/20-debian_defaults | grep '= 2.0'" 0 +assert_raises "docker exec mail grep '\$sa_kill_level_deflt' /etc/amavis/conf.d/20-debian_defaults | grep '= 3.0'" 0 + # Testing OpenDKIM assert "docker exec mail cat /etc/opendkim/KeyTable | wc -l" "2" assert "docker exec mail ls -l /etc/opendkim/keys/ | grep '^d' | wc -l" "2" From 842d54e05179bdb68d0b9d45bfe8717ac6301c57 Mon Sep 17 00:00:00 2001 From: Damien Espitallier Date: Thu, 18 Feb 2016 22:16:50 +0100 Subject: [PATCH 130/155] fix pop3 certificate path --- start-mailserver.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/start-mailserver.sh b/start-mailserver.sh index f52cd5cb..64235540 100644 --- a/start-mailserver.sh +++ b/start-mailserver.sh @@ -131,9 +131,9 @@ case $DMS_SSL in # POP3 courier configuration sed -i -r 's/POP3_TLS_REQUIRED=0/POP3_TLS_REQUIRED=1/g' /etc/courier/pop3d-ssl - sed -i -r 's/TLS_CERTFILE=\/etc\/courier\/pop3d.pem/TLS_CERTFILE=\/etc\/letsencrypt\/live\/'$(hostname)'-combined.pem/g' /etc/courier/pop3d-ssl + sed -i -r 's/TLS_CERTFILE=\/etc\/courier\/pop3d.pem/TLS_CERTFILE=\/etc\/letsencrypt\/live\/'$(hostname)'\/combined.pem/g' /etc/courier/pop3d-ssl # needed to support gmail - sed -i -r 's/TLS_TRUSTCERTS=\/etc\/ssl\/certs/TLS_TRUSTCERTS=\/etc\/letsencrypt\/live\/'$(hostname)'-fullchain.pem/g' /etc/courier/pop3d-ssl + sed -i -r 's/TLS_TRUSTCERTS=\/etc\/ssl\/certs/TLS_TRUSTCERTS=\/etc\/letsencrypt\/live\/'$(hostname)'\/fullchain.pem/g' /etc/courier/pop3d-ssl echo "SSL configured with letsencrypt certificates" From 0f1695cbb265417691ff6181591cee19ee8b23a2 Mon Sep 17 00:00:00 2001 From: Robert Dolca Date: Sat, 20 Feb 2016 02:14:04 +0000 Subject: [PATCH 131/155] Set smtp_tls_security_level for smtp-amavis in master.cf This way you can set smtp_tls_security_level = encrypt in main.cf and amavis would still work. --- postfix/master.cf | 2 ++ 1 file changed, 2 insertions(+) diff --git a/postfix/master.cf b/postfix/master.cf index 8804f632..b2fe0de9 100644 --- a/postfix/master.cf +++ b/postfix/master.cf @@ -72,6 +72,7 @@ smtp-amavis unix - - - - 2 smtp -o smtp_send_xforward_command=yes -o disable_dns_lookups=yes -o max_use=20 + -o smtp_tls_security_level=none 127.0.0.1:10025 inet n - n - - smtpd -o content_filter= @@ -92,3 +93,4 @@ smtp-amavis unix - - - - 2 smtp -o smtpd_client_connection_count_limit=0 -o smtpd_client_connection_rate_limit=0 -o receive_override_options=no_header_body_checks,no_unknown_recipient_checks + -o smtp_tls_security_level=none From 2ff42baf41378f6c410b13fb6db6ddf07266f443 Mon Sep 17 00:00:00 2001 From: Robert Dolca Date: Sat, 20 Feb 2016 02:15:17 +0000 Subject: [PATCH 132/155] Remove duplicate DKIM headers --- postfix/opendkim.conf | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/postfix/opendkim.conf b/postfix/opendkim.conf index 05c9d340..f8c1b6c3 100644 --- a/postfix/opendkim.conf +++ b/postfix/opendkim.conf @@ -4,6 +4,7 @@ UMask 002 Syslog yes SyslogSuccess Yes LogWhy Yes +RemoveOldSignatures Yes Canonicalization relaxed/simple @@ -18,4 +19,4 @@ SignatureAlgorithm rsa-sha256 UserID opendkim:opendkim -Socket inet:12301@localhost \ No newline at end of file +Socket inet:12301@localhost From 0e2ef0f8c296f84f1fe6890286986b2d9139a213 Mon Sep 17 00:00:00 2001 From: Robert Dolca Date: Sat, 20 Feb 2016 02:16:54 +0000 Subject: [PATCH 133/155] Allow custom main.cf settings --- start-mailserver.sh | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/start-mailserver.sh b/start-mailserver.sh index bcabaa72..8756643a 100644 --- a/start-mailserver.sh +++ b/start-mailserver.sh @@ -173,6 +173,15 @@ case $DMS_SSL in esac +if [ -f /tmp/postfix/main.cf ]; then + while read line; do + postconf -e "$line" + done < /tmp/postfix/main.cf + echo "Loaded '/tmp/postfix/main.cf'" +else + echo "==> Warning: '/tmp/postfix/main.cf' is not provided. No extra postfix settings loaded." +fi + echo "Fixing permissions" chown -R 5000:5000 /var/mail mkdir -p /var/log/clamav && chown -R clamav:root /var/log/clamav From d36ecaa2c0965112d0c7e27d667488c05107aed3 Mon Sep 17 00:00:00 2001 From: Robert Dolca Date: Sat, 20 Feb 2016 02:17:14 +0000 Subject: [PATCH 134/155] Add SASL_PASSWD environment variable to configure relay authentication --- README.md | 3 +++ start-mailserver.sh | 11 +++++++++++ 2 files changed, 14 insertions(+) diff --git a/README.md b/README.md index 66337e5a..a34efd12 100644 --- a/README.md +++ b/README.md @@ -94,6 +94,9 @@ Example: * *6.31* (default) => add 'spam detected' headers at that level * SA_KILL * *6.31* (default) => triggers spam evasive actions) +* SASL_PASSWORD + * *empty* (default) => No sasl_passwd will be created + * *string* => A /etc/postfix/sasl_passwd will be created with that content and postmap will be run on it Please read [how the container starts](https://github.com/tomav/docker-mailserver/blob/master/start-mailserver.sh) to understand what's expected. diff --git a/start-mailserver.sh b/start-mailserver.sh index 8756643a..1af17c30 100644 --- a/start-mailserver.sh +++ b/start-mailserver.sh @@ -182,6 +182,17 @@ else echo "==> Warning: '/tmp/postfix/main.cf' is not provided. No extra postfix settings loaded." fi +if [ ! -z "$SASL_PASSWD" ]; then + echo "$SASL_PASSWD" > /etc/postfix/sasl_passwd + postmap hash:/etc/postfix/sasl_passwd + rm /etc/postfix/sasl_passwd + chown root:root /etc/postfix/sasl_passwd.db + chmod 0600 /etc/postfix/sasl_passwd.db + echo "Loaded SASL_PASSWORD" +else + echo "==> Warning: 'SASL_PASSWORD' is not provided. /etc/postfix/sasl_passwd not created." +fi + echo "Fixing permissions" chown -R 5000:5000 /var/mail mkdir -p /var/log/clamav && chown -R clamav:root /var/log/clamav From 91554372e52241ccaabac36c539c6ac38c9e2661 Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Thu, 25 Feb 2016 00:11:18 +0100 Subject: [PATCH 135/155] Removed assert.sh and tests --- assert.sh | 186 --------------------------------------------------- test/test.sh | 116 -------------------------------- 2 files changed, 302 deletions(-) delete mode 100644 assert.sh delete mode 100644 test/test.sh diff --git a/assert.sh b/assert.sh deleted file mode 100644 index ffd2b955..00000000 --- a/assert.sh +++ /dev/null @@ -1,186 +0,0 @@ -#!/bin/bash -# assert.sh 1.1 - bash unit testing framework -# Copyright (C) 2009-2015 Robert Lehmann -# -# http://github.com/lehmannro/assert.sh -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser General Public License as published -# by the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public License -# along with this program. If not, see . - -export DISCOVERONLY=${DISCOVERONLY:-} -export DEBUG=${DEBUG:-} -export STOP=${STOP:-} -export INVARIANT=${INVARIANT:-} -export CONTINUE=${CONTINUE:-} - -args="$(getopt -n "$0" -l \ - verbose,help,stop,discover,invariant,continue vhxdic $*)" \ -|| exit -1 -for arg in $args; do - case "$arg" in - -h) - echo "$0 [-vxidc]" \ - "[--verbose] [--stop] [--invariant] [--discover] [--continue]" - echo "`sed 's/./ /g' <<< "$0"` [-h] [--help]" - exit 0;; - --help) - cat < [stdin] - (( tests_ran++ )) || : - [[ -z "$DISCOVERONLY" ]] || return - expected=$(echo -ne "${2:-}") - result="$(eval 2>/dev/null $1 <<< ${3:-})" || true - if [[ "$result" == "$expected" ]]; then - [[ -z "$DEBUG" ]] || echo -n . - return - fi - result="$(sed -e :a -e '$!N;s/\n/\\n/;ta' <<< "$result")" - [[ -z "$result" ]] && result="nothing" || result="\"$result\"" - [[ -z "$2" ]] && expected="nothing" || expected="\"$2\"" - _assert_fail "expected $expected${_indent}got $result" "$1" "$3" -} - -assert_raises() { - # assert_raises [stdin] - (( tests_ran++ )) || : - [[ -z "$DISCOVERONLY" ]] || return - status=0 - (eval $1 <<< ${3:-}) > /dev/null 2>&1 || status=$? - expected=${2:-0} - if [[ "$status" -eq "$expected" ]]; then - [[ -z "$DEBUG" ]] || echo -n . - return - fi - _assert_fail "program terminated with code $status instead of $expected" "$1" "$3" -} - -_assert_fail() { - # _assert_fail - [[ -n "$DEBUG" ]] && echo -n X - report="test #$tests_ran \"$2${3:+ <<< $3}\" failed:${_indent}$1" - if [[ -n "$STOP" ]]; then - [[ -n "$DEBUG" ]] && echo - echo "$report" - exit 1 - fi - tests_errors[$tests_failed]="$report" - (( tests_failed++ )) || : -} - -skip_if() { - # skip_if - (eval $@) > /dev/null 2>&1 && status=0 || status=$? - [[ "$status" -eq 0 ]] || return - skip -} - -skip() { - # skip (no arguments) - shopt -q extdebug && tests_extdebug=0 || tests_extdebug=1 - shopt -q -o errexit && tests_errexit=0 || tests_errexit=1 - # enable extdebug so returning 1 in a DEBUG trap handler skips next command - shopt -s extdebug - # disable errexit (set -e) so we can safely return 1 without causing exit - set +o errexit - tests_trapped=0 - trap _skip DEBUG -} -_skip() { - if [[ $tests_trapped -eq 0 ]]; then - # DEBUG trap for command we want to skip. Do not remove the handler - # yet because *after* the command we need to reset extdebug/errexit (in - # another DEBUG trap.) - tests_trapped=1 - [[ -z "$DEBUG" ]] || echo -n s - return 1 - else - trap - DEBUG - [[ $tests_extdebug -eq 0 ]] || shopt -u extdebug - [[ $tests_errexit -eq 1 ]] || set -o errexit - return 0 - fi -} - - -_assert_reset -: ${tests_suite_status:=0} # remember if any of the tests failed so far -_assert_cleanup() { - local status=$? - # modify exit code if it's not already non-zero - [[ $status -eq 0 && -z $CONTINUE ]] && exit $tests_suite_status -} -trap _assert_cleanup EXIT diff --git a/test/test.sh b/test/test.sh deleted file mode 100644 index b6530b9d..00000000 --- a/test/test.sh +++ /dev/null @@ -1,116 +0,0 @@ -#!/bin/bash - -# Set up test framework -source assert.sh - -# Testing that services are running and pop3 is disabled -assert_raises "docker exec mail ps aux --forest | grep -v grep | grep '/usr/lib/postfix/master'" 0 -assert_raises "docker exec mail ps aux --forest | grep -v grep | grep '/usr/sbin/saslauthd'" 0 -assert_raises "docker exec mail ps aux --forest | grep -v grep | grep '/usr/sbin/clamd'" 0 -assert_raises "docker exec mail ps aux --forest | grep -v grep | grep '/usr/sbin/amavisd-new'" 0 -assert_raises "docker exec mail ps aux --forest | grep -v grep | grep '/usr/sbin/opendkim'" 0 -assert_raises "docker exec mail ps aux --forest | grep -v grep | grep '/usr/sbin/opendmarc'" 0 -assert_raises "docker exec mail ps aux --forest | grep -v grep | grep '/usr/lib/courier/courier/courierpop3d'" 1 -assert_raises "docker exec mail ps aux --forest | grep -v grep | grep '/usr/bin/python /usr/bin/fail2ban-server'" 0 - -# Testing services of pop3 container -assert_raises "docker exec mail_pop3 ps aux --forest | grep -v grep | grep '/usr/lib/courier/courier/courierpop3d'" 0 - -# Testing IMAP server -assert_raises "docker exec mail nc -w 1 0.0.0.0 143 | grep '* OK' | grep 'STARTTLS' | grep 'Courier-IMAP ready'" 0 -assert_raises "docker exec mail /bin/sh -c 'nc -w 1 0.0.0.0 143 < /tmp/test/auth/imap-auth.txt'" 0 - -# Testing POP3 server on pop3 container -assert_raises "docker exec mail_pop3 nc -w 1 0.0.0.0 110 | grep '+OK'" 0 -assert_raises "docker exec mail_pop3 /bin/sh -c 'nc -w 1 0.0.0.0 110 < /tmp/test/auth/pop3-auth.txt'" 0 - -# Testing SASL -assert_raises "docker exec mail testsaslauthd -u user2 -r otherdomain.tld -p mypassword | grep 'OK \"Success.\"'" 0 -assert_raises "docker exec mail testsaslauthd -u user2 -r otherdomain.tld -p BADPASSWORD | grep 'NO \"authentication failed\"'" 0 -assert_raises "docker exec mail /bin/sh -c 'nc -w 1 0.0.0.0 25 < /tmp/test/auth/smtp-auth-plain.txt' | grep 'Authentication successful'" -assert_raises "docker exec mail /bin/sh -c 'nc -w 1 0.0.0.0 25 < /tmp/test/auth/smtp-auth-login.txt' | grep 'Authentication successful'" - -# Testing user creation -assert "docker exec mail sasldblistusers2" "user1@localhost.localdomain: userPassword\nuser2@otherdomain.tld: userPassword" -assert "docker exec mail ls -A /var/mail/localhost.localdomain/user1" ".Drafts\n.Sent\n.Trash\ncourierimapsubscribed\ncur\nnew\ntmp" -assert "docker exec mail ls -A /var/mail/otherdomain.tld/user2" ".Drafts\n.Sent\n.Trash\ncourierimapsubscribed\ncur\nnew\ntmp" - -# Testing `vhost` creation -assert "docker exec mail cat /etc/postfix/vhost" "localhost.localdomain\notherdomain.tld" - -# Testing that mail is received for existing user -assert_raises "docker exec mail grep 'status=sent (delivered to maildir)' /var/log/mail.log" 0 -assert "docker exec mail ls -A /var/mail/localhost.localdomain/user1/new | wc -l" "2" - -# Testing that mail is rejected for non existing user -assert_raises "docker exec mail grep ': Recipient address rejected: User unknown in virtual mailbox table' /var/log/mail.log" 0 - -# Testing that mail is received for existing alias -assert_raises "docker exec mail grep 'to=, orig_to=' /var/log/mail.log | grep 'status=sent'" 0 - -# Testing that mail is redirected for external alias -assert_raises "docker exec mail grep -- '-> ' /var/log/mail.log" 0 - -# Testing that a SPAM is rejected -assert_raises "docker exec mail grep 'Blocked SPAM' /var/log/mail.log | grep spam@external.tld" 0 - -# Testing that a Virus is rejected -assert_raises "docker exec mail grep 'Blocked INFECTED' /var/log/mail.log | grep virus@external.tld" 0 - -# Testing presence of freshclam CRON -assert "docker exec mail crontab -l" "0 1 * * * /usr/bin/freshclam --quiet" - -# Testing that log don't display errors -assert_raises "docker exec mail grep 'non-null host address bits in' /var/log/mail.log" 1 -assert_raises "docker exec mail grep ': error:' /var/log/mail.log" 1 - -# Testing that pop3 container log don't display errors -assert_raises "docker exec mail_pop3 grep 'non-null host address bits in' /var/log/mail.log" 1 -assert_raises "docker exec mail_pop3 grep ': error:' /var/log/mail.log" 1 - -# Testing Spamssassin config in Amavis -assert_raises "docker exec mail_pop3 grep '\$sa_tag_level_deflt' /etc/amavis/conf.d/20-debian_defaults | grep '= 2.0'" 0 -assert_raises "docker exec mail_pop3 grep '\$sa_tag2_level_deflt' /etc/amavis/conf.d/20-debian_defaults | grep '= 6.31'" 0 -assert_raises "docker exec mail_pop3 grep '\$sa_kill_level_deflt' /etc/amavis/conf.d/20-debian_defaults | grep '= 6.31'" 0 -assert_raises "docker exec mail grep '\$sa_tag_level_deflt' /etc/amavis/conf.d/20-debian_defaults | grep '= 1.0'" 0 -assert_raises "docker exec mail grep '\$sa_tag2_level_deflt' /etc/amavis/conf.d/20-debian_defaults | grep '= 2.0'" 0 -assert_raises "docker exec mail grep '\$sa_kill_level_deflt' /etc/amavis/conf.d/20-debian_defaults | grep '= 3.0'" 0 - -# Testing OpenDKIM -assert "docker exec mail cat /etc/opendkim/KeyTable | wc -l" "2" -assert "docker exec mail ls -l /etc/opendkim/keys/ | grep '^d' | wc -l" "2" - -# Testing OpenDMARC -assert "docker exec mail cat /etc/opendmarc.conf | grep ^AuthservID | wc -l" "1" -assert "docker exec mail cat /etc/opendmarc.conf | grep ^TrustedAuthservID | wc -l" "1" - -# Testing hostname config -assert "docker exec mail cat /etc/mailname" "my-domain.com" - -# Testing presence of LetsEncrypt signed certs -assert_raises "docker exec mail grep 'BEGIN CERTIFICATE' /etc/ssl/certs/lets-encrypt-x1-cross-signed.pem" "0" -assert_raises "docker exec mail grep 'BEGIN CERTIFICATE' /etc/ssl/certs/lets-encrypt-x2-cross-signed.pem" "0" - -# Testing generated ssl certs -assert_raises "docker exec mail openssl s_client -connect 0.0.0.0:587 -starttls smtp -CApath /etc/ssl/certs/ | grep 'Verify return code: 0 (ok)'" "0" - -# Testing fail2ban -assert_raises "docker exec mail fail2ban-client status sasl | grep 'IP list:\s*127.0.0.1'" 1 - -docker exec mail fail2ban-client set sasl delignoreip 127.0.0.1/8 &> /dev/null - -docker exec mail /bin/sh -c 'nc -w 1 0.0.0.0 25 < /tmp/test/auth/smtp-auth-login-wrong.txt' &> /dev/null -docker exec mail /bin/sh -c 'nc -w 1 0.0.0.0 25 < /tmp/test/auth/smtp-auth-login-wrong.txt' &> /dev/null -docker exec mail /bin/sh -c 'nc -w 1 0.0.0.0 25 < /tmp/test/auth/smtp-auth-login-wrong.txt' &> /dev/null - -sleep 10 -assert_raises "docker exec mail fail2ban-client status sasl | grep 'IP list:\s*127.0.0.1'" 0 - -docker exec mail fail2ban-client set sasl addignoreip 127.0.0.1/8 &> /dev/null -docker exec mail fail2ban-client set sasl unbanip 127.0.0.1 &> /dev/null - -sleep 10 -assert_raises "docker exec mail fail2ban-client status sasl | grep 'IP list:\s*127.0.0.1'" 1 - -# Ending tests -assert_end From 22b79b82f846b144afa4e2e8257ea04fa4cedd33 Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Thu, 25 Feb 2016 00:11:48 +0100 Subject: [PATCH 136/155] Moved from assert.sh to bats --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index c83e9fad..01d7ffd6 100644 --- a/Makefile +++ b/Makefile @@ -41,7 +41,7 @@ fixtures: tests: # Start tests - /bin/bash ./test/test.sh + ./test/bats/bats test/tests.bats clean: # Get default files back From 890b70a133f7c17b427bb814a5e68ef51953da7b Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Thu, 25 Feb 2016 00:17:01 +0100 Subject: [PATCH 137/155] Fixes 84 => moved to bats unit test framework --- test/auth/smtp-auth-plain-wrong.txt | 3 + test/bats/bats | 142 ++++++++++++ test/bats/bats-exec-suite | 55 +++++ test/bats/bats-exec-test | 346 ++++++++++++++++++++++++++++ test/bats/bats-format-tap-stream | 165 +++++++++++++ test/bats/bats-preprocess | 52 +++++ test/tests.bats | 340 +++++++++++++++++++++++++++ 7 files changed, 1103 insertions(+) create mode 100644 test/auth/smtp-auth-plain-wrong.txt create mode 100755 test/bats/bats create mode 100755 test/bats/bats-exec-suite create mode 100755 test/bats/bats-exec-test create mode 100755 test/bats/bats-format-tap-stream create mode 100755 test/bats/bats-preprocess create mode 100644 test/tests.bats diff --git a/test/auth/smtp-auth-plain-wrong.txt b/test/auth/smtp-auth-plain-wrong.txt new file mode 100644 index 00000000..d8d8ad2a --- /dev/null +++ b/test/auth/smtp-auth-plain-wrong.txt @@ -0,0 +1,3 @@ +EHLO mail +AUTH PLAIN WRONGPASSWORD +QUIT diff --git a/test/bats/bats b/test/bats/bats new file mode 100755 index 00000000..7e1c9eda --- /dev/null +++ b/test/bats/bats @@ -0,0 +1,142 @@ +#!/usr/bin/env bash +set -e + +version() { + echo "Bats 0.4.0" +} + +usage() { + version + echo "Usage: bats [-c] [-p | -t] [ ...]" +} + +help() { + usage + echo + echo " is the path to a Bats test file, or the path to a directory" + echo " containing Bats test files." + echo + echo " -c, --count Count the number of test cases without running any tests" + echo " -h, --help Display this help message" + echo " -p, --pretty Show results in pretty format (default for terminals)" + echo " -t, --tap Show results in TAP format" + echo " -v, --version Display the version number" + echo + echo " For more information, see https://github.com/sstephenson/bats" + echo +} + +resolve_link() { + $(type -p greadlink readlink | head -1) "$1" +} + +abs_dirname() { + local cwd="$(pwd)" + local path="$1" + + while [ -n "$path" ]; do + cd "${path%/*}" + local name="${path##*/}" + path="$(resolve_link "$name" || true)" + done + + pwd + cd "$cwd" +} + +expand_path() { + { cd "$(dirname "$1")" 2>/dev/null + local dirname="$PWD" + cd "$OLDPWD" + echo "$dirname/$(basename "$1")" + } || echo "$1" +} + +BATS_LIBEXEC="$(abs_dirname "$0")" +export BATS_PREFIX="$(abs_dirname "$BATS_LIBEXEC")" +export BATS_CWD="$(abs_dirname .)" +export PATH="$BATS_LIBEXEC:$PATH" + +options=() +arguments=() +for arg in "$@"; do + if [ "${arg:0:1}" = "-" ]; then + if [ "${arg:1:1}" = "-" ]; then + options[${#options[*]}]="${arg:2}" + else + index=1 + while option="${arg:$index:1}"; do + [ -n "$option" ] || break + options[${#options[*]}]="$option" + let index+=1 + done + fi + else + arguments[${#arguments[*]}]="$arg" + fi +done + +unset count_flag pretty +[ -t 0 ] && [ -t 1 ] && pretty="1" +[ -n "$CI" ] && pretty="" + +for option in "${options[@]}"; do + case "$option" in + "h" | "help" ) + help + exit 0 + ;; + "v" | "version" ) + version + exit 0 + ;; + "c" | "count" ) + count_flag="-c" + ;; + "t" | "tap" ) + pretty="" + ;; + "p" | "pretty" ) + pretty="1" + ;; + * ) + usage >&2 + exit 1 + ;; + esac +done + +if [ "${#arguments[@]}" -eq 0 ]; then + usage >&2 + exit 1 +fi + +filenames=() +for filename in "${arguments[@]}"; do + if [ -d "$filename" ]; then + shopt -s nullglob + for suite_filename in "$(expand_path "$filename")"/*.bats; do + filenames["${#filenames[@]}"]="$suite_filename" + done + shopt -u nullglob + else + filenames["${#filenames[@]}"]="$(expand_path "$filename")" + fi +done + +if [ "${#filenames[@]}" -eq 1 ]; then + command="bats-exec-test" +else + command="bats-exec-suite" +fi + +if [ -n "$pretty" ]; then + extended_syntax_flag="-x" + formatter="bats-format-tap-stream" +else + extended_syntax_flag="" + formatter="cat" +fi + +set -o pipefail execfail +exec "$command" $count_flag $extended_syntax_flag "${filenames[@]}" | "$formatter" \ No newline at end of file diff --git a/test/bats/bats-exec-suite b/test/bats/bats-exec-suite new file mode 100755 index 00000000..29ab255d --- /dev/null +++ b/test/bats/bats-exec-suite @@ -0,0 +1,55 @@ +#!/usr/bin/env bash +set -e + +count_only_flag="" +if [ "$1" = "-c" ]; then + count_only_flag=1 + shift +fi + +extended_syntax_flag="" +if [ "$1" = "-x" ]; then + extended_syntax_flag="-x" + shift +fi + +trap "kill 0; exit 1" int + +count=0 +for filename in "$@"; do + let count+="$(bats-exec-test -c "$filename")" +done + +if [ -n "$count_only_flag" ]; then + echo "$count" + exit +fi + +echo "1..$count" +status=0 +offset=0 +for filename in "$@"; do + index=0 + { + IFS= read -r # 1..n + while IFS= read -r line; do + case "$line" in + "begin "* ) + let index+=1 + echo "${line/ $index / $(($offset + $index)) }" + ;; + "ok "* | "not ok "* ) + [ -n "$extended_syntax_flag" ] || let index+=1 + echo "${line/ $index / $(($offset + $index)) }" + [ "${line:0:6}" != "not ok" ] || status=1 + ;; + * ) + echo "$line" + ;; + esac + done + } < <( bats-exec-test $extended_syntax_flag "$filename" ) + offset=$(($offset + $index)) +done + +exit "$status" diff --git a/test/bats/bats-exec-test b/test/bats/bats-exec-test new file mode 100755 index 00000000..8f3bd510 --- /dev/null +++ b/test/bats/bats-exec-test @@ -0,0 +1,346 @@ +#!/usr/bin/env bash +set -e +set -E +set -T + +BATS_COUNT_ONLY="" +if [ "$1" = "-c" ]; then + BATS_COUNT_ONLY=1 + shift +fi + +BATS_EXTENDED_SYNTAX="" +if [ "$1" = "-x" ]; then + BATS_EXTENDED_SYNTAX="$1" + shift +fi + +BATS_TEST_FILENAME="$1" +if [ -z "$BATS_TEST_FILENAME" ]; then + echo "usage: bats-exec " >&2 + exit 1 +elif [ ! -f "$BATS_TEST_FILENAME" ]; then + echo "bats: $BATS_TEST_FILENAME does not exist" >&2 + exit 1 +else + shift +fi + +BATS_TEST_DIRNAME="$(dirname "$BATS_TEST_FILENAME")" +BATS_TEST_NAMES=() + +load() { + local name="$1" + local filename + + if [ "${name:0:1}" = "/" ]; then + filename="${name}" + else + filename="$BATS_TEST_DIRNAME/${name}.bash" + fi + + [ -f "$filename" ] || { + echo "bats: $filename does not exist" >&2 + exit 1 + } + + source "${filename}" +} + +run() { + local e E T oldIFS + [[ ! "$-" =~ e ]] || e=1 + [[ ! "$-" =~ E ]] || E=1 + [[ ! "$-" =~ T ]] || T=1 + set +e + set +E + set +T + output="$("$@" 2>&1)" + status="$?" + oldIFS=$IFS + IFS=$'\n' lines=($output) + [ -z "$e" ] || set -e + [ -z "$E" ] || set -E + [ -z "$T" ] || set -T + IFS=$oldIFS +} + +setup() { + true +} + +teardown() { + true +} + +skip() { + BATS_TEST_SKIPPED=${1:-1} + BATS_TEST_COMPLETED=1 + exit 0 +} + +bats_test_begin() { + BATS_TEST_DESCRIPTION="$1" + if [ -n "$BATS_EXTENDED_SYNTAX" ]; then + echo "begin $BATS_TEST_NUMBER $BATS_TEST_DESCRIPTION" >&3 + fi + setup +} + +bats_test_function() { + local test_name="$1" + BATS_TEST_NAMES["${#BATS_TEST_NAMES[@]}"]="$test_name" +} + +bats_capture_stack_trace() { + BATS_PREVIOUS_STACK_TRACE=( "${BATS_CURRENT_STACK_TRACE[@]}" ) + BATS_CURRENT_STACK_TRACE=() + + local test_pattern=" $BATS_TEST_NAME $BATS_TEST_SOURCE" + local setup_pattern=" setup $BATS_TEST_SOURCE" + local teardown_pattern=" teardown $BATS_TEST_SOURCE" + + local frame + local index=1 + + while frame="$(caller "$index")"; do + BATS_CURRENT_STACK_TRACE["${#BATS_CURRENT_STACK_TRACE[@]}"]="$frame" + if [[ "$frame" = *"$test_pattern" || \ + "$frame" = *"$setup_pattern" || \ + "$frame" = *"$teardown_pattern" ]]; then + break + else + let index+=1 + fi + done + + BATS_SOURCE="$(bats_frame_filename "${BATS_CURRENT_STACK_TRACE[0]}")" + BATS_LINENO="$(bats_frame_lineno "${BATS_CURRENT_STACK_TRACE[0]}")" +} + +bats_print_stack_trace() { + local frame + local index=1 + local count="${#@}" + + for frame in "$@"; do + local filename="$(bats_trim_filename "$(bats_frame_filename "$frame")")" + local lineno="$(bats_frame_lineno "$frame")" + + if [ $index -eq 1 ]; then + echo -n "# (" + else + echo -n "# " + fi + + local fn="$(bats_frame_function "$frame")" + if [ "$fn" != "$BATS_TEST_NAME" ]; then + echo -n "from function \`$fn' " + fi + + if [ $index -eq $count ]; then + echo "in test file $filename, line $lineno)" + else + echo "in file $filename, line $lineno," + fi + + let index+=1 + done +} + +bats_print_failed_command() { + local frame="$1" + local status="$2" + local filename="$(bats_frame_filename "$frame")" + local lineno="$(bats_frame_lineno "$frame")" + + local failed_line="$(bats_extract_line "$filename" "$lineno")" + local failed_command="$(bats_strip_string "$failed_line")" + echo -n "# \`${failed_command}' " + + if [ $status -eq 1 ]; then + echo "failed" + else + echo "failed with status $status" + fi +} + +bats_frame_lineno() { + local frame="$1" + local lineno="${frame%% *}" + echo "$lineno" +} + +bats_frame_function() { + local frame="$1" + local rest="${frame#* }" + local fn="${rest%% *}" + echo "$fn" +} + +bats_frame_filename() { + local frame="$1" + local rest="${frame#* }" + local filename="${rest#* }" + + if [ "$filename" = "$BATS_TEST_SOURCE" ]; then + echo "$BATS_TEST_FILENAME" + else + echo "$filename" + fi +} + +bats_extract_line() { + local filename="$1" + local lineno="$2" + sed -n "${lineno}p" "$filename" +} + +bats_strip_string() { + local string="$1" + printf "%s" "$string" | sed -e "s/^[ "$'\t'"]*//" -e "s/[ "$'\t'"]*$//" +} + +bats_trim_filename() { + local filename="$1" + local length="${#BATS_CWD}" + + if [ "${filename:0:length+1}" = "${BATS_CWD}/" ]; then + echo "${filename:length+1}" + else + echo "$filename" + fi +} + +bats_debug_trap() { + if [ "$BASH_SOURCE" != "$1" ]; then + bats_capture_stack_trace + fi +} + +bats_error_trap() { + BATS_ERROR_STATUS="$?" + BATS_ERROR_STACK_TRACE=( "${BATS_PREVIOUS_STACK_TRACE[@]}" ) + trap - debug +} + +bats_teardown_trap() { + trap "bats_exit_trap" exit + local status=0 + teardown >>"$BATS_OUT" 2>&1 || status="$?" + + if [ $status -eq 0 ]; then + BATS_TEARDOWN_COMPLETED=1 + elif [ -n "$BATS_TEST_COMPLETED" ]; then + BATS_ERROR_STATUS="$status" + BATS_ERROR_STACK_TRACE=( "${BATS_CURRENT_STACK_TRACE[@]}" ) + fi + + bats_exit_trap +} + +bats_exit_trap() { + local status + local skipped + trap - err exit + + skipped="" + if [ -n "$BATS_TEST_SKIPPED" ]; then + skipped=" # skip" + if [ "1" != "$BATS_TEST_SKIPPED" ]; then + skipped+=" ($BATS_TEST_SKIPPED)" + fi + fi + + if [ -z "$BATS_TEST_COMPLETED" ] || [ -z "$BATS_TEARDOWN_COMPLETED" ]; then + echo "not ok $BATS_TEST_NUMBER $BATS_TEST_DESCRIPTION" >&3 + bats_print_stack_trace "${BATS_ERROR_STACK_TRACE[@]}" >&3 + bats_print_failed_command "${BATS_ERROR_STACK_TRACE[${#BATS_ERROR_STACK_TRACE[@]}-1]}" "$BATS_ERROR_STATUS" >&3 + sed -e "s/^/# /" < "$BATS_OUT" >&3 + status=1 + else + echo "ok ${BATS_TEST_NUMBER}${skipped} ${BATS_TEST_DESCRIPTION}" >&3 + status=0 + fi + + rm -f "$BATS_OUT" + exit "$status" +} + +bats_perform_tests() { + echo "1..$#" + test_number=1 + status=0 + for test_name in "$@"; do + "$0" $BATS_EXTENDED_SYNTAX "$BATS_TEST_FILENAME" "$test_name" "$test_number" || status=1 + let test_number+=1 + done + exit "$status" +} + +bats_perform_test() { + BATS_TEST_NAME="$1" + if [ "$(type -t "$BATS_TEST_NAME" || true)" = "function" ]; then + BATS_TEST_NUMBER="$2" + if [ -z "$BATS_TEST_NUMBER" ]; then + echo "1..1" + BATS_TEST_NUMBER="1" + fi + + BATS_TEST_COMPLETED="" + BATS_TEARDOWN_COMPLETED="" + trap "bats_debug_trap \"\$BASH_SOURCE\"" debug + trap "bats_error_trap" err + trap "bats_teardown_trap" exit + "$BATS_TEST_NAME" >>"$BATS_OUT" 2>&1 + BATS_TEST_COMPLETED=1 + + else + echo "bats: unknown test name \`$BATS_TEST_NAME'" >&2 + exit 1 + fi +} + +if [ -z "$TMPDIR" ]; then + BATS_TMPDIR="/tmp" +else + BATS_TMPDIR="${TMPDIR%/}" +fi + +BATS_TMPNAME="$BATS_TMPDIR/bats.$$" +BATS_PARENT_TMPNAME="$BATS_TMPDIR/bats.$PPID" +BATS_OUT="${BATS_TMPNAME}.out" + +bats_preprocess_source() { + BATS_TEST_SOURCE="${BATS_TMPNAME}.src" + { tr -d '\r' < "$BATS_TEST_FILENAME"; echo; } | bats-preprocess > "$BATS_TEST_SOURCE" + trap "bats_cleanup_preprocessed_source" err exit + trap "bats_cleanup_preprocessed_source; exit 1" int +} + +bats_cleanup_preprocessed_source() { + rm -f "$BATS_TEST_SOURCE" +} + +bats_evaluate_preprocessed_source() { + if [ -z "$BATS_TEST_SOURCE" ]; then + BATS_TEST_SOURCE="${BATS_PARENT_TMPNAME}.src" + fi + source "$BATS_TEST_SOURCE" +} + +exec 3<&1 + +if [ "$#" -eq 0 ]; then + bats_preprocess_source + bats_evaluate_preprocessed_source + + if [ -n "$BATS_COUNT_ONLY" ]; then + echo "${#BATS_TEST_NAMES[@]}" + else + bats_perform_tests "${BATS_TEST_NAMES[@]}" + fi +else + bats_evaluate_preprocessed_source + bats_perform_test "$@" +fi diff --git a/test/bats/bats-format-tap-stream b/test/bats/bats-format-tap-stream new file mode 100755 index 00000000..614768f4 --- /dev/null +++ b/test/bats/bats-format-tap-stream @@ -0,0 +1,165 @@ +#!/usr/bin/env bash +set -e + +# Just stream the TAP output (sans extended syntax) if tput is missing +command -v tput >/dev/null || exec grep -v "^begin " + +header_pattern='[0-9]+\.\.[0-9]+' +IFS= read -r header + +if [[ "$header" =~ $header_pattern ]]; then + count="${header:3}" + index=0 + failures=0 + skipped=0 + name="" + count_column_width=$(( ${#count} * 2 + 2 )) +else + # If the first line isn't a TAP plan, print it and pass the rest through + printf "%s\n" "$header" + exec cat +fi + +update_screen_width() { + screen_width="$(tput cols)" + count_column_left=$(( $screen_width - $count_column_width )) +} + +trap update_screen_width WINCH +update_screen_width + +begin() { + go_to_column 0 + printf_with_truncation $(( $count_column_left - 1 )) " %s" "$name" + clear_to_end_of_line + go_to_column $count_column_left + printf "%${#count}s/${count}" "$index" + go_to_column 1 +} + +pass() { + go_to_column 0 + printf " ✓ %s" "$name" + advance +} + +skip() { + local reason="$1" + [ -z "$reason" ] || reason=": $reason" + go_to_column 0 + printf " - %s (skipped%s)" "$name" "$reason" + advance +} + +fail() { + go_to_column 0 + set_color 1 bold + printf " ✗ %s" "$name" + advance +} + +log() { + set_color 1 + printf " %s\n" "$1" + clear_color +} + +summary() { + printf "\n%d test%s" "$count" "$(plural "$count")" + + printf ", %d failure%s" "$failures" "$(plural "$failures")" + + if [ "$skipped" -gt 0 ]; then + printf ", %d skipped" "$skipped" + fi + + printf "\n" +} + +printf_with_truncation() { + local width="$1" + shift + local string="$(printf "$@")" + + if [ "${#string}" -gt "$width" ]; then + printf "%s..." "${string:0:$(( $width - 4 ))}" + else + printf "%s" "$string" + fi +} + +go_to_column() { + local column="$1" + printf "\x1B[%dG" $(( $column + 1 )) +} + +clear_to_end_of_line() { + printf "\x1B[K" +} + +advance() { + clear_to_end_of_line + echo + clear_color +} + +set_color() { + local color="$1" + local weight="$2" + printf "\x1B[%d;%dm" $(( 30 + $color )) "$( [ "$weight" = "bold" ] && echo 1 || echo 22 )" +} + +clear_color() { + printf "\x1B[0m" +} + +plural() { + [ "$1" -eq 1 ] || echo "s" +} + +_buffer="" + +buffer() { + _buffer="${_buffer}$("$@")" +} + +flush() { + printf "%s" "$_buffer" + _buffer="" +} + +finish() { + flush + printf "\n" +} + +trap finish EXIT + +while IFS= read -r line; do + case "$line" in + "begin "* ) + let index+=1 + name="${line#* $index }" + buffer begin + flush + ;; + "ok "* ) + skip_expr="ok $index # skip (\(([^)]*)\))?" + if [[ "$line" =~ $skip_expr ]]; then + let skipped+=1 + buffer skip "${BASH_REMATCH[2]}" + else + buffer pass + fi + ;; + "not ok "* ) + let failures+=1 + buffer fail + ;; + "# "* ) + buffer log "${line:2}" + ;; + esac +done + +buffer summary diff --git a/test/bats/bats-preprocess b/test/bats/bats-preprocess new file mode 100755 index 00000000..04297ed0 --- /dev/null +++ b/test/bats/bats-preprocess @@ -0,0 +1,52 @@ +#!/usr/bin/env bash +set -e + +encode_name() { + local name="$1" + local result="test_" + + if [[ ! "$name" =~ [^[:alnum:]\ _-] ]]; then + name="${name//_/-5f}" + name="${name//-/-2d}" + name="${name// /_}" + result+="$name" + else + local length="${#name}" + local char i + + for ((i=0; i, orig_to=' /var/log/mail.log | grep 'status=sent' | wc -l" + [ "$status" -eq 0 ] + [ "$output" = 1 ] +} + +@test "checking smtp: user1 should have received 2 mails" { + run docker exec mail /bin/sh -c "ls -A /var/mail/localhost.localdomain/user1/new | wc -l" + [ "$status" -eq 0 ] + [ "$output" = 2 ] +} + +@test "checking smtp: rejects mail to unknown user" { + run docker exec mail /bin/sh -c "grep ': Recipient address rejected: User unknown in virtual mailbox table' /var/log/mail.log | wc -l" + [ "$status" -eq 0 ] + [ "$output" = 1 ] +} + +@test "checking smtp: redirects mail to external alias" { + run docker exec mail /bin/sh -c "grep -- '-> ' /var/log/mail.log | wc -l" + [ "$status" -eq 0 ] + [ "$output" = 1 ] +} + +@test "checking smtp: rejects spam" { + run docker exec mail /bin/sh -c "grep 'Blocked SPAM' /var/log/mail.log | grep spam@external.tld | wc -l" + [ "$status" -eq 0 ] + [ "$output" = 1 ] +} + +@test "checking smtp: rejects virus" { + run docker exec mail /bin/sh -c "grep 'Blocked INFECTED' /var/log/mail.log | grep virus@external.tld | wc -l" + [ "$status" -eq 0 ] + [ "$output" = 1 ] +} + +# +# accounts +# + +@test "checking accounts: user accounts" { + run docker exec mail sasldblistusers2 + [ "$status" -eq 0 ] + [ "${lines[0]}" = "user1@localhost.localdomain: userPassword" ] + [ "${lines[1]}" = "user2@otherdomain.tld: userPassword" ] +} + +@test "checking accounts: user mail folders for user1" { + run docker exec mail ls -A /var/mail/localhost.localdomain/user1 + [ "$status" -eq 0 ] + [ "${lines[0]}" = ".Drafts" ] + [ "${lines[1]}" = ".Sent" ] + [ "${lines[2]}" = ".Trash" ] + [ "${lines[3]}" = "courierimapsubscribed" ] + [ "${lines[4]}" = "cur" ] + [ "${lines[5]}" = "new" ] + [ "${lines[6]}" = "tmp" ] +} + +@test "checking accounts: user mail folders for user2" { + run docker exec mail ls -A /var/mail/otherdomain.tld/user2 + [ "$status" -eq 0 ] + [ "${lines[0]}" = ".Drafts" ] + [ "${lines[1]}" = ".Sent" ] + [ "${lines[2]}" = ".Trash" ] + [ "${lines[3]}" = "courierimapsubscribed" ] + [ "${lines[4]}" = "cur" ] + [ "${lines[5]}" = "new" ] + [ "${lines[6]}" = "tmp" ] +} + +# +# postfix +# + +@test "checking postfix: vhost file is correct" { + run docker exec mail cat /etc/postfix/vhost + [ "$status" -eq 0 ] + [ "${lines[0]}" = "localhost.localdomain" ] + [ "${lines[1]}" = "otherdomain.tld" ] +} + +# +# spamassassin +# + +@test "checking spamassassin: docker env variables are set correctly (default)" { + run docker exec mail_pop3 /bin/sh -c "grep '\$sa_tag_level_deflt' /etc/amavis/conf.d/20-debian_defaults | grep '= 2.0'" + [ "$status" -eq 0 ] + run docker exec mail_pop3 /bin/sh -c "grep '\$sa_tag2_level_deflt' /etc/amavis/conf.d/20-debian_defaults | grep '= 6.31'" + [ "$status" -eq 0 ] + run docker exec mail_pop3 /bin/sh -c "grep '\$sa_kill_level_deflt' /etc/amavis/conf.d/20-debian_defaults | grep '= 6.31'" + [ "$status" -eq 0 ] +} + +@test "checking spamassassin: docker env variables are set correctly (custom)" { + run docker exec mail /bin/sh -c "grep '\$sa_tag_level_deflt' /etc/amavis/conf.d/20-debian_defaults | grep '= 1.0'" + [ "$status" -eq 0 ] + run docker exec mail /bin/sh -c "grep '\$sa_tag2_level_deflt' /etc/amavis/conf.d/20-debian_defaults | grep '= 2.0'" + [ "$status" -eq 0 ] + run docker exec mail /bin/sh -c "grep '\$sa_kill_level_deflt' /etc/amavis/conf.d/20-debian_defaults | grep '= 3.0'" + [ "$status" -eq 0 ] +} + +# +# opendkim +# + +@test "checking opendkim: /etc/opendkim/KeyTable should contain 2 entries" { + run docker exec mail /bin/sh -c "cat /etc/opendkim/KeyTable | wc -l" + [ "$status" -eq 0 ] + [ "$output" -eq 2 ] +} + +@test "checking opendkim: /etc/opendkim/keys/ should contain 2 entries" { + run docker exec mail /bin/sh -c "ls -l /etc/opendkim/keys/ | grep '^d' | wc -l" + [ "$status" -eq 0 ] + [ "$output" -eq 2 ] +} + +# +# opendmarc +# + +@test "checking opendkim: server fqdn should be added to /etc/opendmarc.conf as AuthservID" { + run docker exec mail grep ^AuthservID /etc/opendmarc.conf + [ "$status" -eq 0 ] + [ "$output" = "AuthservID mail.my-domain.com" ] +} + +@test "checking opendkim: server fqdn should be added to /etc/opendmarc.conf as TrustedAuthservIDs" { + run docker exec mail grep ^TrustedAuthservID /etc/opendmarc.conf + [ "$status" -eq 0 ] + [ "$output" = "TrustedAuthservIDs mail.my-domain.com" ] +} + +# +# letsencrypt +# + +@test "checking letsencrypt: lets-encrypt-x1-cross-signed.pem is installed" { + run docker exec mail grep 'BEGIN CERTIFICATE' /etc/ssl/certs/lets-encrypt-x1-cross-signed.pem + [ "$status" -eq 0 ] +} + +@test "checking letsencrypt: lets-encrypt-x2-cross-signed.pem is installed" { + run docker exec mail grep 'BEGIN CERTIFICATE' /etc/ssl/certs/lets-encrypt-x2-cross-signed.pem + [ "$status" -eq 0 ] +} + +# +# ssl +# + +@test "checking ssl: generated default cert is installed" { + run docker exec mail /bin/sh -c "openssl s_client -connect 0.0.0.0:587 -starttls smtp -CApath /etc/ssl/certs/ | grep 'Verify return code: 0 (ok)'" + [ "$status" -eq 0 ] +} + +# +# fail2ban +# + +@test "checking fail2ban: localhost is not banned" { + run docker exec mail /bin/sh -c "fail2ban-client status sasl | grep 'IP list:\s*127.0.0.1'" + [ "$status" -eq 1 ] +} + +@test "checking fail2ban: ban ip on multiple failed login" { + docker exec mail fail2ban-client status sasl + docker exec mail fail2ban-client set sasl delignoreip 127.0.0.1/8 + docker exec mail /bin/sh -c 'nc -w 1 0.0.0.0 25 < /tmp/test/auth/smtp-auth-login-wrong.txt' + docker exec mail /bin/sh -c 'nc -w 1 0.0.0.0 25 < /tmp/test/auth/smtp-auth-login-wrong.txt' + docker exec mail /bin/sh -c 'nc -w 1 0.0.0.0 25 < /tmp/test/auth/smtp-auth-login-wrong.txt' + sleep 5 + run docker exec mail /bin/sh -c "fail2ban-client status sasl | grep 'IP list:\s*127.0.0.1'" + [ "$status" -eq 0 ] +} + +@test "checking fail2ban: unban ip works" { + docker exec mail fail2ban-client set sasl addignoreip 127.0.0.1/8 + docker exec mail fail2ban-client set sasl unbanip 127.0.0.1 + sleep 5 + run docker exec mail /bin/sh -c "fail2ban-client status sasl | grep 'IP list:\s*127.0.0.1'" + [ "$status" -eq 1 ] +} + +# +# system +# + +@test "checking system: freshclam cron is enabled" { + run docker exec mail crontab -l + [ "$status" -eq 0 ] + [ "$output" = "0 1 * * * /usr/bin/freshclam --quiet" ] +} + +@test "checking system: /var/log/mail.log is error free" { + run docker exec mail grep 'non-null host address bits in' /var/log/mail.log + [ "$status" -eq 1 ] + run docker exec mail grep ': error:' /var/log/mail.log + [ "$status" -eq 1 ] + run docker exec mail_pop3 grep 'non-null host address bits in' /var/log/mail.log + [ "$status" -eq 1 ] + run docker exec mail_pop3 grep ': error:' /var/log/mail.log + [ "$status" -eq 1 ] +} + +@test "checking system: sets the server fqdn" { + run docker exec mail hostname + [ "$status" -eq 0 ] + [ "$output" = "mail.my-domain.com" ] +} + +@test "checking system: sets the server domain name in /etc/mailname" { + run docker exec mail cat /etc/mailname + [ "$status" -eq 0 ] + [ "$output" = "my-domain.com" ] +} From ab9fd690520e5f0eb53d69229dbd5e518c663767 Mon Sep 17 00:00:00 2001 From: Thomas VIAL Date: Thu, 25 Feb 2016 12:15:33 +0100 Subject: [PATCH 138/155] Fixed test file now moved to "bats" --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 66337e5a..7b841fca 100644 --- a/README.md +++ b/README.md @@ -110,7 +110,7 @@ Feel free to improve this docker image. - Fork - Improve -- Add integration tests in `test/test.sh` +- Add integration tests in `test/tests.bats` - Build image and run tests using `make` - Document your improvements - Commit, push and make a pull-request From 6bd5c5015af895f98ef38c50778b0519074dd9d4 Mon Sep 17 00:00:00 2001 From: Emanuele Mazzotta Date: Sat, 27 Feb 2016 17:16:28 +0100 Subject: [PATCH 139/155] Allowing CA signed custom certificates This is to use a non-letsencrypt but CA signed (so non-self-signed) certificate which contains everything, key etc. --- start-mailserver.sh | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/start-mailserver.sh b/start-mailserver.sh index bcabaa72..43eb12a6 100644 --- a/start-mailserver.sh +++ b/start-mailserver.sh @@ -139,6 +139,29 @@ case $DMS_SSL in ;; + "custom" ) + # Adding CA signed SSL certificate if provided in 'postfix/ssl' folder + if [ -e "/tmp/postfix/ssl/$(hostname)-full.pem" ]; then + echo "Adding $(hostname) SSL certificate" + mkdir -p /etc/postfix/ssl + cp "/tmp/postfix/ssl/$(hostname)-full.pem" /etc/postfix/ssl + + # Postfix configuration + sed -i -r 's/smtpd_tls_cert_file=\/etc\/ssl\/certs\/ssl-cert-snakeoil.pem/smtpd_tls_cert_file=\/etc\/postfix\/ssl\/'$(hostname)'-full.pem/g' /etc/postfix/main.cf + sed -i -r 's/smtpd_tls_key_file=\/etc\/ssl\/private\/ssl-cert-snakeoil.key/smtpd_tls_key_file=\/etc\/postfix\/ssl\/'$(hostname)'-full.pem/g' /etc/postfix/main.cf + + # Courier configuration + sed -i -r 's/TLS_CERTFILE=\/etc\/courier\/imapd.pem/TLS_CERTFILE=\/etc\/postfix\/ssl\/'$(hostname)'-full.pem/g' /etc/courier/imapd-ssl + + # POP3 courier configuration + sed -i -r 's/POP3_TLS_REQUIRED=0/POP3_TLS_REQUIRED=1/g' /etc/courier/pop3d-ssl + sed -i -r 's/TLS_CERTFILE=\/etc\/courier\/pop3d.pem/TLS_CERTFILE=\/etc\/postfix\/ssl\/'$(hostname)'-full.pem/g' /etc/courier/pop3d-ssl + + echo "SSL configured with CA signed/custom certificates" + + fi + ;; + "self-signed" ) # Adding self-signed SSL certificate if provided in 'postfix/ssl' folder if [ -e "/tmp/postfix/ssl/$(hostname)-cert.pem" ] \ From 2769269bd615732e7f9d5e7b89f1d2fda2a2c1af Mon Sep 17 00:00:00 2001 From: Marko Jung Date: Mon, 29 Feb 2016 23:52:10 +0100 Subject: [PATCH 140/155] new SMTP_ONLY environment option to disable all courier daemons --- Makefile | 8 +++++++- start-mailserver.sh | 6 +++++- test/tests.bats | 16 ++++++++++++++++ 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 01d7ffd6..05029946 100644 --- a/Makefile +++ b/Makefile @@ -25,6 +25,12 @@ run: -v "`pwd`/test":/tmp/test \ -e ENABLE_POP3=1 \ -h mail.my-domain.com -t $(NAME) + docker run -d --name mail_smtponly \ + -v "`pwd`/postfix":/tmp/postfix \ + -v "`pwd`/spamassassin":/tmp/spamassassin \ + -v "`pwd`/test":/tmp/test \ + -e SMTP_ONLY=1 \ + -h mail.my-domain.com -t $(NAME) # Wait for containers to fully start sleep 60 @@ -47,4 +53,4 @@ clean: # Get default files back git checkout postfix/accounts.cf postfix/virtual # Remove running test containers - docker rm -f mail mail_pop3 \ No newline at end of file + docker rm -f mail mail_pop3 mail_smtponly diff --git a/start-mailserver.sh b/start-mailserver.sh index 43eb12a6..e8668a36 100644 --- a/start-mailserver.sh +++ b/start-mailserver.sh @@ -229,11 +229,15 @@ echo "Starting daemons" cron /etc/init.d/rsyslog start /etc/init.d/saslauthd start + +if [ "$SMTP_ONLY" != 1 ]; then + /etc/init.d/courier-authdaemon start /etc/init.d/courier-imap start /etc/init.d/courier-imap-ssl start -if [ "$ENABLE_POP3" = 1 ]; then +fi +if [ "$ENABLE_POP3" = 1 -a "$SMTP_ONLY" != 1 ]; then echo "Starting POP3 services" /etc/init.d/courier-pop start /etc/init.d/courier-pop-ssl start diff --git a/test/tests.bats b/test/tests.bats index 7eeed0ce..be681fb1 100644 --- a/test/tests.bats +++ b/test/tests.bats @@ -47,10 +47,26 @@ [ "$status" -eq 0 ] } +@test "checking process: courierpop3d (disabled using SMTP_ONLY)" { + run docker exec mail_smtponly /bin/bash -c "ps aux --forest | grep -v grep | grep '/usr/lib/courier/courier/courierpop3d'" + [ "$status" -eq 1 ] +} + + # # imap # +@test "checking process: courier imaplogin (enabled in default configuration)" { + run docker exec mail /bin/bash -c "ps aux --forest | grep -v grep | grep '/usr/lib/courier/courier/imaplogin'" + [ "$status" -eq 0 ] +} + +@test "checking process: courier imaplogin (disabled using SMTP_ONLY)" { + run docker exec mail_smtponly /bin/bash -c "ps aux --forest | grep -v grep | grep '/usr/lib/courier/courier/imaplogin'" + [ "$status" -eq 1 ] +} + @test "checking imap: server is ready with STARTTLS" { run docker exec mail /bin/bash -c "nc -w 1 0.0.0.0 143 | grep '* OK' | grep 'STARTTLS' | grep 'Courier-IMAP ready'" [ "$status" -eq 0 ] From ca35e0e313843a765d3167af99014608cb6cd1dd Mon Sep 17 00:00:00 2001 From: Marko Jung Date: Tue, 1 Mar 2016 00:21:23 +0100 Subject: [PATCH 141/155] on special request also some documentation --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 7b841fca..43021837 100644 --- a/README.md +++ b/README.md @@ -94,6 +94,8 @@ Example: * *6.31* (default) => add 'spam detected' headers at that level * SA_KILL * *6.31* (default) => triggers spam evasive actions) +* SMTP_ONLY + * do not launch any courier daemons (imap, pop3) Please read [how the container starts](https://github.com/tomav/docker-mailserver/blob/master/start-mailserver.sh) to understand what's expected. From cbf72bdb538d452f59d167bec6e6fab47b814619 Mon Sep 17 00:00:00 2001 From: Marko J Date: Tue, 1 Mar 2016 01:04:31 +0000 Subject: [PATCH 142/155] Better documentation for SMTP_ONLY environment variable --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 43021837..0cd895f9 100644 --- a/README.md +++ b/README.md @@ -88,14 +88,15 @@ Example: * ENABLE_POP3 * *empty* (default) => POP3 service disabled * 1 => Enables POP3 service +* SMTP_ONLY + * *empty* (default) => courier daemons might start + * *1 => do not launch any courier daemons (imap, pop3) * SA_TAG * *2.0* (default) => add spam info headers if at, or above that level * SA_TAG2 * *6.31* (default) => add 'spam detected' headers at that level * SA_KILL * *6.31* (default) => triggers spam evasive actions) -* SMTP_ONLY - * do not launch any courier daemons (imap, pop3) Please read [how the container starts](https://github.com/tomav/docker-mailserver/blob/master/start-mailserver.sh) to understand what's expected. From 082577f27b1bd04cda2a958bfcf1c205188aa56d Mon Sep 17 00:00:00 2001 From: Dominik Winter Date: Fri, 11 Mar 2016 21:37:04 +0100 Subject: [PATCH 143/155] continue to write the log information in the newly created file after rotating the old log file --- start-mailserver.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/start-mailserver.sh b/start-mailserver.sh index e8668a36..e24d6f8f 100644 --- a/start-mailserver.sh +++ b/start-mailserver.sh @@ -158,7 +158,7 @@ case $DMS_SSL in sed -i -r 's/TLS_CERTFILE=\/etc\/courier\/pop3d.pem/TLS_CERTFILE=\/etc\/postfix\/ssl\/'$(hostname)'-full.pem/g' /etc/courier/pop3d-ssl echo "SSL configured with CA signed/custom certificates" - + fi ;; @@ -224,6 +224,8 @@ sed -i "/^findtime *=/c\findtime = 10800" /etc/fail2ban/jail.conf # avoid warning on startup echo "ignoreregex =" >> /etc/fail2ban/filter.d/postfix-sasl.conf +# continue to write the log information in the newly created file after rotating the old log file +sed -i -r "/^#?compress/c\compress\ncopytruncate" /etc/logrotate.conf echo "Starting daemons" cron From 3cabf10520c792d24fa646db7f6de5c93aef5276 Mon Sep 17 00:00:00 2001 From: Chris54721 Date: Fri, 18 Mar 2016 20:07:58 +0100 Subject: [PATCH 144/155] Add tests for main.cf overrides --- Makefile | 3 ++- test/main.cf | 2 ++ test/tests.bats | 7 +++++++ 3 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 test/main.cf diff --git a/Makefile b/Makefile index 05029946..a64deb56 100644 --- a/Makefile +++ b/Makefile @@ -9,6 +9,7 @@ build: run: # Copy test files cp test/accounts.cf postfix/ + cp test/main.cf postfix/ cp test/virtual postfix/ # Run containers docker run -d --name mail \ @@ -51,6 +52,6 @@ tests: clean: # Get default files back - git checkout postfix/accounts.cf postfix/virtual + git checkout postfix/accounts.cf postfix/main.cf postfix/virtual # Remove running test containers docker rm -f mail mail_pop3 mail_smtponly diff --git a/test/main.cf b/test/main.cf new file mode 100644 index 00000000..37155392 --- /dev/null +++ b/test/main.cf @@ -0,0 +1,2 @@ +max_idle = 600s +readme_directory = /tmp diff --git a/test/tests.bats b/test/tests.bats index be681fb1..89de473e 100644 --- a/test/tests.bats +++ b/test/tests.bats @@ -217,6 +217,13 @@ [ "${lines[1]}" = "otherdomain.tld" ] } +@test "checking postfix: main.cf overrides" { + run docker exec mail grep -q 'max_idle = 600s' /tmp/postfix/main.cf + [ "$status" -eq 0 ] + run docker exec mail grep -q 'readme_directory = /tmp' /tmp/postfix/main.cf + [ "$status" -eq 0 ] +} + # # spamassassin # From ec5837d496fd419429ab7ec0792c8db2a3663c49 Mon Sep 17 00:00:00 2001 From: Chris54721 Date: Fri, 18 Mar 2016 20:10:05 +0100 Subject: [PATCH 145/155] Update start-mailserver.sh --- start-mailserver.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/start-mailserver.sh b/start-mailserver.sh index 3056fcf6..46f1ff45 100644 --- a/start-mailserver.sh +++ b/start-mailserver.sh @@ -202,7 +202,7 @@ if [ -f /tmp/postfix/main.cf ]; then done < /tmp/postfix/main.cf echo "Loaded '/tmp/postfix/main.cf'" else - echo "==> Warning: '/tmp/postfix/main.cf' is not provided. No extra postfix settings loaded." + echo "'/tmp/postfix/main.cf' not provided. No extra postfix settings loaded." fi if [ ! -z "$SASL_PASSWD" ]; then From 53959b8eaed9a40958983c31df18f0df8614f298 Mon Sep 17 00:00:00 2001 From: Chris54721 Date: Fri, 18 Mar 2016 20:12:18 +0100 Subject: [PATCH 146/155] Add tests for SASL_PASSWD --- Makefile | 11 ++++++----- test/tests.bats | 5 +++++ 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index a64deb56..aed0b797 100644 --- a/Makefile +++ b/Makefile @@ -19,6 +19,7 @@ run: -e SA_TAG=1.0 \ -e SA_TAG2=2.0 \ -e SA_KILL=3.0 \ + -e SASL_PASSWD=testing \ -h mail.my-domain.com -t $(NAME) docker run -d --name mail_pop3 \ -v "`pwd`/postfix":/tmp/postfix \ @@ -37,11 +38,11 @@ run: fixtures: # Sending test mails - docker exec mail /bin/sh -c "nc 0.0.0.0 25 < /tmp/test/email-templates/amavis-spam.txt" - docker exec mail /bin/sh -c "nc 0.0.0.0 25 < /tmp/test/email-templates/amavis-virus.txt" - docker exec mail /bin/sh -c "nc 0.0.0.0 25 < /tmp/test/email-templates/existing-alias-external.txt" - docker exec mail /bin/sh -c "nc 0.0.0.0 25 < /tmp/test/email-templates/existing-alias-local.txt" - docker exec mail /bin/sh -c "nc 0.0.0.0 25 < /tmp/test/email-templates/existing-user.txt" + docker exec mail /bin/sh -c "nc 0.0.0.0 25 < /tmp/test/email-templates/amavis-spam.txt" + docker exec mail /bin/sh -c "nc 0.0.0.0 25 < /tmp/test/email-templates/amavis-virus.txt" + docker exec mail /bin/sh -c "nc 0.0.0.0 25 < /tmp/test/email-templates/existing-alias-external.txt" + docker exec mail /bin/sh -c "nc 0.0.0.0 25 < /tmp/test/email-templates/existing-alias-local.txt" + docker exec mail /bin/sh -c "nc 0.0.0.0 25 < /tmp/test/email-templates/existing-user.txt" docker exec mail /bin/sh -c "nc 0.0.0.0 25 < /tmp/test/email-templates/non-existing-user.txt" # Wait for mails to be analyzed sleep 10 diff --git a/test/tests.bats b/test/tests.bats index 89de473e..8cfe488e 100644 --- a/test/tests.bats +++ b/test/tests.bats @@ -105,6 +105,11 @@ [ "$status" -eq 0 ] } +@test "checking sasl: sasl_passwd.db exists" { + run docker exec mail [ -f /etc/postfix/sasl_passwd.db ] + [ "$status" -eq 0 ] +} + # # smtp # From 09315d3d3c373731e444c73de5f2ff054dd2512b Mon Sep 17 00:00:00 2001 From: Reldeis Date: Wed, 30 Mar 2016 11:51:40 +0200 Subject: [PATCH 147/155] Add eol to letsencrypt provided files --- start-mailserver.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/start-mailserver.sh b/start-mailserver.sh index 082341b6..7f133da6 100644 --- a/start-mailserver.sh +++ b/start-mailserver.sh @@ -120,6 +120,10 @@ fi case $DMS_SSL in "letsencrypt" ) # letsencrypt folders and files mounted in /etc/letsencrypt + # add eol to all files before concatenation + sed -i -e '$a\' /etc/letsencrypt/live/$(hostname)/cert.pem + sed -i -e '$a\' /etc/letsencrypt/live/$(hostname)/chain.pem + sed -i -e '$a\' /etc/letsencrypt/live/$(hostname)/privkey.pem # Postfix configuration sed -i -r 's/smtpd_tls_cert_file=\/etc\/ssl\/certs\/ssl-cert-snakeoil.pem/smtpd_tls_cert_file=\/etc\/letsencrypt\/live\/'$(hostname)'\/fullchain.pem/g' /etc/postfix/main.cf From 5219aab9e8d6a0336f330a1d00d412cb00d2fe99 Mon Sep 17 00:00:00 2001 From: angus Date: Thu, 31 Mar 2016 12:33:47 +0200 Subject: [PATCH 148/155] Add ENABLE_FAIL2BAN environment variable to enable fail2ban service (it's not enabled by default, now). * Changed/updated Makefile and integration tests * Changed some grep expressions in the fail2ban tests --- Makefile | 8 +++++++- README.md | 5 ++++- start-mailserver.sh | 6 +++++- test/tests.bats | 27 ++++++++++++++++----------- 4 files changed, 32 insertions(+), 14 deletions(-) diff --git a/Makefile b/Makefile index aed0b797..03899b5c 100644 --- a/Makefile +++ b/Makefile @@ -33,6 +33,12 @@ run: -v "`pwd`/test":/tmp/test \ -e SMTP_ONLY=1 \ -h mail.my-domain.com -t $(NAME) + docker run -d --name mail_fail2ban \ + -v "`pwd`/postfix":/tmp/postfix \ + -v "`pwd`/spamassassin":/tmp/spamassassin \ + -v "`pwd`/test":/tmp/test \ + -e ENABLE_FAIL2BAN=1 \ + -h mail.my-domain.com -t $(NAME) # Wait for containers to fully start sleep 60 @@ -55,4 +61,4 @@ clean: # Get default files back git checkout postfix/accounts.cf postfix/main.cf postfix/virtual # Remove running test containers - docker rm -f mail mail_pop3 mail_smtponly + docker rm -f mail mail_pop3 mail_smtponly mail_fail2ban diff --git a/README.md b/README.md index 6fdb8edf..acb30ea7 100644 --- a/README.md +++ b/README.md @@ -96,10 +96,13 @@ Example: * SA_TAG2 * *6.31* (default) => add 'spam detected' headers at that level * SA_KILL - * *6.31* (default) => triggers spam evasive actions) + * *6.31* (default) => triggers spam evasive actions * SASL_PASSWORD * *empty* (default) => No sasl_passwd will be created * *string* => A /etc/postfix/sasl_passwd will be created with that content and postmap will be run on it +* ENABLE_FAIL2BAN + * *empty* (default) => fail2ban service disabled + * 1 => Enables fail2ban service Please read [how the container starts](https://github.com/tomav/docker-mailserver/blob/master/start-mailserver.sh) to understand what's expected. diff --git a/start-mailserver.sh b/start-mailserver.sh index 46f1ff45..5486c78e 100644 --- a/start-mailserver.sh +++ b/start-mailserver.sh @@ -269,7 +269,11 @@ fi /etc/init.d/opendkim start /etc/init.d/opendmarc start /etc/init.d/postfix start -/etc/init.d/fail2ban start + +if [ "$ENABLE_FAIL2BAN" = 1 ]; then + echo "Starting fail2ban service" + /etc/init.d/fail2ban start +fi echo "Listing SASL users" sasldblistusers2 diff --git a/test/tests.bats b/test/tests.bats index 8cfe488e..72c569b5 100644 --- a/test/tests.bats +++ b/test/tests.bats @@ -32,8 +32,13 @@ [ "$status" -eq 0 ] } -@test "checking process: fail2ban" { +@test "checking process: fail2ban (disabled in default configuration)" { run docker exec mail /bin/bash -c "ps aux --forest | grep -v grep | grep '/usr/bin/python /usr/bin/fail2ban-server'" + [ "$status" -eq 1 ] +} + +@test "checking process: fail2ban (fail2ban server enabled)" { + run docker exec mail_fail2ban /bin/bash -c "ps aux --forest | grep -v grep | grep '/usr/bin/python /usr/bin/fail2ban-server'" [ "$status" -eq 0 ] } @@ -311,26 +316,26 @@ # @test "checking fail2ban: localhost is not banned" { - run docker exec mail /bin/sh -c "fail2ban-client status sasl | grep 'IP list:\s*127.0.0.1'" + run docker exec mail_fail2ban /bin/sh -c "fail2ban-client status sasl | grep 'IP list:.*127.0.0.1'" [ "$status" -eq 1 ] } @test "checking fail2ban: ban ip on multiple failed login" { - docker exec mail fail2ban-client status sasl - docker exec mail fail2ban-client set sasl delignoreip 127.0.0.1/8 - docker exec mail /bin/sh -c 'nc -w 1 0.0.0.0 25 < /tmp/test/auth/smtp-auth-login-wrong.txt' - docker exec mail /bin/sh -c 'nc -w 1 0.0.0.0 25 < /tmp/test/auth/smtp-auth-login-wrong.txt' - docker exec mail /bin/sh -c 'nc -w 1 0.0.0.0 25 < /tmp/test/auth/smtp-auth-login-wrong.txt' + docker exec mail_fail2ban fail2ban-client status sasl + docker exec mail_fail2ban fail2ban-client set sasl delignoreip 127.0.0.1/8 + docker exec mail_fail2ban /bin/sh -c 'nc -w 1 0.0.0.0 25 < /tmp/test/auth/smtp-auth-login-wrong.txt' + docker exec mail_fail2ban /bin/sh -c 'nc -w 1 0.0.0.0 25 < /tmp/test/auth/smtp-auth-login-wrong.txt' + docker exec mail_fail2ban /bin/sh -c 'nc -w 1 0.0.0.0 25 < /tmp/test/auth/smtp-auth-login-wrong.txt' sleep 5 - run docker exec mail /bin/sh -c "fail2ban-client status sasl | grep 'IP list:\s*127.0.0.1'" + run docker exec mail_fail2ban /bin/sh -c "fail2ban-client status sasl | grep 'IP list:.*127.0.0.1'" [ "$status" -eq 0 ] } @test "checking fail2ban: unban ip works" { - docker exec mail fail2ban-client set sasl addignoreip 127.0.0.1/8 - docker exec mail fail2ban-client set sasl unbanip 127.0.0.1 + docker exec mail_fail2ban fail2ban-client set sasl addignoreip 127.0.0.1/8 + docker exec mail_fail2ban fail2ban-client set sasl unbanip 127.0.0.1 sleep 5 - run docker exec mail /bin/sh -c "fail2ban-client status sasl | grep 'IP list:\s*127.0.0.1'" + run docker exec mail_fail2ban /bin/sh -c "fail2ban-client status sasl | grep 'IP list:.*127.0.0.1'" [ "$status" -eq 1 ] } From 0f943788427a6e7eefd963e17822952ad0e99a79 Mon Sep 17 00:00:00 2001 From: angus Date: Fri, 1 Apr 2016 17:18:13 +0200 Subject: [PATCH 149/155] All email-related services now logs in /var/log/mail/ and fail2ban config has been updated accordingly. Added also a check before copying spamassassin rule file. --- start-mailserver.sh | 23 ++++++++++++++++------- test/tests.bats | 22 +++++++++++----------- 2 files changed, 27 insertions(+), 18 deletions(-) diff --git a/start-mailserver.sh b/start-mailserver.sh index 010e09b8..45ca5259 100644 --- a/start-mailserver.sh +++ b/start-mailserver.sh @@ -222,7 +222,6 @@ fi echo "Fixing permissions" chown -R 5000:5000 /var/mail -mkdir -p /var/log/clamav && chown -R clamav:root /var/log/clamav chown postfix.sasl /etc/sasldb2 echo "Creating /etc/mailname" @@ -232,14 +231,16 @@ echo "Configuring Spamassassin" SA_TAG=${SA_TAG:="2.0"} && sed -i -r 's/^\$sa_tag_level_deflt (.*);/\$sa_tag_level_deflt = '$SA_TAG';/g' /etc/amavis/conf.d/20-debian_defaults SA_TAG2=${SA_TAG2:="6.31"} && sed -i -r 's/^\$sa_tag2_level_deflt (.*);/\$sa_tag2_level_deflt = '$SA_TAG2';/g' /etc/amavis/conf.d/20-debian_defaults SA_KILL=${SA_KILL:="6.31"} && sed -i -r 's/^\$sa_kill_level_deflt (.*);/\$sa_kill_level_deflt = '$SA_KILL';/g' /etc/amavis/conf.d/20-debian_defaults -cp /tmp/spamassassin/rules.cf /etc/spamassassin/ +test -e /tmp/spamassassin/rules.cf && cp /tmp/spamassassin/rules.cf /etc/spamassassin/ echo "Configuring fail2ban" # enable filters -perl -i -0pe 's/(\[postfix\]\n\n).*\n/\1enabled = true\n/' /etc/fail2ban/jail.conf -perl -i -0pe 's/(\[couriersmtp\]\n\n).*\n/\1enabled = true\n/' /etc/fail2ban/jail.conf -perl -i -0pe 's/(\[courierauth\]\n\n).*\n/\1enabled = true\n/' /etc/fail2ban/jail.conf -perl -i -0pe 's/(\[sasl\]\n\n).*\n/\1enabled = true\n/' /etc/fail2ban/jail.conf +awk 'BEGIN{unit=0}{if ($1=="[postfix]" || $1=="[couriersmtp]" || $1=="[courierauth]" || $1=="[sasl]") {unit=1;} + if ($1=="enabled" && unit==1) $3="true"; + else if ($1=="logpath" && unit==1) $3="/var/log/mail/mail.log"; + print; + if (unit==1 && $1~/\[/ && $1!~/postfix|couriersmtp|courierauth|sasl/) unit=0; +}'/etc/fail2ban/jail.conf > /tmp/jail.conf.new && mv /tmp/jail.conf.new /etc/fail2ban/jail.conf && rm -f /tmp/jail.conf.new # increase ban time and find time to 3h sed -i "/^bantime *=/c\bantime = 10800" /etc/fail2ban/jail.conf @@ -251,6 +252,14 @@ echo "ignoreregex =" >> /etc/fail2ban/filter.d/postfix-sasl.conf # continue to write the log information in the newly created file after rotating the old log file sed -i -r "/^#?compress/c\compress\ncopytruncate" /etc/logrotate.conf +# Setup logging +mkdir -p /var/log/mail && chown syslog:root /var/log/mail +touch /var/log/mail/clamav.log && chown -R clamav:root /var/log/mail/clamav.log +touch /var/log/mail/freshclam.log && chown -R clamav:root /var/log/mail/freshclam.log +sed -i -r 's|/var/log/mail|/var/log/mail/mail|g' /etc/rsyslog.d/50-default.conf +sed -i -r 's|LogFile /var/log/clamav/|LogFile /var/log/mail/|g' /etc/clamav/clamd.conf +sed -i -r 's|UpdateLogFile /var/log/clamav/|UpdateLogFile /var/log/mail/|g' /etc/clamav/freshclam.conf + echo "Starting daemons" cron /etc/init.d/rsyslog start @@ -285,4 +294,4 @@ echo "Listing SASL users" sasldblistusers2 echo "Starting..." -tail -f /var/log/mail.log +tail -f /var/log/mail/mail.log diff --git a/test/tests.bats b/test/tests.bats index 72c569b5..3aadc551 100644 --- a/test/tests.bats +++ b/test/tests.bats @@ -140,13 +140,13 @@ } @test "checking smtp: delivers mail to existing account" { - run docker exec mail /bin/sh -c "grep 'status=sent (delivered to maildir)' /var/log/mail.log | wc -l" + run docker exec mail /bin/sh -c "grep 'status=sent (delivered to maildir)' /var/log/mail/mail.log | wc -l" [ "$status" -eq 0 ] [ "$output" -eq 2 ] } @test "checking smtp: delivers mail to existing alias" { - run docker exec mail /bin/sh -c "grep 'to=, orig_to=' /var/log/mail.log | grep 'status=sent' | wc -l" + run docker exec mail /bin/sh -c "grep 'to=, orig_to=' /var/log/mail/mail.log | grep 'status=sent' | wc -l" [ "$status" -eq 0 ] [ "$output" = 1 ] } @@ -158,25 +158,25 @@ } @test "checking smtp: rejects mail to unknown user" { - run docker exec mail /bin/sh -c "grep ': Recipient address rejected: User unknown in virtual mailbox table' /var/log/mail.log | wc -l" + run docker exec mail /bin/sh -c "grep ': Recipient address rejected: User unknown in virtual mailbox table' /var/log/mail/mail.log | wc -l" [ "$status" -eq 0 ] [ "$output" = 1 ] } @test "checking smtp: redirects mail to external alias" { - run docker exec mail /bin/sh -c "grep -- '-> ' /var/log/mail.log | wc -l" + run docker exec mail /bin/sh -c "grep -- '-> ' /var/log/mail/mail.log | wc -l" [ "$status" -eq 0 ] [ "$output" = 1 ] } @test "checking smtp: rejects spam" { - run docker exec mail /bin/sh -c "grep 'Blocked SPAM' /var/log/mail.log | grep spam@external.tld | wc -l" + run docker exec mail /bin/sh -c "grep 'Blocked SPAM' /var/log/mail/mail.log | grep spam@external.tld | wc -l" [ "$status" -eq 0 ] [ "$output" = 1 ] } @test "checking smtp: rejects virus" { - run docker exec mail /bin/sh -c "grep 'Blocked INFECTED' /var/log/mail.log | grep virus@external.tld | wc -l" + run docker exec mail /bin/sh -c "grep 'Blocked INFECTED' /var/log/mail/mail.log | grep virus@external.tld | wc -l" [ "$status" -eq 0 ] [ "$output" = 1 ] } @@ -349,14 +349,14 @@ [ "$output" = "0 1 * * * /usr/bin/freshclam --quiet" ] } -@test "checking system: /var/log/mail.log is error free" { - run docker exec mail grep 'non-null host address bits in' /var/log/mail.log +@test "checking system: /var/log/mail/mail.log is error free" { + run docker exec mail grep 'non-null host address bits in' /var/log/mail/mail.log [ "$status" -eq 1 ] - run docker exec mail grep ': error:' /var/log/mail.log + run docker exec mail grep ': error:' /var/log/mail/mail.log [ "$status" -eq 1 ] - run docker exec mail_pop3 grep 'non-null host address bits in' /var/log/mail.log + run docker exec mail_pop3 grep 'non-null host address bits in' /var/log/mail/mail.log [ "$status" -eq 1 ] - run docker exec mail_pop3 grep ': error:' /var/log/mail.log + run docker exec mail_pop3 grep ': error:' /var/log/mail/mail.log [ "$status" -eq 1 ] } From d2bb97a810f88a1e4f114812f682cb030ffc7956 Mon Sep 17 00:00:00 2001 From: Thomas Willems Date: Tue, 5 Apr 2016 11:53:20 +0200 Subject: [PATCH 150/155] check .pem existence and concat to combined.pem with added eol Checks existince of cert, chain and privkey.pem. Concats these files to combined.pem and adds a linebreak after each file if there were none. This commit doesn't change the LE created .pem files, so no unlinking on the host should happen (see https://github.com/tomav/docker-mailserver/pull/111) --- start-mailserver.sh | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/start-mailserver.sh b/start-mailserver.sh index 010e09b8..8fa74992 100644 --- a/start-mailserver.sh +++ b/start-mailserver.sh @@ -120,17 +120,18 @@ fi case $DMS_SSL in "letsencrypt" ) # letsencrypt folders and files mounted in /etc/letsencrypt - # add eol to all files before concatenation - sed -i -e '$a\' /etc/letsencrypt/live/$(hostname)/cert.pem - sed -i -e '$a\' /etc/letsencrypt/live/$(hostname)/chain.pem - sed -i -e '$a\' /etc/letsencrypt/live/$(hostname)/privkey.pem + if [ -e "/etc/letsencrypt/live/$(hostname)/cert.pem" ] \ + && [ -e "/etc/letsencrypt/live/$(hostname)/chain.pem" ] \ + && [ -e "/etc/letsencrypt/live/$(hostname)/privkey.pem" ]; then + echo "Adding $(hostname) SSL certificate" + # create combined.pem from (cert|chain|privkey).pem with eol after each .pem + sed -e '$a\' -s "/etc/letsencrypt/live/$(hostname)/{cert,chain,privkey}.pem" > "/etc/letsencrypt/live/$(hostname)/combined.pem" # Postfix configuration sed -i -r 's/smtpd_tls_cert_file=\/etc\/ssl\/certs\/ssl-cert-snakeoil.pem/smtpd_tls_cert_file=\/etc\/letsencrypt\/live\/'$(hostname)'\/fullchain.pem/g' /etc/postfix/main.cf sed -i -r 's/smtpd_tls_key_file=\/etc\/ssl\/private\/ssl-cert-snakeoil.key/smtpd_tls_key_file=\/etc\/letsencrypt\/live\/'$(hostname)'\/privkey.pem/g' /etc/postfix/main.cf # Courier configuration - cat "/etc/letsencrypt/live/$(hostname)/cert.pem" "/etc/letsencrypt/live/$(hostname)/chain.pem" "/etc/letsencrypt/live/$(hostname)/privkey.pem" > "/etc/letsencrypt/live/$(hostname)/combined.pem" sed -i -r 's/TLS_CERTFILE=\/etc\/courier\/imapd.pem/TLS_CERTFILE=\/etc\/letsencrypt\/live\/'$(hostname)'\/combined.pem/g' /etc/courier/imapd-ssl # POP3 courier configuration @@ -141,6 +142,7 @@ case $DMS_SSL in echo "SSL configured with letsencrypt certificates" + fi ;; "custom" ) From 25ac07cae74f03a87e9256038cda0fa2640c5805 Mon Sep 17 00:00:00 2001 From: angus Date: Wed, 6 Apr 2016 19:29:39 +0200 Subject: [PATCH 151/155] Introduce the env variable ENABLE_FAIL2BAN. Modified the Makefile so that the containers startup with a short delay between each other. Corrected a small bug in start-mailserver.sh that prevented the correct configuration of the jails. --- Makefile | 5 ++++- start-mailserver.sh | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 03899b5c..6ea1a4d4 100644 --- a/Makefile +++ b/Makefile @@ -21,18 +21,21 @@ run: -e SA_KILL=3.0 \ -e SASL_PASSWD=testing \ -h mail.my-domain.com -t $(NAME) + sleep 15 docker run -d --name mail_pop3 \ -v "`pwd`/postfix":/tmp/postfix \ -v "`pwd`/spamassassin":/tmp/spamassassin \ -v "`pwd`/test":/tmp/test \ -e ENABLE_POP3=1 \ -h mail.my-domain.com -t $(NAME) + sleep 15 docker run -d --name mail_smtponly \ -v "`pwd`/postfix":/tmp/postfix \ -v "`pwd`/spamassassin":/tmp/spamassassin \ -v "`pwd`/test":/tmp/test \ -e SMTP_ONLY=1 \ -h mail.my-domain.com -t $(NAME) + sleep 15 docker run -d --name mail_fail2ban \ -v "`pwd`/postfix":/tmp/postfix \ -v "`pwd`/spamassassin":/tmp/spamassassin \ @@ -40,7 +43,7 @@ run: -e ENABLE_FAIL2BAN=1 \ -h mail.my-domain.com -t $(NAME) # Wait for containers to fully start - sleep 60 + sleep 15 fixtures: # Sending test mails diff --git a/start-mailserver.sh b/start-mailserver.sh index 45ca5259..cff93be2 100644 --- a/start-mailserver.sh +++ b/start-mailserver.sh @@ -240,7 +240,7 @@ awk 'BEGIN{unit=0}{if ($1=="[postfix]" || $1=="[couriersmtp]" || $1=="[courierau else if ($1=="logpath" && unit==1) $3="/var/log/mail/mail.log"; print; if (unit==1 && $1~/\[/ && $1!~/postfix|couriersmtp|courierauth|sasl/) unit=0; -}'/etc/fail2ban/jail.conf > /tmp/jail.conf.new && mv /tmp/jail.conf.new /etc/fail2ban/jail.conf && rm -f /tmp/jail.conf.new +}' /etc/fail2ban/jail.conf > /tmp/jail.conf.new && mv /tmp/jail.conf.new /etc/fail2ban/jail.conf && rm -f /tmp/jail.conf.new # increase ban time and find time to 3h sed -i "/^bantime *=/c\bantime = 10800" /etc/fail2ban/jail.conf From ee0d0853dd672488238eecb0ec2d26719ff45d7d Mon Sep 17 00:00:00 2001 From: angus Date: Thu, 7 Apr 2016 14:20:51 +0200 Subject: [PATCH 152/155] Dovecot based version of the mailserver. Courier and Cyrus Sasl have been removed and substituted with Dovecot which now handle authentication for Postfix, Imap and Pop3, with support for SSL. This allow the use of several encryption schemes for the password as well as a single user db. OpenDKIM keys can now be provided at the startup and will be used instead of generating new ones (so that you don't have to change your DNS configuration). This version builds correctly on Docker but no integration tests have been reworked to accommodate Dovecot instead of Courier and Cyrus Sasl. As such at present no automatic tests can be executed. --- Dockerfile | 17 +- Makefile | 5 +- README.md | 21 +- dovecot/10-auth.conf | 128 ++++++++++++ dovecot/10-logging.conf | 84 ++++++++ dovecot/10-mail.conf | 374 ++++++++++++++++++++++++++++++++++++ dovecot/10-master.conf | 127 ++++++++++++ dovecot/10-ssl.conf | 58 ++++++ dovecot/15-mailboxes.conf | 50 +++++ dovecot/auth-passwdfile.inc | 21 ++ dovecot/dovecot.conf | 102 ++++++++++ postfix/main.cf | 5 +- postfix/master.cf | 3 +- postfix/sasl/smtpd.conf | 4 - start-mailserver.sh | 153 ++++++++------- 15 files changed, 1052 insertions(+), 100 deletions(-) create mode 100644 dovecot/10-auth.conf create mode 100644 dovecot/10-logging.conf create mode 100644 dovecot/10-mail.conf create mode 100644 dovecot/10-master.conf create mode 100644 dovecot/10-ssl.conf create mode 100644 dovecot/15-mailboxes.conf create mode 100644 dovecot/auth-passwdfile.inc create mode 100644 dovecot/dovecot.conf delete mode 100644 postfix/sasl/smtpd.conf diff --git a/Dockerfile b/Dockerfile index 4c893e81..ad0de178 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,20 +4,16 @@ MAINTAINER Thomas VIAL # Packages RUN apt-get update -q --fix-missing RUN apt-get -y upgrade -RUN DEBIAN_FRONTEND=noninteractive apt-get -y install vim postfix sasl2-bin courier-imap courier-imap-ssl \ - courier-pop courier-pop-ssl courier-authdaemon supervisor gamin amavisd-new spamassassin clamav clamav-daemon libnet-dns-perl libmail-spf-perl \ +RUN DEBIAN_FRONTEND=noninteractive apt-get -y install vim postfix dovecot-core dovecot-imapd dovecot-pop3d \ + supervisor gamin amavisd-new spamassassin clamav clamav-daemon libnet-dns-perl libmail-spf-perl \ pyzor razor arj bzip2 cabextract cpio file gzip nomarch p7zip pax unzip zip zoo rsyslog mailutils netcat \ opendkim opendkim-tools opendmarc curl fail2ban RUN apt-get autoclean && rm -rf /var/lib/apt/lists/* -# Configures Saslauthd -RUN rm -rf /var/run/saslauthd && ln -s /var/spool/postfix/var/run/saslauthd /var/run/saslauthd -RUN adduser postfix sasl -RUN echo 'NAME="saslauthd"\nSTART=yes\nMECHANISMS="sasldb"\nTHREADS=0\nPWDIR=/var/spool/postfix/var/run/saslauthd\nPIDFILE="${PWDIR}/saslauthd.pid"\nOPTIONS="-n 0 -c -m /var/spool/postfix/var/run/saslauthd"' > /etc/default/saslauthd - -# Configures Courier -RUN sed -i -r 's/daemons=5/daemons=1/g' /etc/courier/authdaemonrc -RUN sed -i -r 's/authmodulelist="authpam"/authmodulelist="authuserdb"/g' /etc/courier/authdaemonrc +# Configures Dovecot +RUN sed -i -e 's/include_try \/usr\/share\/dovecot\/protocols\.d/include_try \/etc\/dovecot\/protocols\.d/g' /etc/dovecot/dovecot.conf +ADD dovecot/auth-passwdfile.inc /etc/dovecot/conf.d/ +ADD dovecot/10-*.conf /etc/dovecot/conf.d/ # Enables Spamassassin and CRON updates RUN sed -i -r 's/^(CRON|ENABLED)=0/\1=1/g' /etc/default/spamassassin @@ -47,7 +43,6 @@ ADD postfix/default-opendmarc /etc/default/opendmarc # Configures Postfix ADD postfix/main.cf /etc/postfix/main.cf ADD postfix/master.cf /etc/postfix/master.cf -ADD postfix/sasl/smtpd.conf /etc/postfix/sasl/smtpd.conf ADD bin/generate-ssl-certificate /usr/local/bin/generate-ssl-certificate RUN chmod +x /usr/local/bin/generate-ssl-certificate diff --git a/Makefile b/Makefile index 03899b5c..1f5da4ae 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,8 @@ NAME = tvial/docker-mailserver -all: build run fixtures tests clean -all-no-build: run fixtures tests clean +#all: build run fixtures tests clean +#all-no-build: run fixtures tests clean +all: build build: docker build --no-cache -t $(NAME) . diff --git a/README.md b/README.md index acb30ea7..f9c89024 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ Easy to deploy and upgrade. Includes: - postfix with smtp auth -- courier-imap with ssl support +- dovecot for sasl, imap (and optional pop3) with ssl support - amavis - spamassasin supporting custom rules - clamav with automatic updates @@ -17,7 +17,6 @@ Includes: - opendmarc - fail2ban - [LetsEncrypt](https://letsencrypt.org/) and self-signed certificates -- optional pop3 server - [integration tests](https://travis-ci.org/tomav/docker-mailserver) - [automated builds on docker hub](https://hub.docker.com/r/tvial/docker-mailserver/) @@ -45,7 +44,7 @@ Before you open an issue, please have a look this `README`, the [FAQ](https://gi - ./spamassassin:/tmp/spamassassin/ - ./postfix:/tmp/postfix/ - # start he container + # start the container docker-compose up -d mail ## Managing users and aliases @@ -53,12 +52,22 @@ Before you open an issue, please have a look this `README`, the [FAQ](https://gi ### Users Users are managed in `postfix/accounts.cf`. -Just add the full email address and its password separated by a pipe. +Just add the full email address and its encrypted password separated by a pipe. Example: - user1@domain.tld|mypassword - user2@otherdomain.tld|myotherpassword + user1@domain.tld|mypassword-encrypted + user2@otherdomain.tld|myotherpassword-encrypted + +To generate the password you could run for example the following: + + docker run --rm -ti tvial/docker-mailserver doveadm pw -s MD5-CRYPT -u user1@domain.tld + +You will be asked for a password (and for a confirmation of the password). Just copy all the output string in the file `postfix/accounts.cf`. + + The `doveadm pw` command let you choose between several encryption schemes for the password. + Use doveadm pw -l to get a list of the currently supported encryption schemes. + ### Aliases diff --git a/dovecot/10-auth.conf b/dovecot/10-auth.conf new file mode 100644 index 00000000..bfec05ef --- /dev/null +++ b/dovecot/10-auth.conf @@ -0,0 +1,128 @@ +## +## Authentication processes +## + +# Disable LOGIN command and all other plaintext authentications unless +# SSL/TLS is used (LOGINDISABLED capability). Note that if the remote IP +# matches the local IP (ie. you're connecting from the same computer), the +# connection is considered secure and plaintext authentication is allowed. +# See also ssl=required setting. +#disable_plaintext_auth = yes + +# Authentication cache size (e.g. 10M). 0 means it's disabled. Note that +# bsdauth, PAM and vpopmail require cache_key to be set for caching to be used. +#auth_cache_size = 0 +# Time to live for cached data. After TTL expires the cached record is no +# longer used, *except* if the main database lookup returns internal failure. +# We also try to handle password changes automatically: If user's previous +# authentication was successful, but this one wasn't, the cache isn't used. +# For now this works only with plaintext authentication. +#auth_cache_ttl = 1 hour +# TTL for negative hits (user not found, password mismatch). +# 0 disables caching them completely. +#auth_cache_negative_ttl = 1 hour + +# Space separated list of realms for SASL authentication mechanisms that need +# them. You can leave it empty if you don't want to support multiple realms. +# Many clients simply use the first one listed here, so keep the default realm +# first. +#auth_realms = + +# Default realm/domain to use if none was specified. This is used for both +# SASL realms and appending @domain to username in plaintext logins. +#auth_default_realm = + +# List of allowed characters in username. If the user-given username contains +# a character not listed in here, the login automatically fails. This is just +# an extra check to make sure user can't exploit any potential quote escaping +# vulnerabilities with SQL/LDAP databases. If you want to allow all characters, +# set this value to empty. +#auth_username_chars = abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890.-_@ + +# Username character translations before it's looked up from databases. The +# value contains series of from -> to characters. For example "#@/@" means +# that '#' and '/' characters are translated to '@'. +#auth_username_translation = + +# Username formatting before it's looked up from databases. You can use +# the standard variables here, eg. %Lu would lowercase the username, %n would +# drop away the domain if it was given, or "%n-AT-%d" would change the '@' into +# "-AT-". This translation is done after auth_username_translation changes. +#auth_username_format = %Lu + +# If you want to allow master users to log in by specifying the master +# username within the normal username string (ie. not using SASL mechanism's +# support for it), you can specify the separator character here. The format +# is then . UW-IMAP uses "*" as the +# separator, so that could be a good choice. +#auth_master_user_separator = + +# Username to use for users logging in with ANONYMOUS SASL mechanism +#auth_anonymous_username = anonymous + +# Maximum number of dovecot-auth worker processes. They're used to execute +# blocking passdb and userdb queries (eg. MySQL and PAM). They're +# automatically created and destroyed as needed. +#auth_worker_max_count = 30 + +# Host name to use in GSSAPI principal names. The default is to use the +# name returned by gethostname(). Use "$ALL" (with quotes) to allow all keytab +# entries. +#auth_gssapi_hostname = + +# Kerberos keytab to use for the GSSAPI mechanism. Will use the system +# default (usually /etc/krb5.keytab) if not specified. You may need to change +# the auth service to run as root to be able to read this file. +#auth_krb5_keytab = + +# Do NTLM and GSS-SPNEGO authentication using Samba's winbind daemon and +# ntlm_auth helper. +#auth_use_winbind = no + +# Path for Samba's ntlm_auth helper binary. +#auth_winbind_helper_path = /usr/bin/ntlm_auth + +# Time to delay before replying to failed authentications. +#auth_failure_delay = 2 secs + +# Require a valid SSL client certificate or the authentication fails. +#auth_ssl_require_client_cert = no + +# Take the username from client's SSL certificate, using +# X509_NAME_get_text_by_NID() which returns the subject's DN's +# CommonName. +#auth_ssl_username_from_cert = no + +# Space separated list of wanted authentication mechanisms: +# plain login digest-md5 cram-md5 ntlm rpa apop anonymous gssapi otp skey +# gss-spnego +# NOTE: See also disable_plaintext_auth setting. +auth_mechanisms = plain login + +## +## Password and user databases +## + +# +# Password database is used to verify user's password (and nothing more). +# You can have multiple passdbs and userdbs. This is useful if you want to +# allow both system users (/etc/passwd) and virtual users to login without +# duplicating the system users into virtual database. +# +# +# +# User database specifies where mails are located and what user/group IDs +# own them. For single-UID configuration use "static" userdb. +# +# + +#!include auth-deny.conf.ext +#!include auth-master.conf.ext + +#!include auth-system.conf.ext +#!include auth-sql.conf.ext +#!include auth-ldap.conf.ext +!include auth-passwdfile.inc +#!include auth-checkpassword.conf.ext +#!include auth-vpopmail.conf.ext +#!include auth-static.conf.ext diff --git a/dovecot/10-logging.conf b/dovecot/10-logging.conf new file mode 100644 index 00000000..ddc45cef --- /dev/null +++ b/dovecot/10-logging.conf @@ -0,0 +1,84 @@ +## +## Log destination. +## + +# Log file to use for error messages. "syslog" logs to syslog, +# /dev/stderr logs to stderr. +#log_path = syslog + +# Log file to use for informational messages. Defaults to log_path. +#info_log_path = +# Log file to use for debug messages. Defaults to info_log_path. +#debug_log_path = + +# Syslog facility to use if you're logging to syslog. Usually if you don't +# want to use "mail", you'll use local0..local7. Also other standard +# facilities are supported. +#syslog_facility = mail + +## +## Logging verbosity and debugging. +## + +# Log unsuccessful authentication attempts and the reasons why they failed. +auth_verbose = yes + +# In case of password mismatches, log the attempted password. Valid values are +# no, plain and sha1. sha1 can be useful for detecting brute force password +# attempts vs. user simply trying the same password over and over again. +# You can also truncate the value to n chars by appending ":n" (e.g. sha1:6). +auth_verbose_passwords = sha1:6 + +# Even more verbose logging for debugging purposes. Shows for example SQL +# queries. +#auth_debug = no + +# In case of password mismatches, log the passwords and used scheme so the +# problem can be debugged. Enabling this also enables auth_debug. +#auth_debug_passwords = no + +# Enable mail process debugging. This can help you figure out why Dovecot +# isn't finding your mails. +#mail_debug = no + +# Show protocol level SSL errors. +verbose_ssl = no + +# mail_log plugin provides more event logging for mail processes. +plugin { + # Events to log. Also available: flag_change append + #mail_log_events = delete undelete expunge copy mailbox_delete mailbox_rename + # Available fields: uid, box, msgid, from, subject, size, vsize, flags + # size and vsize are available only for expunge and copy events. + #mail_log_fields = uid box msgid size +} + +## +## Log formatting. +## + +# Prefix for each line written to log file. % codes are in strftime(3) +# format. +#log_timestamp = "%b %d %H:%M:%S " + +# Space-separated list of elements we want to log. The elements which have +# a non-empty variable value are joined together to form a comma-separated +# string. +#login_log_format_elements = user=<%u> method=%m rip=%r lip=%l mpid=%e %c + +# Login log format. %s contains login_log_format_elements string, %$ contains +# the data we want to log. +#login_log_format = %$: %s + +# Log prefix for mail processes. See doc/wiki/Variables.txt for list of +# possible variables you can use. +#mail_log_prefix = "%s(%u): " + +# Format to use for logging mail deliveries. You can use variables: +# %$ - Delivery status message (e.g. "saved to INBOX") +# %m - Message-ID +# %s - Subject +# %f - From address +# %p - Physical size +# %w - Virtual size +#deliver_log_format = msgid=%m: %$ diff --git a/dovecot/10-mail.conf b/dovecot/10-mail.conf new file mode 100644 index 00000000..da0a13e9 --- /dev/null +++ b/dovecot/10-mail.conf @@ -0,0 +1,374 @@ +## +## Mailbox locations and namespaces +## + +# Location for users' mailboxes. The default is empty, which means that Dovecot +# tries to find the mailboxes automatically. This won't work if the user +# doesn't yet have any mail, so you should explicitly tell Dovecot the full +# location. +# +# If you're using mbox, giving a path to the INBOX file (eg. /var/mail/%u) +# isn't enough. You'll also need to tell Dovecot where the other mailboxes are +# kept. This is called the "root mail directory", and it must be the first +# path given in the mail_location setting. +# +# There are a few special variables you can use, eg.: +# +# %u - username +# %n - user part in user@domain, same as %u if there's no domain +# %d - domain part in user@domain, empty if there's no domain +# %h - home directory +# +# See doc/wiki/Variables.txt for full list. Some examples: +# +# mail_location = maildir:~/Maildir +# mail_location = mbox:~/mail:INBOX=/var/mail/%u +# mail_location = mbox:/var/mail/%d/%1n/%n:INDEX=/var/indexes/%d/%1n/%n +# +# +# +mail_location = maildir:/var/mail/%d/%n + +# If you need to set multiple mailbox locations or want to change default +# namespace settings, you can do it by defining namespace sections. +# +# You can have private, shared and public namespaces. Private namespaces +# are for user's personal mails. Shared namespaces are for accessing other +# users' mailboxes that have been shared. Public namespaces are for shared +# mailboxes that are managed by sysadmin. If you create any shared or public +# namespaces you'll typically want to enable ACL plugin also, otherwise all +# users can access all the shared mailboxes, assuming they have permissions +# on filesystem level to do so. +namespace inbox { + # Namespace type: private, shared or public + #type = private + + # Hierarchy separator to use. You should use the same separator for all + # namespaces or some clients get confused. '/' is usually a good one. + # The default however depends on the underlying mail storage format. + #separator = + + # Prefix required to access this namespace. This needs to be different for + # all namespaces. For example "Public/". + #prefix = + + # Physical location of the mailbox. This is in same format as + # mail_location, which is also the default for it. + #location = + + # There can be only one INBOX, and this setting defines which namespace + # has it. + inbox = yes + + # If namespace is hidden, it's not advertised to clients via NAMESPACE + # extension. You'll most likely also want to set list=no. This is mostly + # useful when converting from another server with different namespaces which + # you want to deprecate but still keep working. For example you can create + # hidden namespaces with prefixes "~/mail/", "~%u/mail/" and "mail/". + #hidden = no + + # Show the mailboxes under this namespace with LIST command. This makes the + # namespace visible for clients that don't support NAMESPACE extension. + # "children" value lists child mailboxes, but hides the namespace prefix. + #list = yes + + # Namespace handles its own subscriptions. If set to "no", the parent + # namespace handles them (empty prefix should always have this as "yes") + #subscriptions = yes +} + +# Example shared namespace configuration +#namespace { + #type = shared + #separator = / + + # Mailboxes are visible under "shared/user@domain/" + # %%n, %%d and %%u are expanded to the destination user. + #prefix = shared/%%u/ + + # Mail location for other users' mailboxes. Note that %variables and ~/ + # expands to the logged in user's data. %%n, %%d, %%u and %%h expand to the + # destination user's data. + #location = maildir:%%h/Maildir:INDEX=~/Maildir/shared/%%u + + # Use the default namespace for saving subscriptions. + #subscriptions = no + + # List the shared/ namespace only if there are visible shared mailboxes. + #list = children +#} +# Should shared INBOX be visible as "shared/user" or "shared/user/INBOX"? +#mail_shared_explicit_inbox = no + +# System user and group used to access mails. If you use multiple, userdb +# can override these by returning uid or gid fields. You can use either numbers +# or names. +#mail_uid = +#mail_gid = + +# Group to enable temporarily for privileged operations. Currently this is +# used only with INBOX when either its initial creation or dotlocking fails. +# Typically this is set to "mail" to give access to /var/mail. +mail_privileged_group = docker + +# Grant access to these supplementary groups for mail processes. Typically +# these are used to set up access to shared mailboxes. Note that it may be +# dangerous to set these if users can create symlinks (e.g. if "mail" group is +# set here, ln -s /var/mail ~/mail/var could allow a user to delete others' +# mailboxes, or ln -s /secret/shared/box ~/mail/mybox would allow reading it). +#mail_access_groups = + +# Allow full filesystem access to clients. There's no access checks other than +# what the operating system does for the active UID/GID. It works with both +# maildir and mboxes, allowing you to prefix mailboxes names with eg. /path/ +# or ~user/. +#mail_full_filesystem_access = no + +# Dictionary for key=value mailbox attributes. Currently used by URLAUTH, but +# soon intended to be used by METADATA as well. +#mail_attribute_dict = + +## +## Mail processes +## + +# Don't use mmap() at all. This is required if you store indexes to shared +# filesystems (NFS or clustered filesystem). +#mmap_disable = no + +# Rely on O_EXCL to work when creating dotlock files. NFS supports O_EXCL +# since version 3, so this should be safe to use nowadays by default. +#dotlock_use_excl = yes + +# When to use fsync() or fdatasync() calls: +# optimized (default): Whenever necessary to avoid losing important data +# always: Useful with e.g. NFS when write()s are delayed +# never: Never use it (best performance, but crashes can lose data) +#mail_fsync = optimized + +# Mail storage exists in NFS. Set this to yes to make Dovecot flush NFS caches +# whenever needed. If you're using only a single mail server this isn't needed. +#mail_nfs_storage = no +# Mail index files also exist in NFS. Setting this to yes requires +# mmap_disable=yes and fsync_disable=no. +#mail_nfs_index = no + +# Locking method for index files. Alternatives are fcntl, flock and dotlock. +# Dotlocking uses some tricks which may create more disk I/O than other locking +# methods. NFS users: flock doesn't work, remember to change mmap_disable. +#lock_method = fcntl + +# Directory in which LDA/LMTP temporarily stores incoming mails >128 kB. +#mail_temp_dir = /tmp + +# Valid UID range for users, defaults to 500 and above. This is mostly +# to make sure that users can't log in as daemons or other system users. +# Note that denying root logins is hardcoded to dovecot binary and can't +# be done even if first_valid_uid is set to 0. +#first_valid_uid = 500 +#last_valid_uid = 0 + +# Valid GID range for users, defaults to non-root/wheel. Users having +# non-valid GID as primary group ID aren't allowed to log in. If user +# belongs to supplementary groups with non-valid GIDs, those groups are +# not set. +#first_valid_gid = 1 +#last_valid_gid = 0 + +# Maximum allowed length for mail keyword name. It's only forced when trying +# to create new keywords. +#mail_max_keyword_length = 50 + +# ':' separated list of directories under which chrooting is allowed for mail +# processes (ie. /var/mail will allow chrooting to /var/mail/foo/bar too). +# This setting doesn't affect login_chroot, mail_chroot or auth chroot +# settings. If this setting is empty, "/./" in home dirs are ignored. +# WARNING: Never add directories here which local users can modify, that +# may lead to root exploit. Usually this should be done only if you don't +# allow shell access for users. +#valid_chroot_dirs = + +# Default chroot directory for mail processes. This can be overridden for +# specific users in user database by giving /./ in user's home directory +# (eg. /home/./user chroots into /home). Note that usually there is no real +# need to do chrooting, Dovecot doesn't allow users to access files outside +# their mail directory anyway. If your home directories are prefixed with +# the chroot directory, append "/." to mail_chroot. +#mail_chroot = + +# UNIX socket path to master authentication server to find users. +# This is used by imap (for shared users) and lda. +#auth_socket_path = /var/run/dovecot/auth-userdb + +# Directory where to look up mail plugins. +#mail_plugin_dir = /usr/lib/dovecot/modules + +# Space separated list of plugins to load for all services. Plugins specific to +# IMAP, LDA, etc. are added to this list in their own .conf files. +#mail_plugins = + +## +## Mailbox handling optimizations +## + +# Mailbox list indexes can be used to optimize IMAP STATUS commands. They are +# also required for IMAP NOTIFY extension to be enabled. +#mailbox_list_index = no + +# The minimum number of mails in a mailbox before updates are done to cache +# file. This allows optimizing Dovecot's behavior to do less disk writes at +# the cost of more disk reads. +#mail_cache_min_mail_count = 0 + +# When IDLE command is running, mailbox is checked once in a while to see if +# there are any new mails or other changes. This setting defines the minimum +# time to wait between those checks. Dovecot can also use dnotify, inotify and +# kqueue to find out immediately when changes occur. +#mailbox_idle_check_interval = 30 secs + +# Save mails with CR+LF instead of plain LF. This makes sending those mails +# take less CPU, especially with sendfile() syscall with Linux and FreeBSD. +# But it also creates a bit more disk I/O which may just make it slower. +# Also note that if other software reads the mboxes/maildirs, they may handle +# the extra CRs wrong and cause problems. +#mail_save_crlf = no + +# Max number of mails to keep open and prefetch to memory. This only works with +# some mailbox formats and/or operating systems. +#mail_prefetch_count = 0 + +# How often to scan for stale temporary files and delete them (0 = never). +# These should exist only after Dovecot dies in the middle of saving mails. +#mail_temp_scan_interval = 1w + +## +## Maildir-specific settings +## + +# By default LIST command returns all entries in maildir beginning with a dot. +# Enabling this option makes Dovecot return only entries which are directories. +# This is done by stat()ing each entry, so it causes more disk I/O. +# (For systems setting struct dirent->d_type, this check is free and it's +# done always regardless of this setting) +#maildir_stat_dirs = no + +# When copying a message, do it with hard links whenever possible. This makes +# the performance much better, and it's unlikely to have any side effects. +#maildir_copy_with_hardlinks = yes + +# Assume Dovecot is the only MUA accessing Maildir: Scan cur/ directory only +# when its mtime changes unexpectedly or when we can't find the mail otherwise. +#maildir_very_dirty_syncs = no + +# If enabled, Dovecot doesn't use the S= in the Maildir filenames for +# getting the mail's physical size, except when recalculating Maildir++ quota. +# This can be useful in systems where a lot of the Maildir filenames have a +# broken size. The performance hit for enabling this is very small. +#maildir_broken_filename_sizes = no + +## +## mbox-specific settings +## + +# Which locking methods to use for locking mbox. There are four available: +# dotlock: Create .lock file. This is the oldest and most NFS-safe +# solution. If you want to use /var/mail/ like directory, the users +# will need write access to that directory. +# dotlock_try: Same as dotlock, but if it fails because of permissions or +# because there isn't enough disk space, just skip it. +# fcntl : Use this if possible. Works with NFS too if lockd is used. +# flock : May not exist in all systems. Doesn't work with NFS. +# lockf : May not exist in all systems. Doesn't work with NFS. +# +# You can use multiple locking methods; if you do the order they're declared +# in is important to avoid deadlocks if other MTAs/MUAs are using multiple +# locking methods as well. Some operating systems don't allow using some of +# them simultaneously. +# +# The Debian value for mbox_write_locks differs from upstream Dovecot. It is +# changed to be compliant with Debian Policy (section 11.6) for NFS safety. +# Dovecot: mbox_write_locks = dotlock fcntl +# Debian: mbox_write_locks = fcntl dotlock +# +#mbox_read_locks = fcntl +#mbox_write_locks = fcntl dotlock + +# Maximum time to wait for lock (all of them) before aborting. +#mbox_lock_timeout = 5 mins + +# If dotlock exists but the mailbox isn't modified in any way, override the +# lock file after this much time. +#mbox_dotlock_change_timeout = 2 mins + +# When mbox changes unexpectedly we have to fully read it to find out what +# changed. If the mbox is large this can take a long time. Since the change +# is usually just a newly appended mail, it'd be faster to simply read the +# new mails. If this setting is enabled, Dovecot does this but still safely +# fallbacks to re-reading the whole mbox file whenever something in mbox isn't +# how it's expected to be. The only real downside to this setting is that if +# some other MUA changes message flags, Dovecot doesn't notice it immediately. +# Note that a full sync is done with SELECT, EXAMINE, EXPUNGE and CHECK +# commands. +#mbox_dirty_syncs = yes + +# Like mbox_dirty_syncs, but don't do full syncs even with SELECT, EXAMINE, +# EXPUNGE or CHECK commands. If this is set, mbox_dirty_syncs is ignored. +#mbox_very_dirty_syncs = no + +# Delay writing mbox headers until doing a full write sync (EXPUNGE and CHECK +# commands and when closing the mailbox). This is especially useful for POP3 +# where clients often delete all mails. The downside is that our changes +# aren't immediately visible to other MUAs. +#mbox_lazy_writes = yes + +# If mbox size is smaller than this (e.g. 100k), don't write index files. +# If an index file already exists it's still read, just not updated. +#mbox_min_index_size = 0 + +# Mail header selection algorithm to use for MD5 POP3 UIDLs when +# pop3_uidl_format=%m. For backwards compatibility we use apop3d inspired +# algorithm, but it fails if the first Received: header isn't unique in all +# mails. An alternative algorithm is "all" that selects all headers. +#mbox_md5 = apop3d + +## +## mdbox-specific settings +## + +# Maximum dbox file size until it's rotated. +#mdbox_rotate_size = 2M + +# Maximum dbox file age until it's rotated. Typically in days. Day begins +# from midnight, so 1d = today, 2d = yesterday, etc. 0 = check disabled. +#mdbox_rotate_interval = 0 + +# When creating new mdbox files, immediately preallocate their size to +# mdbox_rotate_size. This setting currently works only in Linux with some +# filesystems (ext4, xfs). +#mdbox_preallocate_space = no + +## +## Mail attachments +## + +# sdbox and mdbox support saving mail attachments to external files, which +# also allows single instance storage for them. Other backends don't support +# this for now. + +# Directory root where to store mail attachments. Disabled, if empty. +#mail_attachment_dir = + +# Attachments smaller than this aren't saved externally. It's also possible to +# write a plugin to disable saving specific attachments externally. +#mail_attachment_min_size = 128k + +# Filesystem backend to use for saving attachments: +# posix : No SiS done by Dovecot (but this might help FS's own deduplication) +# sis posix : SiS with immediate byte-by-byte comparison during saving +# sis-queue posix : SiS with delayed comparison and deduplication +#mail_attachment_fs = sis posix + +# Hash format to use in attachment filenames. You can add any text and +# variables: %{md4}, %{md5}, %{sha1}, %{sha256}, %{sha512}, %{size}. +# Variables can be truncated, e.g. %{sha256:80} returns only first 80 bits +#mail_attachment_hash = %{sha1} diff --git a/dovecot/10-master.conf b/dovecot/10-master.conf new file mode 100644 index 00000000..48707827 --- /dev/null +++ b/dovecot/10-master.conf @@ -0,0 +1,127 @@ +#default_process_limit = 100 +#default_client_limit = 1000 + +# Default VSZ (virtual memory size) limit for service processes. This is mainly +# intended to catch and kill processes that leak memory before they eat up +# everything. +#default_vsz_limit = 256M + +# Login user is internally used by login processes. This is the most untrusted +# user in Dovecot system. It shouldn't have access to anything at all. +#default_login_user = dovenull + +# Internal user is used by unprivileged processes. It should be separate from +# login user, so that login processes can't disturb other processes. +#default_internal_user = dovecot + +service imap-login { + inet_listener imap { + #port = 143 + } + inet_listener imaps { + #port = 993 + #ssl = yes + } + + # Number of connections to handle before starting a new process. Typically + # the only useful values are 0 (unlimited) or 1. 1 is more secure, but 0 + # is faster. + #service_count = 1 + + # Number of processes to always keep waiting for more connections. + #process_min_avail = 0 + + # If you set service_count=0, you probably need to grow this. + #vsz_limit = $default_vsz_limit +} + +service pop3-login { + inet_listener pop3 { + #port = 110 + } + inet_listener pop3s { + #port = 995 + #ssl = yes + } +} + +service lmtp { + unix_listener lmtp { + #mode = 0666 + } + + # Create inet listener only if you can't use the above UNIX socket + #inet_listener lmtp { + # Avoid making LMTP visible for the entire internet + #address = + #port = + #} +} + +service imap { + # Most of the memory goes to mmap()ing files. You may need to increase this + # limit if you have huge mailboxes. + #vsz_limit = $default_vsz_limit + + # Max. number of IMAP processes (connections) + #process_limit = 1024 +} + +service pop3 { + # Max. number of POP3 processes (connections) + #process_limit = 1024 +} + +service auth { + # auth_socket_path points to this userdb socket by default. It's typically + # used by dovecot-lda, doveadm, possibly imap process, etc. Users that have + # full permissions to this socket are able to get a list of all usernames and + # get the results of everyone's userdb lookups. + # + # The default 0666 mode allows anyone to connect to the socket, but the + # userdb lookups will succeed only if the userdb returns an "uid" field that + # matches the caller process's UID. Also if caller's uid or gid matches the + # socket's uid or gid the lookup succeeds. Anything else causes a failure. + # + # To give the caller full permissions to lookup all users, set the mode to + # something else than 0666 and Dovecot lets the kernel enforce the + # permissions (e.g. 0777 allows everyone full permissions). + unix_listener auth-userdb { + mode = 0666 + user = docker + group = docker + } + + unix_listener auth-master { + mode = 0600 + user = docker + group = docker + } + + # Postfix smtp-auth + unix_listener /var/spool/postfix/private/auth { + mode = 0666 + user = docker + group = docker + } + + # Auth process is run as this user. + #user = $default_internal_user +} + +service auth-worker { + # Auth worker process is run as root by default, so that it can access + # /etc/shadow. If this isn't necessary, the user should be changed to + # $default_internal_user. + #user = root +} + +service dict { + # If dict proxy is used, mail processes should have access to its socket. + # For example: mode=0660, group=vmail and global mail_access_groups=vmail + unix_listener dict { + #mode = 0600 + #user = + #group = + } +} diff --git a/dovecot/10-ssl.conf b/dovecot/10-ssl.conf new file mode 100644 index 00000000..8873bc25 --- /dev/null +++ b/dovecot/10-ssl.conf @@ -0,0 +1,58 @@ +## +## SSL settings +## + +# SSL/TLS support: yes, no, required. +#ssl = yes + +# PEM encoded X.509 SSL/TLS certificate and private key. They're opened before +# dropping root privileges, so keep the key file unreadable by anyone but +# root. Included doc/mkcert.sh can be used to easily generate self-signed +# certificate, just make sure to update the domains in dovecot-openssl.cnf +ssl_cert = + +passdb { + driver = passwd-file + args = scheme=CRYPT username_format=%u /etc/dovecot/userdb +} + +userdb { + driver = passwd-file + args = username_format=%u /etc/dovecot/userdb + + # Default fields that can be overridden by passwd-file + #default_fields = quota_rule=*:storage=1G + default_fields = uid=docker gid=docker home=/var/mail/%d/%u + + # Override fields from passwd-file + #override_fields = home=/home/virtual/%u +} diff --git a/dovecot/dovecot.conf b/dovecot/dovecot.conf new file mode 100644 index 00000000..5a35e5fe --- /dev/null +++ b/dovecot/dovecot.conf @@ -0,0 +1,102 @@ +## Dovecot configuration file + +# If you're in a hurry, see http://wiki2.dovecot.org/QuickConfiguration + +# "doveconf -n" command gives a clean output of the changed settings. Use it +# instead of copy&pasting files when posting to the Dovecot mailing list. + +# '#' character and everything after it is treated as comments. Extra spaces +# and tabs are ignored. If you want to use either of these explicitly, put the +# value inside quotes, eg.: key = "# char and trailing whitespace " + +# Most (but not all) settings can be overridden by different protocols and/or +# source/destination IPs by placing the settings inside sections, for example: +# protocol imap { }, local 127.0.0.1 { }, remote 10.0.0.0/8 { } + +# Default values are shown for each setting, it's not required to uncomment +# those. These are exceptions to this though: No sections (e.g. namespace {}) +# or plugin settings are added by default, they're listed only as examples. +# Paths are also just examples with the real defaults being based on configure +# options. The paths listed here are for configure --prefix=/usr +# --sysconfdir=/etc --localstatedir=/var + +# Enable installed protocols +!include_try /etc/dovecot/protocols.d/*.protocol + +# A comma separated list of IPs or hosts where to listen in for connections. +# "*" listens in all IPv4 interfaces, "::" listens in all IPv6 interfaces. +# If you want to specify non-default ports or anything more complex, +# edit conf.d/master.conf. +#listen = *, :: + +# Base directory where to store runtime data. +#base_dir = /var/run/dovecot/ + +# Name of this instance. In multi-instance setup doveadm and other commands +# can use -i to select which instance is used (an alternative +# to -c ). The instance name is also added to Dovecot processes +# in ps output. +#instance_name = dovecot + +# Greeting message for clients. +#login_greeting = Dovecot ready. + +# Space separated list of trusted network ranges. Connections from these +# IPs are allowed to override their IP addresses and ports (for logging and +# for authentication checks). disable_plaintext_auth is also ignored for +# these networks. Typically you'd specify your IMAP proxy servers here. +#login_trusted_networks = + +# Space separated list of login access check sockets (e.g. tcpwrap) +#login_access_sockets = + +# With proxy_maybe=yes if proxy destination matches any of these IPs, don't do +# proxying. This isn't necessary normally, but may be useful if the destination +# IP is e.g. a load balancer's IP. +#auth_proxy_self = + +# Show more verbose process titles (in ps). Currently shows user name and +# IP address. Useful for seeing who are actually using the IMAP processes +# (eg. shared mailboxes or if same uid is used for multiple accounts). +#verbose_proctitle = no + +# Should all processes be killed when Dovecot master process shuts down. +# Setting this to "no" means that Dovecot can be upgraded without +# forcing existing client connections to close (although that could also be +# a problem if the upgrade is e.g. because of a security fix). +#shutdown_clients = yes + +# If non-zero, run mail commands via this many connections to doveadm server, +# instead of running them directly in the same process. +#doveadm_worker_count = 0 +# UNIX socket or host:port used for connecting to doveadm server +#doveadm_socket_path = doveadm-server + +# Space separated list of environment variables that are preserved on Dovecot +# startup and passed down to all of its child processes. You can also give +# key=value pairs to always set specific settings. +#import_environment = TZ + +## +## Dictionary server settings +## + +# Dictionary can be used to store key=value lists. This is used by several +# plugins. The dictionary can be accessed either directly or though a +# dictionary server. The following dict block maps dictionary names to URIs +# when the server is used. These can then be referenced using URIs in format +# "proxy::". + +dict { + #quota = mysql:/etc/dovecot/dovecot-dict-sql.conf.ext + #expire = sqlite:/etc/dovecot/dovecot-dict-sql.conf.ext +} + +# Most of the actual configuration gets included below. The filenames are +# first sorted by their ASCII value and parsed in that order. The 00-prefixes +# in filenames are intended to make it easier to understand the ordering. +!include conf.d/*.conf + +# A config file can also tried to be included without giving an error if +# it's not found: +#!include_try local.conf diff --git a/postfix/main.cf b/postfix/main.cf index 593b6394..c1451c46 100644 --- a/postfix/main.cf +++ b/postfix/main.cf @@ -40,11 +40,10 @@ smtpd_tls_exclude_ciphers = aNULL, LOW, EXP, MEDIUM, ADH, AECDH, MD5, DSS, ECDSA # SASL smtpd_sasl_auth_enable = yes -smtpd_sasl_path = smtpd -smtpd_sasl_type = cyrus +smtpd_sasl_path = private/auth +smtpd_sasl_type = dovecot smtpd_sasl_security_options = noanonymous smtpd_sasl_local_domain = $myhostname -cyrus_sasl_config_path = /etc/postfix/sasl broken_sasl_auth_clients = yes # Mail directory diff --git a/postfix/master.cf b/postfix/master.cf index b2fe0de9..a8078d5b 100644 --- a/postfix/master.cf +++ b/postfix/master.cf @@ -15,9 +15,10 @@ submission inet n - n - - smtpd -o syslog_name=postfix/submission -o smtpd_tls_security_level=encrypt -o smtpd_sasl_auth_enable=yes + -o smtpd_sasl_type=dovecot + -o smtpd_sasl_path=private/auth -o smtpd_reject_unlisted_recipient=no -o smtpd_sasl_authenticated_header=yes - -o smtpd_relay_restrictions=permit_sasl_authenticated,reject -o smtpd_client_restrictions=permit_sasl_authenticated,reject -o smtpd_relay_restrictions=permit_sasl_authenticated,reject -o milter_macro_daemon_name=ORIGINATING diff --git a/postfix/sasl/smtpd.conf b/postfix/sasl/smtpd.conf deleted file mode 100644 index f02eb91d..00000000 --- a/postfix/sasl/smtpd.conf +++ /dev/null @@ -1,4 +0,0 @@ -pwcheck_method: auxprop -auxprop_plugin: sasldb -mech_list: PLAIN LOGIN CRAM-MD5 DIGEST-MD5 -log_level: 7 diff --git a/start-mailserver.sh b/start-mailserver.sh index 010e09b8..84e4351d 100644 --- a/start-mailserver.sh +++ b/start-mailserver.sh @@ -11,8 +11,20 @@ if [ -f /tmp/postfix/accounts.cf ]; then # Checking that /tmp/postfix/accounts.cf ends with a newline sed -i -e '$a\' /tmp/postfix/accounts.cf + # Configuring Dovecot + echo -n > /etc/dovecot/userdb + chown dovecot:dovecot /etc/dovecot/userdb + chmod 640 /etc/dovecot/userdb + cp -a /usr/share/dovecot/protocols.d /etc/dovecot/ + # Disable pop3 (it will be eventually enabled later in the script, if requested) + mv /etc/dovecot/protocols.d/pop3d.protocol /etc/dovecot/protocols.d/pop3d.protocol.disab + sed -i -e 's/#ssl = yes/ssl = yes/g' /etc/dovecot/conf.d/10-master.conf + sed -i -e 's/#port = 993/port = 993/g' /etc/dovecot/conf.d/10-master.conf + sed -i -e 's/#port = 995/port = 995/g' /etc/dovecot/conf.d/10-master.conf + sed -i -e 's/#ssl = yes/ssl = required/g' /etc/dovecot/conf.d/10-ssl.conf # Creating users + # pass is encrypted while IFS=$'|' read login pass do # Setting variables for better readability @@ -21,22 +33,22 @@ if [ -f /tmp/postfix/accounts.cf ]; then # Let's go! echo "user '${user}' for domain '${domain}' with password '********'" echo "${login} ${domain}/${user}/" >> /etc/postfix/vmailbox - /usr/sbin/userdb ${login} set uid=5000 gid=5000 home=/var/mail/${domain}/${user} mail=/var/mail/${domain}/${user} - echo "${pass}" | userdbpw -md5 | userdb ${login} set systempw - echo "${pass}" | saslpasswd2 -p -c -u ${domain} ${login} + # user database for dovecot has the following format: + # user:password:uid:gid:(gecos):home:(shell):extra_fields + # Example : ${login}:${pass}:5000:5000::/var/mail/${domain}/${user}::userdb_mail=maildir:/var/mail/${domain}/${user} + echo "${login}:${pass}:5000:5000::/var/mail/${domain}/${user}::" >> /etc/dovecot/userdb mkdir -p /var/mail/${domain} if [ ! -d "/var/mail/${domain}/${user}" ]; then - maildirmake "/var/mail/${domain}/${user}" - maildirmake "/var/mail/${domain}/${user}/.Sent" - maildirmake "/var/mail/${domain}/${user}/.Trash" - maildirmake "/var/mail/${domain}/${user}/.Drafts" - echo -e "INBOX\nINBOX.Sent\nINBOX.Trash\nInbox.Drafts" >> "/var/mail/${domain}/${user}/courierimapsubscribed" + maildirmake.dovecot "/var/mail/${domain}/${user}" + maildirmake.dovecot "/var/mail/${domain}/${user}/.Sent" + maildirmake.dovecot "/var/mail/${domain}/${user}/.Trash" + maildirmake.dovecot "/var/mail/${domain}/${user}/.Drafts" + echo -e "INBOX\nSent\nTrash\nDrafts" >> "/var/mail/${domain}/${user}/subscriptions" touch "/var/mail/${domain}/${user}/.Sent/maildirfolder" fi echo ${domain} >> /tmp/vhost.tmp done < /tmp/postfix/accounts.cf - makeuserdb else echo "==> Warning: '/tmp/postfix/accounts.cf' is not provided. No mail account created." fi @@ -63,39 +75,46 @@ touch /etc/postfix/vmailbox && postmap /etc/postfix/vmailbox touch /etc/postfix/virtual && postmap /etc/postfix/virtual # DKIM -grep -vE '^(\s*$|#)' /etc/postfix/vhost | while read domainname; do - mkdir -p /etc/opendkim/keys/$domainname - if [ ! -f "/etc/opendkim/keys/$domainname/mail.private" ]; then - echo "Creating DKIM private key /etc/opendkim/keys/$domainname/mail.private" - pushd /etc/opendkim/keys/$domainname - opendkim-genkey --subdomains --domain=$domainname --selector=mail - popd - echo "" - echo "DKIM PUBLIC KEY ################################################################" - cat /etc/opendkim/keys/$domainname/mail.txt - echo "################################################################################" - fi - # Write to KeyTable if necessary - keytableentry="mail._domainkey.$domainname $domainname:mail:/etc/opendkim/keys/$domainname/mail.private" - if [ ! -f "/etc/opendkim/KeyTable" ]; then - echo "Creating DKIM KeyTable" - echo "mail._domainkey.$domainname $domainname:mail:/etc/opendkim/keys/$domainname/mail.private" > /etc/opendkim/KeyTable - else - if ! grep -q "$keytableentry" "/etc/opendkim/KeyTable" ; then - echo $keytableentry >> /etc/opendkim/KeyTable +# Check if keys are already available +if [ -e "/tmp/postfix/opendkim/KeyTable" ]; then + mkdir -p /etc/opendkim + cp -a /tmp/postfix/opendkim/* /etc/opendkim/ + echo "DKIM keys added for : `ls -C /etc/opendkim/keys/`" +else + grep -vE '^(\s*$|#)' /etc/postfix/vhost | while read domainname; do + mkdir -p /etc/opendkim/keys/$domainname + if [ ! -f "/etc/opendkim/keys/$domainname/mail.private" ]; then + echo "Creating DKIM private key /etc/opendkim/keys/$domainname/mail.private" + pushd /etc/opendkim/keys/$domainname + opendkim-genkey --subdomains --domain=$domainname --selector=mail + popd + echo "" + echo "DKIM PUBLIC KEY ################################################################" + cat /etc/opendkim/keys/$domainname/mail.txt + echo "################################################################################" fi - fi - # Write to SigningTable if necessary - signingtableentry="*@$domainname mail._domainkey.$domainname" - if [ ! -f "/etc/opendkim/SigningTable" ]; then - echo "Creating DKIM SigningTable" - echo "*@$domainname mail._domainkey.$domainname" > /etc/opendkim/SigningTable - else - if ! grep -q "$signingtableentry" "/etc/opendkim/SigningTable" ; then - echo $signingtableentry >> /etc/opendkim/SigningTable + # Write to KeyTable if necessary + keytableentry="mail._domainkey.$domainname $domainname:mail:/etc/opendkim/keys/$domainname/mail.private" + if [ ! -f "/etc/opendkim/KeyTable" ]; then + echo "Creating DKIM KeyTable" + echo "mail._domainkey.$domainname $domainname:mail:/etc/opendkim/keys/$domainname/mail.private" > /etc/opendkim/KeyTable + else + if ! grep -q "$keytableentry" "/etc/opendkim/KeyTable" ; then + echo $keytableentry >> /etc/opendkim/KeyTable + fi fi - fi -done + # Write to SigningTable if necessary + signingtableentry="*@$domainname mail._domainkey.$domainname" + if [ ! -f "/etc/opendkim/SigningTable" ]; then + echo "Creating DKIM SigningTable" + echo "*@$domainname mail._domainkey.$domainname" > /etc/opendkim/SigningTable + else + if ! grep -q "$signingtableentry" "/etc/opendkim/SigningTable" ; then + echo $signingtableentry >> /etc/opendkim/SigningTable + fi + fi + done +fi echo "Changing permissions on /etc/opendkim" # chown entire directory @@ -104,7 +123,7 @@ chown -R opendkim:opendkim /etc/opendkim/ chmod -R 0700 /etc/opendkim/keys/ # DMARC -# if ther is no AuthservID create it +# if there is no AuthservID create it if [ `cat /etc/opendmarc.conf | grep -w AuthservID | wc -l` -eq 0 ]; then echo "AuthservID $(hostname)" >> /etc/opendmarc.conf fi @@ -129,15 +148,9 @@ case $DMS_SSL in sed -i -r 's/smtpd_tls_cert_file=\/etc\/ssl\/certs\/ssl-cert-snakeoil.pem/smtpd_tls_cert_file=\/etc\/letsencrypt\/live\/'$(hostname)'\/fullchain.pem/g' /etc/postfix/main.cf sed -i -r 's/smtpd_tls_key_file=\/etc\/ssl\/private\/ssl-cert-snakeoil.key/smtpd_tls_key_file=\/etc\/letsencrypt\/live\/'$(hostname)'\/privkey.pem/g' /etc/postfix/main.cf - # Courier configuration - cat "/etc/letsencrypt/live/$(hostname)/cert.pem" "/etc/letsencrypt/live/$(hostname)/chain.pem" "/etc/letsencrypt/live/$(hostname)/privkey.pem" > "/etc/letsencrypt/live/$(hostname)/combined.pem" - sed -i -r 's/TLS_CERTFILE=\/etc\/courier\/imapd.pem/TLS_CERTFILE=\/etc\/letsencrypt\/live\/'$(hostname)'\/combined.pem/g' /etc/courier/imapd-ssl - - # POP3 courier configuration - sed -i -r 's/POP3_TLS_REQUIRED=0/POP3_TLS_REQUIRED=1/g' /etc/courier/pop3d-ssl - sed -i -r 's/TLS_CERTFILE=\/etc\/courier\/pop3d.pem/TLS_CERTFILE=\/etc\/letsencrypt\/live\/'$(hostname)'\/combined.pem/g' /etc/courier/pop3d-ssl - # needed to support gmail - sed -i -r 's/TLS_TRUSTCERTS=\/etc\/ssl\/certs/TLS_TRUSTCERTS=\/etc\/letsencrypt\/live\/'$(hostname)'\/fullchain.pem/g' /etc/courier/pop3d-ssl + # Dovecot configuration + sed -i -e 's/ssl_cert = <\/etc\/dovecot\/dovecot\.pem/ssl_cert = <\/etc\/letsencrypt\/live\/'$(hostname)'\/fullchain\.pem/g' /etc/dovecot/conf.d/10-ssl.conf + sed -i -e 's/ssl_key = <\/etc\/dovecot\/private\/dovecot\.pem/ssl_key = <\/etc\/letsencrypt\/live\/'$(hostname)'\/privkey\.pem/g' /etc/dovecot/conf.d/10-ssl.conf echo "SSL configured with letsencrypt certificates" @@ -154,12 +167,9 @@ case $DMS_SSL in sed -i -r 's/smtpd_tls_cert_file=\/etc\/ssl\/certs\/ssl-cert-snakeoil.pem/smtpd_tls_cert_file=\/etc\/postfix\/ssl\/'$(hostname)'-full.pem/g' /etc/postfix/main.cf sed -i -r 's/smtpd_tls_key_file=\/etc\/ssl\/private\/ssl-cert-snakeoil.key/smtpd_tls_key_file=\/etc\/postfix\/ssl\/'$(hostname)'-full.pem/g' /etc/postfix/main.cf - # Courier configuration - sed -i -r 's/TLS_CERTFILE=\/etc\/courier\/imapd.pem/TLS_CERTFILE=\/etc\/postfix\/ssl\/'$(hostname)'-full.pem/g' /etc/courier/imapd-ssl - - # POP3 courier configuration - sed -i -r 's/POP3_TLS_REQUIRED=0/POP3_TLS_REQUIRED=1/g' /etc/courier/pop3d-ssl - sed -i -r 's/TLS_CERTFILE=\/etc\/courier\/pop3d.pem/TLS_CERTFILE=\/etc\/postfix\/ssl\/'$(hostname)'-full.pem/g' /etc/courier/pop3d-ssl + # Dovecot configuration + sed -i -e 's/ssl_cert = <\/etc\/dovecot\/dovecot\.pem/ssl_cert = <\/etc\/postfix\/ssl\/'$(hostname)'-full\.pem/g' /etc/dovecot/conf.d/10-ssl.conf + sed -i -e 's/ssl_key = <\/etc\/dovecot\/private\/dovecot\.pem/ssl_key = <\/etc\/postfix\/ssl\/'$(hostname)'-full\.pem/g' /etc/dovecot/conf.d/10-ssl.conf echo "SSL configured with CA signed/custom certificates" @@ -176,6 +186,8 @@ case $DMS_SSL in mkdir -p /etc/postfix/ssl cp "/tmp/postfix/ssl/$(hostname)-cert.pem" /etc/postfix/ssl cp "/tmp/postfix/ssl/$(hostname)-key.pem" /etc/postfix/ssl + # Force permission on key file + chmod 600 /etc/postfix/ssl/$(hostname)-key.pem cp "/tmp/postfix/ssl/$(hostname)-combined.pem" /etc/postfix/ssl cp /tmp/postfix/ssl/demoCA/cacert.pem /etc/postfix/ssl @@ -186,12 +198,9 @@ case $DMS_SSL in sed -i -r 's/#smtp_tls_CAfile=/smtp_tls_CAfile=\/etc\/postfix\/ssl\/cacert.pem/g' /etc/postfix/main.cf ln -s /etc/postfix/ssl/cacert.pem "/etc/ssl/certs/cacert-$(hostname).pem" - # Courier configuration - sed -i -r 's/TLS_CERTFILE=\/etc\/courier\/imapd.pem/TLS_CERTFILE=\/etc\/postfix\/ssl\/'$(hostname)'-combined.pem/g' /etc/courier/imapd-ssl - - # POP3 courier configuration - sed -i -r 's/POP3_TLS_REQUIRED=0/POP3_TLS_REQUIRED=1/g' /etc/courier/pop3d-ssl - sed -i -r 's/TLS_CERTFILE=\/etc\/courier\/pop3d.pem/TLS_CERTFILE=\/etc\/postfix\/ssl\/'$(hostname)'-combined.pem/g' /etc/courier/pop3d-ssl + # Dovecot configuration + sed -i -e 's/ssl_cert = <\/etc\/dovecot\/dovecot\.pem/ssl_cert = <\/etc\/postfix\/ssl\/'$(hostname)'-combined\.pem/g' /etc/dovecot/conf.d/10-ssl.conf + sed -i -e 's/ssl_key = <\/etc\/dovecot\/private\/dovecot\.pem/ssl_key = <\/etc\/postfix\/ssl\/'$(hostname)'-key\.pem/g' /etc/dovecot/conf.d/10-ssl.conf echo "SSL configured with self-signed/custom certificates" @@ -223,7 +232,6 @@ fi echo "Fixing permissions" chown -R 5000:5000 /var/mail mkdir -p /var/log/clamav && chown -R clamav:root /var/log/clamav -chown postfix.sasl /etc/sasldb2 echo "Creating /etc/mailname" echo $(hostname -d) > /etc/mailname @@ -254,19 +262,18 @@ sed -i -r "/^#?compress/c\compress\ncopytruncate" /etc/logrotate.conf echo "Starting daemons" cron /etc/init.d/rsyslog start -/etc/init.d/saslauthd start +##/etc/init.d/saslauthd start if [ "$SMTP_ONLY" != 1 ]; then - -/etc/init.d/courier-authdaemon start -/etc/init.d/courier-imap start -/etc/init.d/courier-imap-ssl start - + # Here we are starting sasl and imap, not pop3 because it's disabled by default + echo " * Starting dovecot services" + /usr/sbin/dovecot -F -c /etc/dovecot/dovecot.conf & fi + if [ "$ENABLE_POP3" = 1 -a "$SMTP_ONLY" != 1 ]; then echo "Starting POP3 services" - /etc/init.d/courier-pop start - /etc/init.d/courier-pop-ssl start + mv /etc/dovecot/protocols.d/pop3d.protocol.disab /etc/dovecot/protocols.d/pop3d.protocol + /usr/sbin/dovecot reload fi /etc/init.d/spamassassin start @@ -281,8 +288,8 @@ if [ "$ENABLE_FAIL2BAN" = 1 ]; then /etc/init.d/fail2ban start fi -echo "Listing SASL users" -sasldblistusers2 +echo "Listing users" +/usr/sbin/dovecot user '*' echo "Starting..." tail -f /var/log/mail.log From c2881024c776f141c8e211b34df4dcab8ab81af0 Mon Sep 17 00:00:00 2001 From: angus Date: Fri, 8 Apr 2016 00:23:12 +0200 Subject: [PATCH 153/155] Clamav, Imap, Pop3, Dovecot, Postfix services are now logging into /var/log/mail directory. Fail2ban jails and logrotate config files have been updated accordingly. Integration tests have been extended to include a check of the new path. --- start-mailserver.sh | 3 +++ test/tests.bats | 10 ++++++++++ 2 files changed, 13 insertions(+) diff --git a/start-mailserver.sh b/start-mailserver.sh index cff93be2..80054489 100644 --- a/start-mailserver.sh +++ b/start-mailserver.sh @@ -259,6 +259,9 @@ touch /var/log/mail/freshclam.log && chown -R clamav:root /var/log/mail/freshcl sed -i -r 's|/var/log/mail|/var/log/mail/mail|g' /etc/rsyslog.d/50-default.conf sed -i -r 's|LogFile /var/log/clamav/|LogFile /var/log/mail/|g' /etc/clamav/clamd.conf sed -i -r 's|UpdateLogFile /var/log/clamav/|UpdateLogFile /var/log/mail/|g' /etc/clamav/freshclam.conf +sed -i -r 's|/var/log/clamav|/var/log/mail|g' /etc/logrotate.d/clamav-daemon +sed -i -r 's|/var/log/clamav|/var/log/mail|g' /etc/logrotate.d/clamav-freshclam +sed -i -r 's|/var/log/mail|/var/log/mail/mail|g' /etc/logrotate.d/rsyslog echo "Starting daemons" cron diff --git a/test/tests.bats b/test/tests.bats index 3aadc551..709fcae5 100644 --- a/test/tests.bats +++ b/test/tests.bats @@ -115,6 +115,16 @@ [ "$status" -eq 0 ] } +# +# logs +# + +@test "checking logs: mail related logs should be located in a subdirectory" { + run docker exec mail /bin/sh -c "ls -1 /var/log/mail/ | grep -E 'clamav|freshclam|mail'|wc -l" + [ "$status" -eq 0 ] + [ "$output" = 3 ] +} + # # smtp # From 09d5bb72e3e2e49d45b74cae21f01eae5a1140be Mon Sep 17 00:00:00 2001 From: angus Date: Fri, 8 Apr 2016 16:48:52 +0200 Subject: [PATCH 154/155] Configure fail2ban for dovecot and add custom failregex. Correct the handling of virtual_alias_maps file in postfix (virtual) for the generation of virtual_mailbox_domains file (vhost). Minor changes to file names. --- LICENCE => LICENSE | 0 start-mailserver.sh | 31 ++++++++++++++++++++++++++++--- 2 files changed, 28 insertions(+), 3 deletions(-) rename LICENCE => LICENSE (100%) diff --git a/LICENCE b/LICENSE similarity index 100% rename from LICENCE rename to LICENSE diff --git a/start-mailserver.sh b/start-mailserver.sh index 5de852ea..5354a56c 100644 --- a/start-mailserver.sh +++ b/start-mailserver.sh @@ -59,8 +59,10 @@ if [ -f /tmp/postfix/virtual ]; then while IFS=$' ' read from to do # Setting variables for better readability + uname=$(echo ${from} | cut -d @ -f1) domain=$(echo ${from} | cut -d @ -f2) - echo ${domain} >> /tmp/vhost.tmp + # if they are equal it means the line looks like: "user1 other@domain.tld" + test "$uname" != "$domain" && echo ${domain} >> /tmp/vhost.tmp done < /tmp/postfix/virtual else echo "==> Warning: '/tmp/postfix/virtual' is not provided. No mail alias created." @@ -243,13 +245,36 @@ test -e /tmp/spamassassin/rules.cf && cp /tmp/spamassassin/rules.cf /etc/spamass echo "Configuring fail2ban" # enable filters -awk 'BEGIN{unit=0}{if ($1=="[postfix]" || $1=="[couriersmtp]" || $1=="[courierauth]" || $1=="[sasl]") {unit=1;} +awk 'BEGIN{unit=0}{if ($1=="[postfix]" || $1=="[dovecot]" || $1=="[sasl]") {unit=1;} if ($1=="enabled" && unit==1) $3="true"; else if ($1=="logpath" && unit==1) $3="/var/log/mail/mail.log"; print; - if (unit==1 && $1~/\[/ && $1!~/postfix|couriersmtp|courierauth|sasl/) unit=0; + if (unit==1 && $1~/\[/ && $1!~/postfix|dovecot|sasl/) unit=0; }' /etc/fail2ban/jail.conf > /tmp/jail.conf.new && mv /tmp/jail.conf.new /etc/fail2ban/jail.conf && rm -f /tmp/jail.conf.new +cat > /etc/fail2ban/filter.d/dovecot.conf << _EOF_ +# Fail2Ban filter Dovecot authentication and pop3/imap server +# + +[INCLUDES] + +before = common.conf + +[Definition] + +_daemon = (auth|dovecot(-auth)?|auth-worker) + +failregex = ^%(__prefix_line)s(pam_unix(\(dovecot:auth\))?:)?\s+authentication failure; logname=\S* uid=\S* euid=\S* tty=dovecot ruser=\S* rhost=(\s+user=\S*)?\s*$ + ^%(__prefix_line)s(pop3|imap)-login: (Info: )?(Aborted login|Disconnected)(: Inactivity)? \(((no auth attempts|auth failed, \d+ attempts)( in \d+ secs)?|tried to use (disabled|disallowed) \S+ auth)\):( user=<\S*>,)?( method=\S+,)? rip=, lip=(\d{1,3}\.){3}\d{1,3}(, session=<\w+>)?(, TLS( handshaking)?(: Disconnected)?)?\s*$ + ^%(__prefix_line)s(Info|dovecot: auth\(default\)): pam\(\S+,\): pam_authenticate\(\) failed: (User not known to the underlying authentication module: \d+ Time\(s\)|Authentication failure \(password mismatch\?\))\s*$ + ^\s.*passwd-file\(\S*,\): unknown user.*$ + (?: pop3-login|imap-login): .*(?:Authentication failure|Aborted login \(auth failed|Aborted login \(tried to use disabled|Disconnected \(auth failed).*rip=(?P\S*),.* + +## ^%(__prefix_line)spasswd-file\(\S*,\): unknown user.*$ +ignoreregex = +_EOF_ + + # increase ban time and find time to 3h sed -i "/^bantime *=/c\bantime = 10800" /etc/fail2ban/jail.conf sed -i "/^findtime *=/c\findtime = 10800" /etc/fail2ban/jail.conf From 56b8b12966dabcd16f5f73bda42e8208dd0f58f4 Mon Sep 17 00:00:00 2001 From: angus Date: Sat, 9 Apr 2016 00:46:34 +0200 Subject: [PATCH 155/155] Modified the name of the image being created by adding the version: dovecot. --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 47f2090f..acb6d581 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -NAME = tvial/docker-mailserver +NAME = tvial/docker-mailserver:dovecot #all: build run fixtures tests clean #all-no-build: run fixtures tests clean