Skip to content

TLS / Letsencrypt / virtualdomain support #24

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 25 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
docker-postfix
==============

Modified from catatnight/postfix to add virtualhost support

run postfix with smtp authentication (sasldb) in a docker container.
TLS and OpenDKIM support are optional.

Expand All @@ -11,39 +13,55 @@ TLS and OpenDKIM support are optional.
1. Build image

```bash
$ sudo docker pull catatnight/postfix
$ sudo docker pull benxo/postfix
```

## Usage
1. Create postfix container with smtp authentication

```bash
$ sudo docker run -p 25:25 \
-e maildomain=mail.example.com -e smtp_user=user:pwd \
--name postfix -d catatnight/postfix
-e mailhostname=mail.example.com -e maildomain=example.com -e smtp_user=user:pwd \
--name postfix -d benxo/postfix
# Set multiple user credentials: -e smtp_user=user1:pwd1,user2:pwd2,...,userN:pwdN
```
2. Enable OpenDKIM: save your domain key ```.private``` in ```/path/to/domainkeys```

```bash
$ sudo docker run -p 25:25 \
-e maildomain=mail.example.com -e smtp_user=user:pwd \
-e mailhostname=mail.example.com -e maildomain=example.com -e smtp_user=user:pwd \
-v /path/to/domainkeys:/etc/opendkim/domainkeys \
--name postfix -d catatnight/postfix
--name postfix -d benxo/postfix
```
3. Enable TLS(587): save your SSL certificates ```.key``` and ```.crt``` to ```/path/to/certs```

```bash
$ sudo docker run -p 587:587 \
-e maildomain=mail.example.com -e smtp_user=user:pwd \
-e mailhostname=mail.example.com -e maildomain=example.com -e smtp_user=user:pwd \
-v /path/to/certs:/etc/postfix/certs \
--name postfix -d catatnight/postfix
--name postfix -d benxo/postfix
```

4. Full example (where you have symlinked certs from letsencrypt into /etc/postfix/certs):

``` bash
docker run -p 25:25 -p 587:587 \
-e mailhostname=mail.example.com -e maildomain=example.com -e smtp_user=user:pwd \
-e virtual_domains="mail.example.com test.example.com etc.example.com" \
-v /path/to/domainkeys:/etc/opendkim/domainkeys \
-v /etc/postfix/virtual:/etc/postfix/virtual \
-v /etc/letsencrypt/live:/etc/letsencrypt/live \
-v /etc/letsencrypt/archive:/etc/letsencrypt/archive \
-v /etc/postfix/certs:/etc/postfix/certs \
--name postfix -d benxo/postfix
```


## Note
+ Login credential should be set to (`[email protected]`, `password`) in Smtp Client
+ You can assign the port of MTA on the host machine to one other than 25 ([postfix how-to](http://www.postfix.org/MULTI_INSTANCE_README.html))
+ Read the reference below to find out how to generate domain keys and add public key to the domain's DNS records
+ If you want a persistent queue between restarts, you will need to extract an empty spool from /var/spool/postfix inside the container, preserving IDs and permissions! One is provided in postfix-spool.tgz

## Reference
+ [Postfix SASL Howto](http://www.postfix.org/SASL_README.html)
Expand Down
97 changes: 84 additions & 13 deletions assets/install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -26,18 +26,55 @@ service postfix start
tail -f /var/log/mail.log
EOF
chmod +x /opt/postfix.sh
postconf -e myhostname=$maildomain

if [[ -z "$mailhostname" ]]; then
mailhostname=$maildomain
fi

postconf -e myhostname=$mailhostname
postconf -F '*/*/chroot = n'

# set up some email security as per https://ssl-tools.net/mailservers/ and
# https://serverfault.com/questions/670348/how-to-force-a-own-set-of-ciphers-in-postfix-2-11#670359 and
# https://blog.tinned-software.net/harden-the-ssl-configuration-of-your-mailserver/

postconf -e tls_ssl_options=NO_COMPRESSION

postconf -e smtp_use_tls=yes
postconf -e smtp_tls_security_level=may
postconf -e "smtp_tls_protocols = !SSLv2, !SSLv3"
postconf -e "smtp_tls_mandatory_protocols = !SSLv2, !SSLv3"
postconf -e "smtp_tls_exclude_ciphers = DES-CBC3-SHA, EDH-RSA-DES-CBC3-SHA, RC2, RC4, aNULL"
postconf -e smtp_tls_loglevel=1

postconf -e smtpd_tls_security_level=may
# postconf -e smtpd_tls_auth_only=yes
postconf -e "smtpd_tls_protocols = !SSLv2, !SSLv3"
postconf -e "smtpd_tls_mandatory_protocols = !SSLv2, !SSLv3"
postconf -e smtpd_tls_ciphers=high
postconf -e smtpd_tls_mandatory_ciphers=high
postconf -e "smtpd_tls_exclude_ciphers = DES-CBC3-SHA, EDH-RSA-DES-CBC3-SHA, RC2, RC4, aNULL"
postconf -e smtpd_tls_eecdh_grade=ultra

# include 172.16/12 for docker
postconf -e "mynetworks=127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128 172.16.0.0/12"


############
# SASL SUPPORT FOR CLIENTS
# The following options set parameters needed by Postfix to enable
# Cyrus-SASL support for authentication of mail clients.
############
# /etc/postfix/main.cf
postconf -e smtpd_sasl_auth_enable=yes

# this is enabled separately for smpt 25 and submission 587
#postconf -e smtpd_sasl_auth_enable=yes

postconf -e broken_sasl_auth_clients=yes
postconf -e smtpd_recipient_restrictions=permit_sasl_authenticated,reject_unauth_destination
postconf -e smtpd_sasl_security_options=noanonymous
postconf -e "smtpd_recipient_restrictions=permit_mynetworks, permit_sasl_authenticated, reject_unauth_destination"
postconf -e "smtpd_relay_restrictions = permit_mynetworks, permit_sasl_authenticated, reject_unauth_destination"

# smtpd.conf
cat >> /etc/postfix/sasl/smtpd.conf <<EOF
pwcheck_method: auxprop
Expand All @@ -51,21 +88,47 @@ while IFS=':' read -r _user _pwd; do
done < /tmp/passwd
chown postfix.sasl /etc/sasldb2

############
# Virtual Domain support
############
if [[ "$virtual_domains" != "" ]]; then
postconf -e virtual_alias_maps=hash:/etc/postfix/virtual
postconf -e "virtual_alias_domains=$virtual_domains"
postmap /etc/postfix/virtual
fi

############
# Enable TLS
############

if [[ -n "$(find /etc/postfix/certs -iname *.crt)" && -n "$(find /etc/postfix/certs -iname *.key)" ]]; then
SMTPD_TLS_CERT_FILE=$(find /etc/postfix/certs -iname *.crt)
SMTPD_TLS_KEY_FILE=$(find /etc/postfix/certs -iname *.key)
fi

# for letsencrypt
if [[ -n "$(find /etc/postfix/certs -iname *.pem)" ]]; then
SMTPD_TLS_CERT_FILE=$(find /etc/postfix/certs -iname *full*.pem)
SMTPD_TLS_KEY_FILE=$(find /etc/postfix/certs -iname *priv*.pem)
fi

if [[ "$SMTPD_TLS_CERT_FILE" != "" ]]; then
# /etc/postfix/main.cf
postconf -e smtpd_tls_cert_file=$(find /etc/postfix/certs -iname *.crt)
postconf -e smtpd_tls_key_file=$(find /etc/postfix/certs -iname *.key)
postconf -e smtpd_tls_cert_file=$SMTPD_TLS_CERT_FILE
postconf -e smtpd_tls_key_file=$SMTPD_TLS_KEY_FILE
chmod 400 /etc/postfix/certs/*.*
# /etc/postfix/master.cf
#postconf -M submission/inet="submission inet n - n - - smtpd -v" # enable for debugging auth on 587
postconf -M submission/inet="submission inet n - n - - smtpd"
postconf -P "submission/inet/syslog_name=postfix/submission"
postconf -P "submission/inet/smtpd_tls_security_level=encrypt"
postconf -P "submission/inet/smtpd_tls_security_level=encrypt" # comment out to test AUTH
postconf -P "submission/inet/smtpd_sasl_auth_enable=yes"
postconf -P "submission/inet/milter_macro_daemon_name=ORIGINATING"
postconf -P "submission/inet/smtpd_recipient_restrictions=permit_sasl_authenticated,reject_unauth_destination"
postconf -P "submission/inet/tls_preempt_cipherlist=yes"

# only allow login from port 587
postconf -P "smtp/inet/smtpd_sasl_auth_enable=no"
fi

#############
Expand Down Expand Up @@ -117,14 +180,22 @@ cat >> /etc/opendkim/TrustedHosts <<EOF
127.0.0.1
localhost
192.168.0.1/24
172.16.0.0/12

*.$maildomain
EOF
cat >> /etc/opendkim/KeyTable <<EOF
mail._domainkey.$maildomain $maildomain:mail:$(find /etc/opendkim/domainkeys -iname *.private)
EOF
cat >> /etc/opendkim/SigningTable <<EOF
*@$maildomain mail._domainkey.$maildomain
EOF

for d in $virtual_domains; do
echo >> /etc/opendkim/TrustedHosts "*.$d"
done

for d in $maildomain $virtual_domains; do
private_key_file=$(find /etc/opendkim/domainkeys/$d -iname *.private)
if [[ "$private_key_file" != "" ]]; then
echo >> /etc/opendkim/KeyTable "mail._domainkey.$d $d:mail:$private_key_file"
echo >> /etc/opendkim/SigningTable "*@$d mail._domainkey.$d"
fi
done

chown opendkim:opendkim $(find /etc/opendkim/domainkeys -iname *.private)
chmod 400 $(find /etc/opendkim/domainkeys -iname *.private)
chmod 400 $(find /etc/opendkim/domainkeys -iname *.private)
4 changes: 2 additions & 2 deletions build.sh
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
#!/bin/bash
#!/bin/bash -xe

docker build -t catatnight/postfix .
docker build -t benxo/postfix .
Binary file added postfix-spool.tgz
Binary file not shown.