Posted on Sun, 03 Jan 2016


How to setup a fully authenticated mail server on CentOs 7.


postfix + dovecot + amavisd + opendkim + letsencrypt + webmail on CentOS 7

How to setup a fully authenticated mail server on CentOs 7.

This howto will cover basics of setting up a postfix mail server with dovecot POP and IMAP client. Furthermore, we will show how to ensure our emails are not flagged as spam and are accepted by big email providers such as gmail. In the end we will setup webmail client and will sign our email and web server with an official certificate authority using letsencrypt.org.

Acknowledgments

This howto wouldn’t have happened if it weren’t for two excellent tutorials by Kliment Andreev and Stephane Caron and an excellent documentation by letsencrypt.org.

Before we start

The first thing we need to do is to check if our ip is not blacklisted. You can do it on blacklistalert.org or mxtoolbox, just type in your IP and it will list its status. If you IP is blacklisted then you need to ask you ISP for a new one.

Prerequisites

This assumes that you have a working installation of CentOs 7.

So first let’s upgrade

yum -y upgrade

Before we begin we’ll need to install epel repository, so type

yum -y install epel-release

In our first step we will just configure postfix and dovecot server without any encryption and after we verify that we have a working email server we’ll add encryption, spam filter and message signing.

Configuring postfix

Now let’s create a user and group that we’ll use for postfix

groupadd vpostfix && useradd vpostfix -g vpostfix -s /sbin/nologin -c "Virtual postfix user" -d /var/empty

Next, we need to check uid and gid of our newly created group and user.

grep vpostfix /etc/passwd && grep vpostfix /etc/group

You will see something like this. Remember these numbers because we will need them later.

vpostfix:x:1000:1000:Virtual postfix user:/var/empty:/sbin/nologin
vpostfix:x:1000:

Now edit main.cf in /etc/postfix and change the following lines (of course, replacing example.com with your real domain)

myhostname = www.example.com
mydomain = example.com
myorigin = $mydomain
inet_interfaces = all
home_mailbox = Maildir/

Add the following to the end of main.cf (be careful to put the same uid and gid as the ones we have just created)

# Virtual domain config
virtual_mailbox_domains = /etc/postfix/virtual_domains
virtual_mailbox_base = /var/mail/vhosts
virtual_mailbox_maps = hash:/etc/postfix/vmailbox

# Make sure you replace these UID:GID numbers
virtual_minimum_uid = 1000
virtual_uid_maps = static:1000
virtual_gid_maps = static:1000
virtual_alias_maps = hash:/etc/postfix/virtual

Now we have to create a file for virtual domains named /etc/postfix/virtual_domains. In this file we will list all domains that this mail server will serve. Do not forget to configure MX records of all these domains so that they point to this server.

cd /etc/postfix/
touch virtual_domains

Now edit the file virtual_domains and put each domain your mail server is going to server on separate line.

#  Each domain is on separate line
example.com
example2.com
example3.com

After that, create the directory for email, and create all subdirectories for the domains. Our e-mail will be stored in these directories.

mkdir /var/mail/vhosts
chgrp -R vpostfix /var/mail
cd /var/mail/vhosts
mkdir example.com
mkdir example2.com
mkdir example3.com
cd ..
chown -R vpostfix:vpostfix vhosts

Postfix will now create the “Maildir” directories automatically and will assign them proper permissions.

Now, create a file /etc/postfix/vmailbox and in that file list all of the users for all the domains that will receive e-mails.

dragan@example.com        example.com/dragan/
john@example2.com         example2.com/john/

Be sure to end up each line with “/”, or mail will not be delivered.

Now, let’s create the virtual aliases file and create a local aliases file.

touch /etc/postfix/virtual
cd /etc
postalias aliases

When we’ve added all our users, we need to do the following to create the hashed files.

NOTE: These two commands need to be executed anytime you make a change to these files (virtual_domains and vmailbox).

postmap /etc/postfix/virtual
postmap /etc/postfix/vmailbox

You should restart postfix now so it can reload new settings.

systemctl restart postfix

You can check the log file with the command:

tail /var/log/maillog

You should see that the daemon is started, something like this:

Dec 18 08:00:30 sysname postfix/postfix-script[26682]: stopping the Postfix mail system
Dec 18 08:00:30 sysname postfix/master[1014]: terminating on signal 15
Dec 18 08:00:30 sysname postfix/postfix-script[26764]: starting the Postfix mail system
Dec 18 08:00:30 sysname postfix/master[26766]: daemon started -- version 2.10.1, configuration /etc/postfix

You can check if postfix is up and listens on port 25 with:

ps -eaf | grep postfix
root     26766     1  0 08:00 ?        00:00:00 /usr/libexec/postfix/master -w
postfix  26767 26766  0 08:00 ?        00:00:00 pickup -l -t unix -u
postfix  26768 26766  0 08:00 ?        00:00:00 qmgr -l -t unix -u
root     26793  8708  0 08:01 pts/0    00:00:00 grep --color=auto postfix

ss -l | grep smtp
u_str  LISTEN     0      100    private/smtp 42340                 * 0
tcp    LISTEN     0      100     *:smtp                  *:*
tcp    LISTEN     0      100    :::smtp                 :::*

If you don’t see anything in the log and you verified that postfix is listening on port 25 from the server itself, it is probably a firewall issue. Do not forget to open the SMTP port.

firewall-cmd --add-service=smtp --permanent
success
firewall-cmd --reload
success

Now is the time to test your email server. send a mail to user@example.com (of course, replacing user and example.com with your real username and domain names).

tail -f /var/log/maillog

you should see something like this:

Dec 18 08:04:32 example postfix/smtpd[27607]: connect from www.somedomain.com[46.101.163.203]
Dec 18 08:04:32 example postfix/smtpd[27607]: B5D433FDFE: client=www.somedomain.com[46.101.163.203]
Dec 18 08:04:32 example postfix/cleanup[27611]: B5D433FDFE: message-id=<5674045E.3010300@somedomain.com>
Dec 18 08:04:32 example postfix/qmgr[26768]: B5D433FDFE: from=<dragan@somedomain.com>, size=1700, nrcpt=1 (queue active)
Dec 18 08:04:32 example postfix/smtpd[27607]: disconnect from www.somedomain.com[46.101.163.203]
Dec 18 08:04:32 example postfix/virtual[27612]: B5D433FDFE: to=<dragan@example.com>, relay=virtual, delay=0.06, delays=0.03/0.03/0/0, dsn=2.0.0, status=sent (delivered to maildir)
Dec 18 08:04:32 example postfix/qmgr[26768]: B5D433FDFE: removed

After we’ve made sure we can receive e-mail we will now install dovecot.

Installing dovecot

yum -y install dovecot

We will now configure dovecot for simple authentication without any encryption. After we make sure dovecot is up and running we will add encryption.

Edit /etc/dovecot/dovecot.conf and uncomment the following line

protocols = imap pop3 lmtp

Then head to /etc/dovecot/conf.d directory and change the following files:

10-auth.conf

disable_plaintext_auth = no
#!include auth-system.conf.ext
!include auth-passwdfile.conf.ext

10-logging.conf

log_path = /var/log/dovecot.log
auth_verbose = no
auth_debug = no
verbose_ssl = no

10-mail.conf (be careful to put your vpostfix uid and gid)

mail_home = /var/mail/vhosts/%d/%n
mail_location = maildir:~
mail_uid = 1000    # Your vpostfix UID
mail_gid = 1000    # Your vpostfix GID
mail_privileged_group = vpostfix

10-master.conf

unix_listener auth-userdb {
  mode = 0600
  user = vpostfix
  group =  vpostfix
}
# Postfix smtp-auth
unix_listener /var/spool/postfix/private/auth {
  mode = 0666
  user = vpostfix
  group = vpostfix
}

10-ssl.conf

ssl = no
# ssl_cert = </etc/ssl/certs/dovecot.pem
# ssl_key = </etc/ssl/private/dovecot.pem

Creating users

In file /etc/dovecot/conf.d/10-auth.conf we have uncommented the line !include auth-passwdfile.conf.ext. If we check that file we’ll see the following:

passdb {
  driver = passwd-file
  args = scheme=CRYPT username_format=%u /etc/dovecot/users
}

userdb {
  driver = passwd-file
  args = username_format=%u /etc/dovecot/users

  # Default fields that can be overridden by passwd-file
  #default_fields = quota_rule=*:storage=1G

  # Override fields from passwd-file
  #override_fields = home=/home/virtual/%u
}

This file sets the location of our users file. Currently it is in /etc/dovecot/users. If you want to keep it elsewhere you need to change those lines.

Now let’s put our users in the file. We can create the hashed password with the following command:

doveadm pw -s SHA512-CRYPT

This will ask you for password and will give you a hash of your password. You should put it in /etc/dovecot/users like this:

dragan@example.com:{SHA512-CRYPT}$6$1PrBJZz7QsUJBhVw$Ww39ihL9UtPrdk/3ORrEj7NTueTa.hpjy9ufboLoH0EjQBUwk0brezb.wIYrZ6CarfR629XGGzoLazkoev3wp1::::

So, the format is your email, followed by colon, followed by hash line given by doveadm and followed by 4 colons. Since it can be pretty tedious job to copy-paste these lines for each of your users what I usually do is to just list the names of users in the file like this:

dragan@example.com
john@example2.com
...

and then use some script like this one below that will fill passwords for users:

username="$1"
password="$2"

newpassword=$(doveadm pw -s SHA512-CRYPT -p "${password}")
newrow=${username}':'${newpassword}'::::'

sed -i '/'$username'/c\'$newrow'' /etc/dovecot/users

With this solution your users will not be able to change their passwords. The only way to change the password is to type these commands in the console but we will see later how to make a script that will give them the ability to change their passwords through webmail client.

starting dovecot

systemctl start dovecot
systemctl enable dovecot
tail /var/log/dovecot.log

You should see something like this

Dec 21 08:29:13 master: Info: Dovecot v2.2.10 starting up for imap, pop3, lmtp (core dumps disabled)

Now, let’s check our e-mail. You can do that from the server using the telnet command.

For IMAP, do the following.

telnet localhost 143
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
+ OK [CAPABILITY IMAP4rev1 LITERAL+ SASL-IR LOGIN-REFERRALS ID ENABLE IDLE AUTH=PLAIN] Dovecot ready.
? login dragan@example.com mypassword
? OK [CAPABILITY IMAP4rev1 LITERAL+ SASL-IR LOGIN-REFERRALS ID ENABLE IDLE SORT SORT=DISPLAY THREAD=REFERENCES THREAD=REFS THREAD=ORDEREDSUBJECT MULTIAPPEND URL-PARTIAL CATENATE UNSELECT CHILDREN NAMESPACE UIDPLUS LIST-EXTENDED I18NLEVEL=1 CONDSTORE QRESYNC ESEARCH ESORT SEARCHRES WITHIN CONTEXT=SEARCH LIST-STATUS SPECIAL-USE BINARY MOVE] Logged in
? list "" "*"
+ LIST (\HasNoChildren) "." INBOX
? OK List completed.
? logout
+ BYE Logging out
? OK Logout completed.
Connection closed by foreign host.

Now that we have our postfix and dovecot up and running, the next step will be to add some security

Adding security

Installing certificates from letsencrypt.org

The first thing we’ll do is to install certificates for our server. For that we’ll use certificate authority named let’s encrypt, it’s aim is to provide free certificates through automated process. The only drawback is that it uses port 80 for its work so if you have http server active you’ll have to stop it for now, we’ll show later how it can be automated without stopping it.

In this example I presume that you do not have your http server active. Also if you server has more than one cname you will have to get certificates for all its names. You can get certificates for each of your cnames (example.com, mail.example.com, www.example.com) or you can have one certificate for all your cnames. In this example I have asked for one certificate for multiple cnames, just substitute example.com with your domain name.

cd ~
yum -y install git
git clone https://github.com/letsencrypt/letsencrypt
cd letsencrypt

At this step it is important that you have port 80 open on your server, so if it is not already open, type the following:

firewall-cmd --add-port=80/tcp --permanent
firewall-cmd --reload

It is also important to have your DNS properly configured for all of the domains that you will be asking certificates for.

./letsencrypt-auto certonly --standalone -d example.com -d www.example.com -d mail.example.com -d webmail.example.com

This will first install additional packages if needed and configure a few things. Follow the instructions on the screen.

Our certificates are now stored in /etc/letsencrypt/live/example.com. These certificates are valid for three months only, so before they expire you will have to request new ones periodically.

Adding security to postfix

In /etc/postfix/main.cf add the following text to the end of file. Substitute your certificate directory in smtpd_tls_key_file and smtpd_tls_cert_file

# TLS
smtpd_use_tls = yes
smtpd_tls_security_level = may
smtpd_tls_auth_only = yes
smtpd_tls_key_file = /etc/letsencrypt/live/example.com/privkey.pem
smtpd_tls_cert_file = /etc/letsencrypt/live/example.com/fullchain.pem
smtpd_tls_loglevel = 1
smtpd_tls_received_header = yes
smtpd_tls_session_cache_timeout = 3600s
tls_random_source = dev:/dev/urandom

# SASL
smtpd_sasl_type = dovecot
broken_sasl_auth_clients = yes
smtpd_sasl_path = private/auth
smtpd_sasl_auth_enable = yes
smtpd_sasl_security_options = noanonymous
smtpd_recipient_restrictions = permit_sasl_authenticated, permit_mynetworks, reject_unauth_destination
smtpd_relay_restrictions = permit_sasl_authenticated, permit_mynetworks, reject_unauth_destination

After that edit the /etc/postfix/master.cf and remove the comments to look like this.

submission inet n       -       n       -       -       smtpd
  -o syslog_name=postfix/submission
  -o smtpd_tls_security_level=encrypt
  -o smtpd_sasl_auth_enable=yes
  -o smtpd_reject_unlisted_recipient=no
#  -o smtpd_client_restrictions=$mua_client_restrictions
#  -o smtpd_helo_restrictions=$mua_helo_restrictions
#  -o smtpd_sender_restrictions=$mua_sender_restrictions
  -o smtpd_recipient_restrictions=permit_sasl_authenticated,reject
  -o milter_macro_daemon_name=ORIGINATING

Restart postfix after these changes and add the following firewall rules.

systemctl restart postfix
firewall-cmd --add-port=587/tcp --permanent
firewall-cmd --reload

If you do telnet localhost 587 and type EHLO something.com you should see that postfix replies with STARTTLS.

telnet localhost 587
Trying ::1...
Connected to localhost.
Escape character is '^]'.
220 www.example.com ESMTP Postfix
ehlo example.com
250-www.example.com
250-PIPELINING
250-SIZE 10240000
250-VRFY
250-ETRN
250-STARTTLS
250-ENHANCEDSTATUSCODES
250-8BITMIME
250 DSN
quit
221 2.0.0 Bye
Connection closed by foreign host.

Now that we have postfix secured let’s do the same for dovecot

dovecot and SSL

Let’s head back to /etc/dovecot/conf.d directory

cd /etc/dovecot/conf.d

And then edit 10-auth.conf and change:

disable_plaintext_auth = yes

Then, edit 10-ssl.conf and change:

ssl = yes
ssl_cert = </etc/letsencrypt/live/example.com/fullchain.pem
ssl_key = </etc/letsencrypt/live/example.com/privkey.pem

Both postfix and dovecot should be able to use those certificates now, so you should restart them now.

systemctl restart postfix
systemctl restart dovecot

You can test SMTP SSL/TLS connection on port 587 with the following command:

openssl s_client -starttls smtp -connect localhost:587

Then type

ehlo example.com,
mail from:user@example.com.

If these steps work, you should be OK. To test SASL with postfix and dovecot, type:

doveadm auth test -a /var/spool/postfix/private/auth user@exmaple.com your_password
passdb: user@example.com auth succeeded
extra fields:
  user=user@example.com

If you want you can open the firewall for IMAPs and POP3s.

firewall-cmd --add-port=993/tcp --permanent
firewall-cmd --add-port=995/tcp --permanent
firewall-cmd --reload

You can now test your e-mail server by setting it up in your favourite e-mail client. You should be able to send and receive email. However your server is currently open to all kinds of spam and not all email providers will accept your emails (google mail will probably mark your messages as spam). So, let’s now configure your spam filter.

Amavisd, Spamassassin and clamav

To test email for spam you will need spamassassin, to test it for viruses you will need clamav and you will need amavisd which is an interface between these two programs and postfix. When you install amavisd-new, clamav and spamassassin will be installed automatically.

yum install -y amavisd-new
yum install -y clamav-update

First we need to configure amavisd. The configuration file is /etc/amavisd/amavisd.conf. Edit this file and make sure that these values are correct.

# @bypass_virus_checks_maps = (1);  # controls running of anti-virus code
# @bypass_spam_checks_maps  = (1);  # controls running of anti-spam code
# $bypass_decode_parts = 1;         # controls running of decoders&dearchivers
$daemon_user  = 'amavis';     # (no default;  customary: vscan or amavis), -u
$daemon_group = 'amavis';     # (no default;  customary: vscan or amavis), -g
$mydomain = 'example.com';   # a convenient default for other settings (change it)
$MYHOME = '/var/spool/amavisd';   # a convenient default for other settings, -H (remove the comment in front)
@local_domains_maps = ( [".$mydomain","myotherdomain.net"] );  # list of all local domains. If you have multiple domains, add the here.
$myhostname = 'host.example.com';  # must be a fully-qualified domain name! (remove the comment in front)



# ### http://www.clamav.net/
['ClamAV-clamd',
  \&ask_daemon, ["CONTSCAN {}\n", "/var/run/clamav/clamd.sock.sock"],
  qr/\bOK$/m, qr/\bFOUND$/m,
  qr/^.*?: (?!Infected Archive)(.*) FOUND$/m ],
# # NOTE: run clamd under the same user as amavisd - or run it under its own
# #   uid such as clamav, add user clamav to the amavis group, and then add
# #   AllowSupplementaryGroups to clamd.conf;
# # NOTE: match socket name (LocalSocket) in clamav.conf to the socket name in
# #   this entry; when running chrooted one may prefer a socket under $MYHOME.

A WORD OF ADVICE: Clamav and memory. For clamav to work properly it needs a lot of memory. At least two 2GB of ram memory is recommended. If you have 1GB or less you will need to turn off your virus scanner. You can do it by uncommenting the following line in /etc/amavisd/amavisd.conf:

@bypass_virus_checks_maps = (1);  # controls running of anti-virus code

and commenting out the following lines in the same file:

# ### http://www.clamav.net/
#['ClamAV-clamd',
#  \&ask_daemon, ["CONTSCAN {}\n", "/var/run/clamav/clamd.sock.sock"],
#  qr/\bOK$/m, qr/\bFOUND$/m,
#  qr/^.*?: (?!Infected Archive)(.*) FOUND$/m ],
# # NOTE: run clamd under the same user as amavisd - or run it under its own
# #   uid such as clamav, add user clamav to the amavis group, and then add
# #   AllowSupplementaryGroups to clamd.conf;
# # NOTE: match socket name (LocalSocket) in clamav.conf to the socket name in
# #   this entry; when running chrooted one may prefer a socket under $MYHOME.

Now, we need to connect postfix to amavisd. Add the following lines at the end of /etc/postfix/master.cf

# Amavisd
amavisfeed unix - - n - 2 lmtp
        -o lmtp_data_done_timeout=1200
        -o lmtp_send_xforward_command=yes
127.0.0.1:10025 inet n - n - - smtpd
        -o content_filter=
        -o smtpd_delay_reject=no
        -o smtpd_client_restrictions=permit_mynetworks,reject
        -o smtpd_helo_restrictions=
        -o smtpd_sender_restrictions=
        -o smtpd_recipient_restrictions=permit_mynetworks,reject
        -o smtpd_data_restrictions=reject_unauth_pipelining
        -o smtpd_end_of_data_restrictions=
        -o smtpd_restriction_classes=
        -o mynetworks=127.0.0.0/8
        -o smtpd_error_sleep_time=0
        -o smtpd_soft_error_limit=1001
        -o smtpd_hard_error_limit=1000
        -o smtpd_client_connection_count_limit=0
        -o smtpd_client_connection_rate_limit=0
        -o receive_override_options=no_header_body_checks,no_unknown_recipient_checks,no_milters,no_address_mappings
        -o local_header_rewrite_clients=
        -o smtpd_milters=
        -o local_recipient_maps=
        -o relay_recipient_maps=

Edit /usr/local/etc/postfix/main.cf and add these lines at the end.

# Amavisd
content_filter = amavisfeed:[127.0.0.1]:10024

Now we need to prepare everything for antivirus scanner. If you have decided to opt-out of antivirus scanning you do not need to do these lines.

Edit /etc/freshclam.conf and remove or comment out the Example line.

# Comment or remove the line below.
Example

After that, edit /etc/sysconfig/freshclam and remove all 4 lines at the bottom.

### !!!!! REMOVE ME !!!!!!
### REMOVE ME: By default, the freshclam update is disabled to avoid
### REMOVE ME: network access without prior activation
FRESHCLAM_DELAY=disabled-warn   # REMOVE ME

You can now update antivirus definitions with the following command:

freshclam

And after that you can update spamassassins’s signatures.

  sa-update -D

The “-D” option is to run in debug mode so you can see what’s going on. If there is an update available, spamassassin’s exit code is 0, if not the exit code is 1. In case there is an update, we’ll have to restart the spamassassin’s daemon.
Check the cron folder and make sure you see both clamav-update and sa-update files.

cd /etc/cron.d
ls -l clamav-update sa-update

Now, we can start everything.

systemctl start amavisd
systemctl enable amavisd
systemctl start spamassassin
systemctl enable spamassassin

Once you start amavisd, clamd starts as well. Finally, let’s restart postfix.

systemctl restart postfix

Check the connection between amavisd and postfix.

telnet localhost 10024

Type ehlo localhost and check the ouput. In my case it looks like this.

250-[127.0.0.1]
250-VRFY
250-PIPELINING
250-SIZE
250-ENHANCEDSTATUSCODES
250-8BITMIME
250-DSN
250 XFORWARD NAME ADDR PORT PROTO HELO IDENT SOURCE

Then do

telnet localhost 10025

Again, type ehlo localhost and check the ouput. In my case it looks like this.

250-www.example.org
250-PIPELINING
250-SIZE 10240000
250-VRFY
250-ETRN
250-STARTTLS
250-ENHANCEDSTATUSCODES
250-8BITMIME
250 DSN

Your email server should now be protected against spam and viruses. To test it go to Email Security Check and follow the instructions there. The system will send you 7 emails, all of them should be caught by amavisd.

Now that we’ve installed spam filter you have to prove that you are not a spammer. That means that every email will have to be signed using DKIM.

Proving that you are not a spammer - signing your email messages with openDKIM

yum install -y opendkim pypolicyd-spf

Now edit /etc/opendkim.conf and make sure it contains the following lines (change example.com to your domain)

Mode        sv 
Domain          example.com
KeyTable           refile:/etc/opendkim/KeyTable
SigningTable       refile:/etc/opendkim/SigningTable
ExternalIgnoreList refile:/etc/opendkim/TrustedHosts
InternalHosts      refile:/etc/opendkim/TrustedHosts
LogWhy yes

Also, check the number of socket port for opendkim service, you will need it later

Socket      inet:8891@localhost

Now we will create our signing keys

cd /etc/opendkim/keys
mkdir example.com
cd example.com
opendkim-genkey -s default -d example.com
chown opendkim:opendkim default.private
cd /etc/opendkim/

Edit /etc/opendkim/KeyTable and add the following line:

default._domainkey.example.com example.com:default:/etc/opendkim/keys/example.com/default.private

After that, edit /etc/opendkim/SigningTable and add the following

*@example.com default._domainkey.example.com

And finally edit /etc/opendkim/TrustedHosts and add your domain name and your full host name.

example.com
www.example.com

Now that we’ve configured opendkim we have to put the public key in our DNS record, so type the following

cat /etc/opendkim/keys/example.com/default.txt

You will get something like this:

default._domainkey      IN      TXT     ( "v=DKIM1; k=rsa; "
          "p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrIUYTOyl+IT3+CvGqZP0lgT5gPHKjVMIcm/GySA+0KP8/uK9JK2CM2Lu+i3qSCXlcVpvFMV8m5P5iRANkO3nGZXKOKPnabMvGt+Sa6INJd7LRR1OUKv+MzP9A83WVXTdwuy5nzr6bM03xin1E/3BimxS3xytzcGiFsnSL+UHn9wIDAQAB" )  ; ----- DKIM key default for example.com

Now use this to create a new DNS record for your domain. It has to be a TXT record where key is “default._domainkey” and value is the text inside the parenthesis (without the quotes).

While we are at your DNS records, you will also need to add two other TXT records, first add a nameless (@) TXT record with the following value (change YOUR_IPv4_ADDRESS AND YOUR_IPv6_ADDRESS to match your values):

v=spf1 a mx ip4:YOUR_IPv4_ADDRESS ip6:YOUR_IPv6_ADDRESS ~all

and then add the “_dmarc” TXT record with the following value:

v=DMARC1; p=none

Now let’s check if those values are visible.

yum install bind-utils
dig default._domainkey.example.com TXT

You should receive the same value that you’ve entered in your DNS record:

;; ANSWER SECTION:
default._domainkey.example.com. 1799 IN TXT "v=DKIM1\; k=rsa\; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCw7O7uyU/Lkn9BaQwA8obSm13EXwYf44QD+XMb2kdYbPhW4Q/NyITpR4DH+/GEYadHrN+7ezygVaG7J+Hg0u6YRL34QYN5fTVT/aon2X0GvJeT1xNsggYy50pHgTkVzYGhUyhhepHhxt2Yc12GVeibZj505MnvlvuMeU9Xs3iRiQIDAQAB"

We now have to modify postfix configuration and to tell it to use opendkim

Add the following to /etc/postfix/master.cf

policy-spf  unix  -       n       n       -       -       spawn
     user=nobody argv=/usr/libexec/postfix/policyd-spf

Change the following line in /etc/postfix/main.cf to

smtpd_recipient_restrictions = permit_sasl_authenticated, permit_mynetworks, reject_unauth_destination, check_policy_service, unix:private/policy-spf

And also add the following lines to /etc/postfix/main.cf. Port values for smtpd_milters and non_smtpd_milters should be the same as in “Socket” in /etc/opendkim.conf

policy-spf_time_limit = 3600s

# DKIM
milter_default_action = accept
milter_protocol = 6
smtpd_milters = inet:localhost:8891
non_smtpd_milters = inet:localhost:8891

Now let’s start opendkim and restart postfix.

systemctl start opendkim
systemctl enable opendkim
systemctl restart postfix

And that should be it.

You can check if dkim signature is added if you check your maillog and send an email.

tail -f /var/log/maillog

You should see a line similar to this

Dec 28 18:11:25 example opendkim[1169]: 03DD041429: DKIM-Signature field added (s=default, d=example.com)

If you send an email to your other email address and check the source you should see the DKIM signature in the header, it will look like this:

...
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=example.com;
  s=default; t=1450868845;
  bh=1i0m94nmanDDd6Gu/03Obw9meKedLOruAZb2JFtSyfY=;
  h=To:From:Subject:Date:From;
  b=TvscdTJaWJps1khxQ5dqw/TWLkZbSWhZqPa0JnnuG076Xom2KJDFzQSBLz7XVylKS
   jVtdw7q23QAslgzcDHLPT/099f7dB4x4gPwABuN6W0Km7B8EGJYI/0QCmp359PfalT
   nr8Pv5EoC1pbRS+oaMGDamRVF8zHfHpp5MO8OYRM=
...

You can also check your e-mail score on www.mail-tester.com. If everything went well you should receive a perfect score of 10/10. Your e-mail server is now fully configured and ready to send and receive e-mail. If you wish you can also install webmail client but that step is optional.

Installing webmail client

There are a lot of open source webmail clients, which one you choose to install is up to you. If you want simplicity you can choose squirrelmail, or if you want something modern you can choose one of many web 2.0 clients. In this example we will install Rainloop webmail client.

We shall set up our webmail server to be accessible on webmail.example.com so be sure to set up the appropriate DNS record.

yum -y install httpd php unzip mod_ssl
cd /var/www/html
mkdir webmail
wget http://repository.rainloop.net/v2/webmail/rainloop-community-latest.zip
unzip rainloop-community-latest.zip
rm rainloop-community-latest.zip
cd ..
chown -R apache.apache webmail

firewall-cmd --add-port=443/tcp --permanent
firewall-cmd --reload

Now edit the file /etc/httpd/conf.d/ssl.conf. Find the section and add the following lines:

<VirtualHost _default_:443>

# General setup for the virtual host, inherited from global configuration
DocumentRoot "/var/www/html/webmail"
ServerName webmail.example.com:443

In the same section change the following lines:

#   Server Certificate:
# Point SSLCertificateFile at a PEM encoded certificate.  If
# the certificate is encrypted, then you will be prompted for a
# pass phrase.  Note that a kill -HUP will prompt again.  A new
# certificate can be generated using the genkey(1) command.
SSLCertificateFile /etc/letsencrypt/live/example.com/cert.pem

#   Server Private Key:
#   If the key is not combined with the certificate, use this
#   directive to point at the key file.  Keep in mind that if
#   you've both a RSA and a DSA private key you can configure
#   both in parallel (to also allow the use of DSA ciphers, etc.)
SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem

#   Server Certificate Chain:
#   Point SSLCertificateChainFile at a file containing the
#   concatenation of PEM encoded CA certificates which form the
#   certificate chain for the server certificate. Alternatively
#   the referenced file can be the same as SSLCertificateFile
#   when the CA certificates are directly appended to the server
#   certificate for convinience.
SSLCertificateChainFile /etc/letsencrypt/live/example.com/chain.pem

We have now installed our certificates into http server.

now start the httpd server

systemctl enable httpd
systemctl start httpd

You can now try to access your webmail server on https://webmail.example.com. It should give you the login screen. First you need to configure it, so open the admin page on https://webmail.example.com/?admin. It will open a login page to the admin panel. Default login for is “admin”, password “12345” so be sure to change it immediately after login. Setting up rainloop webmail is pretty straightforward, click on “domains” and there click on “add domain” button. There you can set up access to your mail server.

Type your domain name there like shown on the picture and press “test” button. If everything is ok, click to “add” and then “close”. And there it is, your webmail server is set up.

Bonus track: giving users a way to change their passwords.

If you remember when we were creating passwords for our e-mail users we mentioned that the only way to change the password would be to log in to server terminal and to change it by hand. Now that we have a working webmail we can use it to enable users to change their own passwords. For that we will use rainloop’s own change password example.

you should first download rainloop’s source

cd ~
git clone https://github.com/RainLoop/rainloop-webmail.git

For rainloop to be able to change password we need to create a script and it needs to be able to access the file. Therefore we will move our password file somewhere where rainloop can access it. We shall put it in /var/www/dovecot directory and of course we have to tell dovecot the new location of the file.

mkdir /var/www/dovecot
mv /etc/dovecot/users /var/www/dovecot

Now that we have moved the file we need to change the configuration file of the dovecot. Edit the file /etc/dovecot/conf.d/10-auth.conf and change value /etc/dovecot/users it to /var/www/dovecot/users like this:

passdb {
  driver = passwd-file
  args = scheme=CRYPT username_format=%u /var/www/dovecot/users
}

userdb {
  driver = passwd-file
  args = username_format=%u /var/www/dovecot/users
}

After that we need to restart dovecot to reload the changes

systemctl restart dovecot

We will now create a script that will change password on rainloop’s demand.

cd /var/www/dovecot
touch pwdchange.sh
chmod +c pwdchange.sh
chown -R apache.apache /var/www/dovecot

Now edit the pwdchange.sh and put the following:

username="$1"
password="$2"

newpassword=$(doveadm pw -s SHA512-CRYPT -p "${password}")
newrow=${username}':'${newpassword}'::::'

sed -i '/'$username'/c\'$newrow'' /var/www/dovecot/users

This script takes two arguments, the first one is username whose password is to be changed and the second one is the new password. You can call it like this:

./pwdchange.sh dragan@example.com mynewpassword

Or if you want a passphrase you can put it in quotation marks:

./pwdchange.sh dragan@example.com "my new passphrase"

Now that we have moved users file and the script is ready we can create rainloop plugin that will use it.

We will now use rainloop’s change password example plugin and to copy it to our rainloop installation.

cd /var/www/html/webmail/data/_data_/_default_/plugins/
mkdir change-password-mydomain
cd ~/rainloop-webmail/plugins/change-password-example
cp * /var/www/html/webmail/data/_data_/_default_/plugins/change-password-mydomain
cd /var/www/html/webmail/data/_data_/_default_/plugins
chown -R apache.apache change-password-mydomain
cd change-password-mydomain

Now edit the file ChangePasswordExampleDriver.php, locate the function called ChangePassword and under the //TODO add the following line

exec('/var/www/dovecot/pwdchange.sh '.$oAccount->Email().' "'.$sNewPassword.'"');

And there it is. Now all you have to do is login to webmail with Admin password, go to settings, click on enable plugins and check on change-password-mydomain plugin and that’s it. Your users will now be able to change their passwords from their webmail.



Log in to leave a comment