How to Configure SSL In Multi-Tenant Email Servers Using SNI

Running a multi-tenant or multi-domain email server introduces unique SSL challenges. Each hosted domain must present the correct certificate while being handled seamlessly by Postfix (SMTP) and Dovecot (IMAP/POP3).

This guide shows a production-ready way to configure SSL using SNI with Postfix, Dovecot, and Let’s Encrypt.

This guide assumes:

  • Postfix and Dovecot are already installed and working.
  • Valid SSL certificates are already issued for each mail hostname

Let's get started!

Postfix SNI Configuration

In this step we will first configure default TLS settings using your primary domain so that postfix can use it when either the client sends no SNI at all, or the client sends SNI, but the name doesn't match anything in the tls_server_sni_maps table.

Open /etc/postfix/main.cf.
sudo nano /etc/postfix/main.cf
Make sure the following lines are present or add them if not. Replace mail.primary_domain.com with your own primary hostname.
#Enable TLS Encryption when Postfix receives incoming emails
smtpd_tls_cert_file=/etc/letsencrypt/live/mail.primary_domain.com/fullchain.pem
smtpd_tls_key_file=/etc/letsencrypt/live/mail.primary_domain.com/privkey.pem
smtpd_tls_security_level=may
smtpd_tls_loglevel = 1
smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache

#Enable TLS when Postfix acts as an SMTP client (outbound mail)
smtp_tls_security_level = may
smtp_tls_loglevel = 1
smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache

#Enforce TLSv1.3 or TLSv1.2
smtpd_tls_mandatory_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1
smtpd_tls_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1
smtp_tls_mandatory_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1
smtp_tls_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1

Now add the following line which points to the file containing SNI maps. You could use any name instead of tls_sni.map (eg: my_snis.map etc.)
tls_server_sni_maps=hash:/etc/postfix/tls_sni.map
Save and close the file, and create the file /etc/postfix/tls_sni.map (Note: make sure you used the correct file name if you used different file name).
sudo nano /etc/postfix/tls_sni.map
Add the SNI mappings for all of your secondary hostnames using the following format. (Note: Make sure that you follow the exact order in a single line, otherwise it will not work)
secondary_hostname    cert_key_file    cert_file
eg:
mail.domain1.com /etc/letsencrypt/live/mail.domain1.com/privkey.pem    /etc/letsencrypt/live/mail.domain1.com/fullchain.pem
If you have multiple mail hostnames for secondary domains, the file contents will look something like the following.


Save and close the file, and run the following command.
postmap -F hash:/etc/postfix/tls_sni.map
Then restart postfix.
sudo systemctl restart postfix

Dovecot SNI Configuration

In this step too, similar to how we did in the Postfix configuration, we need to add the default SSL configuration for your primary hostname first before adding the SNI mappings for the mail hostnames for secondary domains. Open the file /etc/dovecot/conf.d/10-ssl.conf and make sure the following lines exist and add them if not.
ssl_cert = </etc/letsencrypt/live/mail.primary_domain.com/fullchain.pem
ssl_key = </etc/letsencrypt/live/mail.primary_domain.com/privkey.pem
Save and close the file. Unlike Postfix, Dovecot is quite flexible. You can add SNI mappings in multiple ways.
  1. Adding all the SNI mappings at end of /etc/dovecot/conf.d/10-ssl.conf file.
  2. Adding all the SNI mapping together in a separate file.
  3. Creating a separate file for each SNI mapping (My preferred way).
As Dovecot load all the configs in /etc/dovecot/conf.d/  directory, I will create a separate file for each SNI mapping, following the given naming format 13-ssl-sni-domain_name.conf. In the example for Postfix configuration, I added three mail hostnames for secondary domains. Therefore I will use three domains for demonstrating Dovecot configuration. Be sure to replace the placeholder domain names/hostnames with your own domain name/hostname (Note: If you are curious about the starting number of file name, this is used to ensure the order of which the configurations are loaded in Dovecot)

hostname: mail.domain1.com

Create the file /etc/dovecot/conf.d/13-ssl-sni-mail.domain1.com.conf and add the following lines.
    local_name mail.domain1.com {
      ssl_cert = </etc/letsencrypt/live/mail.domain1.com/fullchain.pem
      ssl_key  = </etc/letsencrypt/live/mail.domain1.com/privkey.pem
    }
Save and close the file.

hostname: mail.domain2.com

Create the file /etc/dovecot/conf.d/13-ssl-sni-mail.domain2.com.conf and add the following lines.
    local_name mail.domain2.com {
      ssl_cert = </etc/letsencrypt/live/mail.domain2.com/fullchain.pem
      ssl_key  = </etc/letsencrypt/live/mail.domain2.com/privkey.pem
    }
Save and close the file.

hostname: mail.domain3.com

Create the file /etc/dovecot/conf.d/13-ssl-sni-mail.domain3.com.conf and add the following lines.
    local_name mail.domain3.com {
      ssl_cert = </etc/letsencrypt/live/mail.domain3.com/fullchain.pem
      ssl_key  = </etc/letsencrypt/live/mail.domain3.com/privkey.pem
    }
Save and close the file.

Finally restart Dovecot.
sudo systemctl restart dovecot

Testing & Troubleshooting SNI Configuration

Postfix

For each SNI mapping configured, use the following command by replacing mail.domain1.com with the actual hostname.
openssl s_client -connect mail.domain1.com:587 -starttls smtp -servername mail.domain1.com
Configuration is working correctly if in the output,
  • Verify return code: 0 (ok)
  • Certificate CN/SAN matches mail.domain1.com
Otherwise,
  • Check whether the tls_server_sni_maps is configured correctly.
  • Confirm the order of values of SNI mapping in /etc/postfix/tls_sni.map (or the file you created) is correct. Correct order: hostname path_to_private_key path_to_cert
  • Make sure you executed the command postmap -F hash:/etc/postfix/tls_sni.map (replace the path with yours if you used a different one) and restarted the postfix service.

Dovecot

For each SNI mapping configured, use the following command by replacing mail.domain1.com with the actual hostname and the ports (993, 995 etc.).
openssl s_client -connect mail.domain1.com:993 -servername mail.domain1.com
For this one too, configuration is working correctly if in the output,
  • Verify return code: 0 (ok)
  • Certificate CN/SAN matches mail.domain1.com
Otherwise,
  • Check the Dovecot SNI mapping in each /etc/dovecot/conf.d/13-ssl-sni-*.conf file.
  • Make sure you restart the dovecot service.
This is how you configure SSL for a multi-tenant email server using SNI. Please share and leave a comment if you find this post helpful. Your feedback is very valuable to me.

Comments