E-mail server hosting on Amazon EC2

In the previous post I described how to set up web hosting with HTTPS and WordPress. All those steps require less work compared to settings up a fully secured e-mail server. Technologies For e-mail self-hosting we need postfix as a message transfer agent (MTA), dovecot for POP3 e-mail server, cyrus SASL (simple authentication security layer) for SMTP relay security, Amazon SES (simple e-mail service) for SMTP relay authority and reverse DNS lookup, SSL certificate from Let's Encrypt described in the previous post. Base setup
  1. Install postfix, dovecot, cyrus SASL, start them and enable the correspondent services (postfix, dovecot, saslauthd), and remove sendmail.
    1. sudo yum install postfix dovecot cyrus-sasl
    2. sudo yum remove sendmail
    3. sudo yum postfix start # repeat for dovecot and saslauthd
    4. sudo chkconfig postfix on # repeat for dovecot and saslauthd
  2. Create real user with password + directory (or a virtual user with a virtual mailbox).
    1. sudo useradd admin
    2. sudo passwd admin
    3. sudo mkdir /home/admin/mail/
    4. sudo chown admin /home/admin/mail
  3. Configure postfix for basic SMTP on port 25
    1. Edit /etc/postfix/main.cf to specify
      1. myhostname=yourhostname.com
      2. mydomain=yourhostname.com
      3. inet_interfaces=all
      4. inet_protocols=all
      5. home_mailbox=mail/
      6. message_size_limit=10485760 # for 10MB
      7. mailbox_size_limit=1073741824 # for ~1GB
      8. smtpd_recipient_restrictions=permit_mynetworks, permit_auth_destinations,permit_sasl_authenticated,reject
  4. Configure dovecot for basic POP3 on port 110
    1. Edit /etc/dovecot/10-auth.conf to specify
      1. disable_plaintext_auth=no
      2. auth_mechanisms=plain login
    2. Edit /etc/dovecot/10-mail.conf to specify
      1. mail_location=maildir:~/mail
    3. Edit /etc/dovecot/10-ssl.conf to specify
      1. ssl=no
  5. Open ports 25 and 110 in EC2 security groups, restart dovecot, postfix, and check that you can send e-mail to yourself and receive it via your favorite e-mail agent (SMTP and POP3 hosts are yourhostname.com, no encryption, no SSL/TLS).
Authenticated SMTP The above setup is the least secure. The first step for amending is to require authentication for SMTP. For that, use dovecot for SASL authentication with SMTP server (smtpd).
  1. Edit /etc/postfix/main.cf to specify
    1. smtpd_sasl_type = dovecot
    2. smtpd_sasl_path = private/auth
    3. smtpd_sasl_auth_enable = yes
    4. smtpd_sasl_security_options = noanonymous
    5. smtpd_sasl_local_domain=$myhostname
    6. broken_sasl_auth_clients=yes
    7. smtpd_sasl_authenticated_header = yes
  2. Edit /etc/dovecot/10-master.conf to specify
    1. unix_listener /var/spool/postfix/private/auth  {
    2. mode = 0666
    3. user = postfix
    4. group = postfix
    5. }
  3. In your favorite e-mail application set "My outgoing server (SMTP) requires authentication" -> "Use same settings as my incoming mail server" and test that the new set up can send and receive e-mails to self and to/from one external account.
Secure SMTP and POP3 The above setup doesn't allow for anonymous access to the e-mail server. However, the established connections are not secure. Both POP3 and SMTP can be secured with the same SSL certificate, we used for HTTPS as long as the connection server names coincide with the domain name.
  1. Enable SMTP port 587, which makes life easier as an addressee, as many popular mailservers would prefer to send to port 587. Note that SMTP port number itself has little to do with the use of SSL.
    1. Edit /etc/postfix/master.cf and uncomment "submission inet n ..." line.
  2. Configure smtpd setting to require SSL by editing /etc/postfix/main.cf:
    1. smtpd_tls_cert_file=/etc/letsencrypt/live/yourhostname.com/fullchain.pem
    2. smtpd_tls_key_file=/etc/letsencrypt/live/youthostname.com/privkey.pem
    3. smtpd_tls_security_level = encrypt # this is the main setting to require SSL
    4. smtpd_tls_loglevel = 1 # raise to 2 or 3 if you plan to dig through logs /var/log/maillog
    5. smtpd_tls_received_header=yes
  3. Configure dovecot to require SSL:
    1. Edit /etc/dovecot/conf.d/10-auth.conf to specify
      1. disable_plaintext_auth = yes
    2. Edit /etc/dovecot/conf.d/10-master.conf to specify
      1. service pop3-login { ...
      2. inet_listener_pop3s {
      3. port = 995
      4. ssl = yes
      5. }
      6. }
    3. Edit /etc/dovecot/conf.d/10-ssl.conf. Mind "<" signs for ssl_cert and ssl_key.
      1. ssl = required
      2. ssl_cert=</etc/letsencrypt/live/yourhostname.com/fullchain.pem
      3. ssl_key=</etc/letsencrypt/live/yourhostname.com/privkey.pem
  4. Restart postfix and dovecot, open ports 587 and 995 on EC2 instance, configure SMTP in your client to use port 587 and "Use the following type of encrypted connection = TLS", configure POP3 in your client to use port 995. Tests should pass.
Relay sending SMTP messages to Amazon SES. The above SMTP and POP3 client setup looks identical to the one for Gmail, which brings the false sense that we are done. Your first e-mail from such self-hosted SMTP server to Gmail will end up in a Spam folder. I know as I tried it. The problem is that your own SMTP server doesn't have an authority standing by it to certify that the sender is good. Amazon SES serves as such authority after you promise them you won't be doing anything bad. In short, an e-mail from your SMTP server needs to be relayed to Amazon SES server in a correct hosting zone. Then Amazon SES provides reverse DNS lookup.
  1. Sign up with Amazon SES, verify your primary e-mail on yourhostname.com and e-mail on Gmail, obtain a correct relay host based on a hosting zone, obtain SMTP credentials, verify DKIM. Generally follow guide for integration with postfix.
  2. Configure smtp server for relay. As a rule of thumb "smtpd" server handles e-mail by itself, while "smtp" server asks someone else to handle their e-mail => we need "smtp" and many smtpd options need to be duplicated into smtp options:
    1. Edit /etc/postfix/main.cf to specify
      1. relayhost = email-smtp.us-east-1.amazonaws.com:25 # port doesn't matter - 587 is as good as 25, the server depends on a hosting zone
      2. smtp_sasl_auth_enable = yes
      3. smtp_sasl_security_options = noanonymous
      4. smtp_tls_security_level = encrypt #outgoing connection must be secure as well
      5. smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd
      6. smtp_use_tls = yes
      7. smtp_tls_note_starttls_offer = yes
      8. smtp_sasl_mechanism_filter = plain, login # essential, but not found in a official guide
      9. smtp_tls_CAfile = /etc/ssl/certs/ca-bundle.crt # we verify authenticity of Amazon SES server
      10. smtp_sasl_type = cyrus # which is the default
    2. It may come as a surprise, but dovecot doesn't support SASL authentication for "smtp" and we have to use cyrus-sasl. One can store hashes of passwords in a file, which is simpler than the database:
      1. Ensure saslauthd service is running and is set to start automatically.
      2. Create /etc/postfix/sasl_passwd file with Amazon SES SMTP server and SMTP credentials.
      3. Run "sudo postmap hash:/etc/postfix/sasl_passwd" to generate a hash file referenced by password_maps above.
  3. Restart postfix and test sending/receiving e-mail between your 2 verified account.
  4. Apply on Amazon SES for a production account, which allows sending e-mail to unverified accounts (aka clients).
This is basically it! We now have a production e-mail system, which is fully secured and can send 50,000 high authority e-mails per day.  Dependent on the use case, you may consider forwarding incoming e-mails to Gmail.

Leave a Reply

Your email address will not be published. Required fields are marked *