Setup mail server with ldap authentication in docker

Getting an email server to run in docker is easy but getting an email server with ldap authentication to run in docker spend me a week to get up and running.

Here are the steps that I taken. I will assume you already know how to install docker.

Install LDAP.

docker run \
             --detach \
             --restart unless-stopped \
             --name openldap \
             -e LDAP_ORGANISATION=domain \
             -e LDAP_DOMAIN=domain.com \
             -e LDAP_ADMIN_PASSWORD=complex-password \
             -e LDAP_RFC2307BIS_SCHEMA=true \
             -e LDAP_REMOVE_CONFIG_AFTER_SETUP=true \
             -e LDAP_TLS=false \
             -p 389:389 \
             --volume /data/openldap/var_lib_ldap:/var/lib/ldap \
             --volume /data/openldap/etc_ldap_slapd.d:/etc/ldap/slapd.d \
             osixia/openldap:latest


Install postfix-book schema into the ldap.

# cd /etc/ldap/schema
# apt update
# apt install vim wget
# wget https://raw.githubusercontent.com/variablenix/ldap-mail-schema/master/postfix-book.schema
# use vim to remove mailAlias block
# mkdir ldif_output
# vim schema_convert.conf

;add these lines
include /etc/ldap/schema/core.schema
include /etc/ldap/schema/cosine.schema
include /etc/ldap/schema/nis.schema
include /etc/ldap/schema/inetorgperson.schema
include /etc/ldap/schema/postfix-book.schema

# slapcat -f schema_convert.conf -F ./ldif_output/ -n0
# cp ldif_output/cn\=config/cn\=schema/cn\=\{4\}postfix-book.ldif ./postfix-book.ldif

;Edited the file /etc/ldap/schema/ldif_out/cn\=config/cn\=schema/cn\=\{4\}postfix-book.ldif to delete the 7 last line and make following changes:
dn: cn=postfix-book,cn=schema,cn=config
cn: postfix-book

# ldapadd -Y EXTERNAL -H ldapi:/// -f postfix-book.ldif

Install web base ldap user manager (mainly for user to change password)

docker run \
             --detach \
             --name=ldap-manager \
             -p 8080:80 \
             -e SERVER_HOSTNAME=localhost \
             -e LDAP_URI=ldap://ip.add.re.ss \
             -e LDAP_BASE_DN=dc=domain,dc=com \
             -e LDAP_REQUIRE_STARTTLS=FALSE \
             -e LDAP_ADMINS_GROUP=admins \
             -e LDAP_ADMIN_BIND_DN="cn=admin,dc=domain,dc=com" \
             -e LDAP_ADMIN_BIND_PWD=complex-password \
             -e NO_HTTPS=TRUE \
             wheelybird/ldap-user-manager:latest

Install postfix and dovecot.

# cat docker-compose.yml 
version: '2'

services:
  mail:
    image: tvial/docker-mailserver:latest
    hostname: mail
    domainname: domain.com
    container_name: mailserver
    ports:
      - "25:25"
      - "143:143"
      - "587:587"
      - "993:993"
    volumes:
      - /data/mailserver/maildata:/var/mail
      - /data/mailserver/mailstate:/var/mail-state
      - /data/mailserver/maillogs:/var/log/mail
      - /data/mailserver/config/:/tmp/docker-mailserver/
    environment:
      - ENABLE_SPAMASSASSIN=1
      - SPAMASSASSIN_SPAM_TO_INBOX=1
      - ENABLE_CLAMAV=1
      - ENABLE_FAIL2BAN=0
      - ENABLE_POSTGREY=1
      - ONE_DIR=1
      - DMS_DEBUG=0
      - ENABLE_LDAP=1
      - LDAP_SERVER_HOST=192.168.1.1 # your ldap container/IP/ServerName
      - LDAP_SEARCH_BASE=ou=people,dc=domain,dc=com
      - LDAP_BIND_DN=cn=admin,dc=domain,dc=com
      - LDAP_BIND_PW=complex-password
      - LDAP_QUERY_FILTER_USER=(&(mail=%s)(mailEnabled=TRUE))
      - LDAP_QUERY_FILTER_GROUP=(&(mailGroupMember=%s)(mailEnabled=TRUE))
      - LDAP_QUERY_FILTER_ALIAS=(|(&(mailAlias=%s)(objectClass=PostfixBookMailForward))(&(mailAlias=%s)(objectClass=inetOrgPerson)(mailEnabled=TRUE)))
      - LDAP_QUERY_FILTER_DOMAIN=(|(&(mail=*@%s)(objectClass=PostfixBookMailAccount)(mailEnabled=TRUE))(&(mailGroupMember=*@%s)(objectClass=PostfixBookMailAccount)(mailEnabled=TRUE))(&(mailalias=*@%s)(objectClass=PostfixBookMailForward)))
      - DOVECOT_PASS_FILTER=(&(objectClass=inetOrgPerson)(uid=%n))
      - DOVECOT_USER_FILTER=(&(objectClass=inetOrgPerson)(uid=%n))
      - DOVECOT_USER_ATTRS=homeDirectory=home,=uid=5000,=gid=5000
      - ENABLE_SASLAUTHD=1
      - SASLAUTHD_MECHANISMS=ldap
      - SASLAUTHD_LDAP_SERVER=192.168.1.1
      - SASLAUTHD_LDAP_BIND_DN=cn=admin,dc=domain,dc=com
      - SASLAUTHD_LDAP_PASSWORD=complex-password
      - SASLAUTHD_LDAP_SEARCH_BASE=ou=people,dc=domain,dc=com
      - SASLAUTHD_LDAP_FILTER=(&(objectClass=inetOrgPerson)(uid=%U))
      - POSTMASTER_ADDRESS=postmaster@localhost.localdomain
      - POSTFIX_MESSAGE_SIZE_LIMIT=100000000
    cap_add:
      - SYS_PTRACE

I remove the fail2ban and change some of the query.

# docker-compose up -d

Once the container is up and running , go into the container to modify some settings.

# docker exec -it mailserver /bin/bash
# vim /etc/postfix/main.cf

Modify this line, add the reject_sender_login_mismatch at first position, to prevent user can send email as anyone.

smtpd_sender_restrictions = reject_sender_login_mismatch, permit_sasl_authenticated, permit_mynetworks, reject_unknown_sender_domain

add this line, so that user can send email not limited to own email address , user can send using alias email address.

smtpd_sender_login_maps = ldap:/etc/postfix/ldap-aliases.cf

I am trying to use AWS SES service to send outgoing email, but not sure why the postfix not able to send the correct user name and password. So I route the outgoing email to another postfix container.

relayhost = 192.168.1.1:2525

Install postfix mail relay.


docker container run -d \
            --restart=always \
            --name postfix \
            -e MAIL_RELAY_HOST='email-smtp.ap-southeast-1.amazonaws.com' \
            -e MAIL_RELAY_PORT='465' \
            -e MAIL_RELAY_USER='username' \
            -e MAIL_RELAY_PASS='password' \
            -e MAIL_CANONICAL_DOMAINS='domain.com' \
            -p 2525:25 \
            tecnativa/postfix-relay

Install roundcube as web base mail client.

docker run -d \
        --restart=always \
        --name roundcube \
        -e ROUNDCUBEMAIL_DEFAULT_HOST=192.168.1.1 \
        -e ROUNDCUBEMAIL_SMTP_SERVER=tls://192.168.1.1 \
        -e ROUNDCUBEMAIL_UPLOAD_MAX_FILESIZE=1024M \
        -v /data/roundcube/config/:/var/roundcube/config/ \
        -p 8081:80 \
        -d roundcube/roundcubemail

Once the container is up and running, go into the container to modify some setting.

docker exec -it roundcube /bin/bash
 # vim /var/www/html/config/config.inc.php

Append these lines at the end of the file, so that roundcube will ignore the cert error.

    $config['imap_conn_options'] = array(
'ssl' => array(
'verify_peer' => false,
'verfify_peer_name' => false,
),
    );
    $config['smtp_conn_options'] = array(
'ssl' => array(
'verify_peer' => false,
'verify_peer_name' => false,
),
    );

Install nginx.

docker run -d \
            --name nginx \
            -p 80:80 -p 443:443 \
            -v /data/nginx/certs/:/etc/nginx/certs/
            -v /data/nginx/conf.d/:/etc/nginx/conf.d/
            nginx

The nginx configuration I leave it to you. If you need help on configure the nginx, please leave a comment and let me know.

Manage email account.


The ldap account that need to use for log in mail system and send/receive email.

1. Make sure the ldap account has PostfixBookMailAccount object class.
2. Add mailEnabled attribute and set the value to TRUE .
3. Add mail attribute and set the value to the main email address.
4. Add mailalias attribute and set the value to the main email address.
5. Add mailalias attribute and set the value to any distribution list email address, if needed.

Testing

Now you should be able to send/receive email using roundcube web email client and connect using port 143 (imap) and port 587 (smtp) from any email client. Remember to select STARTTLS option.

*

This is not the perfect solution, especially the self sign cert. If you have concern with it , you can buy a cert or get a cert from letencrypt.


---

Comments

Popular posts from this blog

How to allow non root user to execute hping command ?

Boot Acronis from PXE