Introduction
This is the second stage of my OpenLDAP home lab. I set up a mail server to work with existing LDAP configuration.
Pre-Requisites
Setup Process
Mail Server Install
In the existing setup, I cloned another debian server VM, gave it static IP 192.168.57.7, set its hostname to mail-server.acme.internal and then added the DNS record in Pi-hole. Then I went ahead and installed the required packages for postfix and dovecot to work with LDAP.
sudo apt install -y postfix postfix-ldap dovecot-core dovecot-imapd dovecot-ldap dovecot-lmtpd
Then I chose "Internet Site" in the postfix install prompt asking about which type of mail server to install and set the domain to acme.internal.
Postfix Config
I edited /etc/postfix/main.cf to have this configuration:
myhostname = mail-server.acme.internal
mydomain = acme.internal
mydestination = $myhostname, $mydomain, localhost
mynetworks = 192.168.57.0/24 127.0.0.0/8
inet_interfaces = all
mailbox_transport = lmtp:unix:private/dovecot-lmtp
smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth
smtpd_sasl_auth_enable = yes
local_recipient_maps = ldap:/etc/postfix/ldap-recipients.cf
mailbox_transport hands mail delivery off to Dovecot via LMTP. The smtpd_sasl_* settings let Postfix use Dovecot for SMTP authentication. local_recipient_maps tells Postfix to look up valid recipients in LDAP instead of the local user table - without this, Postfix rejects mail to LDAP users with "User unknown in local recipient table".
I created /etc/postfix/ldap-recipients.cf for the recipient lookup:
server_host = ldaps://ldap-server.acme.internal
bind = yes
bind_dn = cn=sssd,ou=service-accounts,dc=acme,dc=internal
bind_pw = SSSDPass123
search_base = ou=users,dc=acme,dc=internal
query_filter = (&(objectClass=posixAccount)(mail=%s))
result_attribute = mail
Then reloaded Postfix:
sudo systemctl reload postfix
Local CA Config on Mail Server
I copied rootCA.pem that I created earlier to this server and trusted it.
debian@mail-server:~/acme-certs$ ls
rootCA.pem
debian@mail-server:~/acme-certs$ sudo cp rootCA.pem /usr/local/share/ca-certificates/acme-rootCA.crt
[sudo] password for debian:
debian@mail-server:~/acme-certs$ sudo update-ca-certificates
Updating certificates in /etc/ssl/certs...
rehash: warning: skipping ca-certificates.crt, it does not contain exactly one certificate or CRL
1 added, 0 removed; done.
Running hooks in /etc/ca-certificates/update.d...
done.
debian@mail-server:~/acme-certs$
Dovecot TLS Config
I generated a TLS cert for mail-server.acme.internal using mkcert and copied it to the server:
sudo cp mail-server.acme.internal.pem /etc/dovecot/private/mail-server.crt
sudo cp mail-server.acme.internal-key.pem /etc/dovecot/private/mail-server.key
sudo chown root:dovecot /etc/dovecot/private/mail-server.key
sudo chmod 640 /etc/dovecot/private/mail-server.key
Then updated /etc/dovecot/conf.d/10-ssl.conf:
ssl_server_cert_file = /etc/dovecot/private/mail-server.crt
ssl_server_key_file = /etc/dovecot/private/mail-server.key
Dovecot LDAP Config
I changed dovecot auth settings to use LDAP auth instead of system auth by editing /etc/dovecot/conf.d/10-auth.conf - commented out auth-system.conf.ext and uncommented auth-ldap.conf.ext.
debian@mail-server:~/acme-certs$ cat /etc/dovecot/conf.d/10-auth.conf | grep "include auth"
#!include auth-deny.conf.ext
#!include auth-master.conf.ext
#!include auth-oauth2.conf.ext
#!include auth-system.conf.ext
#!include auth-sql.conf.ext
!include auth-ldap.conf.ext
#!include auth-passwdfile.conf.ext
#!include auth-static.conf.ext
Dovecot 2.4 changed the config syntax from older versions, so the standard examples online did not work. After checking the example config the package ships with, I set /etc/dovecot/conf.d/auth-ldap.conf.ext to:
ldap_uris = ldaps://ldap-server.acme.internal
ldap_auth_dn = cn=sssd,ou=service-accounts,dc=acme,dc=internal
ldap_auth_dn_password = SSSDPass123
ldap_base = ou=users,dc=acme,dc=internal
passdb ldap {
ldap_filter = (&(objectClass=posixAccount)(uid=%{user}))
ldap_bind = yes
}
userdb ldap {
ldap_filter = (&(objectClass=posixAccount)(uid=%{user}))
fields {
uid = vmail
gid = vmail
home = /var/mail/vhosts/%{user | username}
}
}
This reuses the same read-only service account from the LDAP lab. ldap_bind = yes means Dovecot verifies passwords by actually binding to LDAP as the user rather than fetching and comparing the hash. The userdb block maps all mail storage to a dedicated vmail system user instead of running as the LDAP user's UID.
Note:
ldap_auth_dn_passwordis stored in plaintext, but/etc/dovecot/conf.d/auth-ldap.conf.extis owned by root and not readable by other users.
Dovecot Mail Storage and Postfix Integration
Since LDAP users don't have home directories on the mail server, I created a dedicated vmail system user to own all mailboxes and set up a central mail storage directory:
sudo adduser --system --no-create-home --group vmail
sudo mkdir -p /var/mail/vhosts
sudo chown -R vmail:vmail /var/mail/vhosts
sudo chmod 770 /var/mail/vhosts
I updated /etc/dovecot/conf.d/10-mail.conf to use this path:
mail_driver = maildir
mail_home = /var/mail/vhosts/%{user | username}
mail_path = %{home}/Maildir
first_valid_uid = 100
Then I configured the LMTP and auth unix sockets in /etc/dovecot/conf.d/10-master.conf so Postfix can hand off incoming mail to Dovecot and use Dovecot for SMTP authentication.
In the service lmtp block:
service lmtp {
unix_listener /var/spool/postfix/private/dovecot-lmtp {
mode = 0600
user = postfix
group = postfix
}
}
In the service auth block:
service auth {
unix_listener /var/spool/postfix/private/auth {
mode = 0660
user = postfix
group = postfix
}
}
Then restarted Dovecot:
sudo systemctl restart dovecot
Verification
Sending mail
I sent a test mail from jsmith to adoe over SMTP from a desktop VM on the same network:
debian@debian:~/acme-certs$ curl -v --url "smtp://mail-server.acme.internal:25" \
--mail-from "jsmith@acme.internal" \
--mail-rcpt "adoe@acme.internal" \
--upload-file - <<EOF
From: jsmith@acme.internal
To: adoe@acme.internal
Subject: Test from jsmith
Hello Alice, this is John.
EOF
Postfix accepted it and delivered it to Dovecot via LMTP:
250 2.0.0 Ok: queued as 98B624018B
Verified the mail landed in adoe's mailbox on the server:
debian@mail-server:~$ sudo ls /var/mail/vhosts/adoe/Maildir/new/
1773903163.M693787P7845.mail-server.acme.internal,S=560,W=576
Retrieving mail over IMAPS
I verified that adoe can authenticate and retrieve mail over IMAPS using their LDAP credentials:
debian@debian:~/acme-certs$ curl -v --url "imaps://mail-server.acme.internal/INBOX" \
--user "adoe:Password456"
* SSL certificate verify ok.
* Connected to mail-server.acme.internal (192.168.57.7) port 993
< A002 OK Logged in
< * LIST (\HasNoChildren) "." INBOX
< A003 OK List completed (0.001 + 0.000 secs).
TLS handshake succeeded using the mkcert CA, LDAP authentication worked, and the INBOX is accessible.
Thunderbird Verification
Thunderbird has its own certificate store separate from the system trust store, so I had to manually import rootCA.pem into Thunderbird settings before it would trust the IMAPS connection.
adoe sends an email to jsmith
jsmith opens it
jsmith sends a reply email to adoe
adoe views the reply email
Conclusion
Postfix and Dovecot are now running as a mail server for acme.internal. Users defined in the OpenLDAP directory can send and receive mail using their LDAP credentials. Postfix looks up valid recipients in LDAP so it accepts mail for LDAP users. Dovecot authenticates over LDAPS using the same read-only service account from the LDAP lab and stores mail in a central directory owned by a dedicated vmail user. IMAP access is over TLS only.
This mail server will be used in the next part of this series as the SMTP backend for Keycloak notifications.




Top comments (0)