1. Home
  2. Symbiosis User Guide
  3. Enabling SNI for Exim on Symbiosis

Enabling SNI for Exim on Symbiosis

If you use Symbiosis to host multiple email domains, you’ll want to help your users configure their mail clients to connect. It’s simple to do this for Exim, with a one-time change to your server configuration.

To follow this guide, you will need to be comfortable with the Linux/Unix command line and with editing simple text files. If you’re not, then please contact our support team for help.

What is SNI?

Server Name Indication (SNI) is a TLS mechanism that lets your client tell the server which domain it wants to connect to, so that the server can provide the correct security certificate to the client. It’s widely used for web sites, but less widely implemented in mail servers. It also helps prevent “server name mismatch” errors.

A note on paths

Symbiosis understands that /srv/ contains directories named for local domains, and Exim in Symbiosis understands that too. If you’re using Exim on another operating system, you might be able to use the same configuration snippet by altering the paths in it.

Configuring Exim

In Exim, the variable $tls_sni contains the SNI string, if there is one. It’s not sanitised, so we’ll put in a test to ensure the string contains a domain, and then look for an SSL certificate in the expected place. We’ll also add logging of the string, to make debugging a bit easier.

So, you’ll need to edit /etc/exim4/symbiosis.d/00-main/50-tls-options, then rebuild the Exim configuration. Note that you’ll need to remove or comment out the existing definitions of tls_certificate and tls_privatekey.

# log the TLS_SNI string when an email is accepted.
log_selector = +tls_sni

#tls_certificate = /etc/ssl/ssl.combined
#tls_privatekey = /etc/ssl/ssl.combined

# here we test that $tls_in_sni really is a domain, but constructing an arbitrary email address foo@...
# and then extracting the domain with a function that should fails if the email address is not valid
# then we looks to see that the cert exists, and use it
# otherwise we use the default cert in /etc/ssl
tls_certificate = \
        ${if and {\
                     { eq {${domain:foo@$tls_in_sni}} {$tls_in_sni}}\
                     { exists{/srv/$tls_in_sni/config/ssl/current/ssl.combined} }\
                 }\
                 {/srv/$tls_in_sni/config/ssl/current/ssl.combined}\
                 {/etc/ssl/ssl.combined}\
         }
# "tls_privatekey" defaults to the value of tls_certificate, which is fine.
#

Testing the configuration

When you’ve made the change to 50-tls-options, you’ll need to test that your configuration is safe, then deploy and finally test that the new configuration is actually working.

# change directory
cd /etc/exim4
# this is safe
make test
# make sure only the expected changes are present
diff exim4.conf exim4.conf.tmp

If you’re happy with those changes, then use Exim to check the syntax as follows:

# check the syntax
exim -bV -C exim4.conf.tmp

The output should look something like this:

Exim version 4.89 #1 built 10-Feb-2018 08:26:05
Copyright (c) University of Cambridge, 1995 - 2017
(c) The Exim Maintainers and contributors in ACKNOWLEDGMENTS file, 2007 - 2017
Berkeley DB: Berkeley DB 5.3.28: (September 9, 2013)
Support for: crypteq iconv() IPv6 PAM Perl Expand_dlfunc GnuTLS move_frozen_messages Content_Scanning DKIM DNSSEC Event OCSP PRDR PROXY SOCKS TCP_Fast_Open
Lookups (built-in): lsearch wildlsearch nwildlsearch iplsearch cdb dbm dbmjz dbmnz dnsdb dsearch ldap ldapdn ldapm mysql nis nis0 passwd pgsql sqlite
Authenticators: cram_md5 cyrus_sasl dovecot plaintext spa tls
Routers: accept dnslookup ipliteral iplookup manualroute queryprogram redirect
Transports: appendfile/maildir/mailstore/mbx autoreply lmtp pipe smtp
Fixed never_users: 0
Configure owner: 0:0
Size of off_t: 8
Configuration file is /etc/exim4/exim4.conf.tmp

Deploying your configuration

If no errors are shown, then deploy. This will build the configuration, and reload Exim

cd /etc/exim4
make

Verifying it works

Finally, test that Exim is doing the right thing. This will work best if you’ve kept /srv/ tidy. Ideally, it only contains directories, each of which is named for a domain. Hidden files (with names starting with a dot) are ok, but anything else will produce unnecessary output with this test.

for m in `ls /srv`
do servername=$m; 
  echo -n "$m: ";
  (sleep 0.3;echo quit)|openssl s_client -connect localhost:smtp -starttls smtp -servername $servername 2>&1 | openssl x509 -noout -subject; 
done

Ideally, for every domain that has a certificate, you’ll see a line like this, with the two domains matching. For other domains, the CN will be your default domain.

example.com: subject=CN = example.com

Subdomain implementation strategy

The instructions above will allow Exim to serve the SSL certificate for all your domains. But, Symbiosis publishes subdomains like “mx.example.com” and “mail.example.com“. Symbiosis’ Let’s Encrypt certificates will automatically cover “www.example.com“, but not the “mx” and “mail” subdomains, so you might want to add coverage for those by creating the aliases /srv/mx.example.com/ and /srv/mail.example.com/ pointing to /srv/example.com/.

So, for each domain that you install, you might want to run the following (replacing example.com with the correct domain name):

# set your domain name here
domain=example.com

# create the links
cd /srv/
ln -s $domain mx.$domain/
ln -s $domain mail.$domain/

# symbiosis will do these bits on a schedule, but you might want to speed it up
# generate DNS
symbiosis-dns-generate --verbose
# get certificates
symbiosis-ssl --verbose
Updated on November 27, 2018

Was this article helpful?

Related Articles