{"id":160,"date":"2016-03-29T13:27:53","date_gmt":"2016-03-29T11:27:53","guid":{"rendered":"http:\/\/blog.le-vert.net\/?p=160"},"modified":"2016-03-29T13:28:36","modified_gmt":"2016-03-29T11:28:36","slug":"master-master-simple-email-server-with-dovecot","status":"publish","type":"post","link":"https:\/\/blog.le-vert.net\/?p=160","title":{"rendered":"Master-master simple email server with Dovecot"},"content":{"rendered":"<div class=\"twttr_buttons\"><div class=\"twttr_twitter\">\n\t\t\t\t\t<a href=\"http:\/\/twitter.com\/share?text=Master-master+simple+email+server+with+Dovecot\" class=\"twitter-share-button\" data-via=\"\" data-hashtags=\"\"  data-size=\"default\" data-url=\"https:\/\/blog.le-vert.net\/?p=160\"  data-related=\"\" target=\"_blank\">Tweet<\/a>\n\t\t\t\t<\/div><\/div><p>The purpose of this article is to explain how to create an hight availability email server with Dovecot.<br \/>\nWe will use internal plain text files as users backend but it can of course easily be extended to use LDAP or SQL, but this article won&#8217;t cover this setup.<\/p>\n<h1>Install required packages<\/h1>\n<p>On both servers we&#8217;ll install dovecot as well as the POP3 and IMAP backends<\/p>\n<pre>apt-get install dovecot-core dovecot-imapd dovecot-pop3d<\/pre>\n<p>To use dovecot clustering feature, known as dsync, we need dovecot 2.2 or later. Debian Jessie&#8217;s version is ok.<\/p>\n<h1>Setup file-based users database<\/h1>\n<p>Edit <strong>\/etc\/dovecot\/conf.d\/auth-passwdfile.conf.ext<\/strong> and set both userdb and passworddb like this:<\/p>\n<pre>\r\npassdb {\r\n  driver = passwd-file\r\n  args = scheme=PLAIN username_format=%u \/etc\/dovecot\/users\r\n}\r\n\r\nuserdb {\r\n  driver = passwd-file\r\n  args = username_format=%u \/etc\/dovecot\/users\r\n  default_fields = uid=vmail gid=mail home=\/srv\/vmail\/%u\r\n}\r\n<\/pre>\n<p>I will use plaintext clear password here because I really want to be able to read the users from the configuration file directly. You can of course use an encrypted format, see <a href=\"http:\/\/wiki.dovecot.org\/Authentication\/PasswordSchemes\">Dovecot documentation<\/a>.<\/p>\n<p>The file <strong>\/etc\/dovecot\/users<\/strong> will contains the users accounts and we&#8217;ll deliver all emails using paths like <strong>\/srv\/vmail\/user@domain.com<\/strong>.<br \/>\nDovecot is set up to always use the vmail user with mail group to avoid uid\/gids madness.<\/p>\n<p>First I tried to create a multi-domain setup, using &#8220;username_format=%n \/etc\/dovecot\/%d\/users&#8221; and &#8220;default_fields = uid=vmail gid=mail home=\/srv\/vmail\/%d\/%n&#8221; but current master\/master plugin is unable to handle such configuration (<em>Error: passwd-file: User iteration isn&#8217;t currently supported with %variable paths<\/em>) so I decided to use a single authentication file using email as login (%u instead of %n).<\/p>\n<p>We need to create the system user for dovecot:<\/p>\n<pre>adduser --system --ingroup mail --uid 500 vmail --home \/srv\/vmail<\/pre>\n<p>Now we need to enable this backend by commenting auth-system and un-commenting auth-passwdfile from <strong>\/etc\/dovecot\/conf.d\/10-auth.conf<\/strong><\/p>\n<pre>\r\n#!include auth-system.conf.ext\r\n#!include auth-sql.conf.ext\r\n#!include auth-ldap.conf.ext\r\n!include auth-passwdfile.conf.ext\r\n#!include auth-checkpassword.conf.ext\r\n#!include auth-vpopmail.conf.ext\r\n#!include auth-static.conf.ext\r\n<\/pre>\n<h1>Configure Postfix to use Dovecot as delivery agent<\/h1>\n<p>In <strong>\/etc\/postfix\/master.cf<\/strong> add the following section:<\/p>\n<pre>\r\n# Dovecot LDA \r\ndovecot    unix  -       n       n       -       -       pipe\r\n  flags=DRhu user=vmail:mail argv=\/usr\/lib\/dovecot\/dovecot-lda -f ${sender} -a ${original_recipient} -d ${user}@${nexthop}\r\n<\/pre>\n<p>Then run the following command to make sure Postfix is configured correctly (postconf is a command that will edit main.cf config file):<\/p>\n<pre>\r\npostconf -e \"myhostname=`hostname -f`\"\r\npostconf -e \"mydestination=`hostname -f`, `hostname -s`.localdomain, `hostname -s`, localhost.`hostname -d`, localhost.localdomain, localhost\"\r\n<\/pre>\n<p>Please <strong>MAKE SURE<\/strong> your \/etc\/hosts and \/etc\/hostname are configured correctly !<br \/>\nThe following commands should return short\/full\/domain names:<\/p>\n<pre>\r\nhostname -s\r\nhostname -f\r\nhostname -d\r\n<\/pre>\n<p>Now we&#8217;ll enable Dovecot LDAP and enable our mail domain:<\/p>\n<pre>\r\npostconf -e virtual_transport=\"dovecot\"\r\npostconf -e dovecot_destination_recipient_limit=1\r\npostconf -e virtual_mailbox_domains=domain.com\r\n<\/pre>\n<h1>Additional Dovecot config<\/h1>\n<p>In <strong>\/etc\/dovecot\/conf.d\/10-mail.conf<\/strong> set<\/p>\n<pre>\r\nmail_location = maildir:~\/Maildir\r\n<\/pre>\n<p>It will deliver emails in Maildir format like this: \/srv\/vmail\/user@domain.com\/Maildir<\/p>\n<p>In <strong>\/etc\/dovecot\/conf.d\/10-auth.conf<\/strong> we&#8217;ll enable plain text login because we don&#8217;t care about SSL and stuff (non-encrypted auth is disabled for any host except localhost by default):<\/p>\n<pre>\r\ndisable_plaintext_auth = no\r\n<\/pre>\n<h1>Create first user and try it<\/h1>\n<p>Create <strong>\/etc\/dovecot\/users<\/strong> with the following content:<\/p>\n<pre>\r\ntest@domain.com:{plain}testpassword::::\r\n<\/pre>\n<p>And secure the file permissions:<\/p>\n<pre>\r\nchown root:dovecot \/etc\/dovecot\/users\r\nchmod 640 \/etc\/dovecot\/users\r\n<\/pre>\n<p>Finally restart dovecot, postfix and send a test email:<\/p>\n<pre>\r\nsystemctl restart dovecot\r\nsystemctl restart postfix\r\necho test | mail -s test test@domain.com && tail -f -n 20 \/var\/log\/syslog\r\n<\/pre>\n<p>You should see something like this in the logs:<\/p>\n<pre>\r\nMar 29 10:16:40 smtp1 postfix\/pickup[26046]: 0620580AE772: uid=0 from=<root>\r\nMar 29 10:16:40 smtp1 postfix\/cleanup[26052]: 0620580AE772: message-id=<20160329101640.0620580AE772@smtp1.service.domain.com>\r\nMar 29 10:16:40 smtp1 postfix\/qmgr[26047]: 0620580AE772: from=<root@smtp1.service.domain.com>, size=339, nrcpt=1 (queue active)\r\nMar 29 10:16:40 smtp1 dovecot: lda(test@domain.com): msgid=<20160329101640.0620580AE772@smtp1.service.domain.com>: saved mail to INBOX\r\nMar 29 10:16:40 smtp1 postfix\/pipe[26055]: 0620580AE772: to=<test@domain.com>, relay=dovecot, delay=0.04, delays=0.02\/0.01\/0\/0.02, dsn=2.0.0, status=sent (delivered via dovecot service)\r\nMar 29 10:16:40 smtp1 postfix\/qmgr[26047]: 0620580AE772: removed\r\n<\/pre>\n<p>The key part here is <strong>dovecot: lda(test@domain.com): msgid=<id>: saved mail to INBOX<\/strong>.<\/p>\n<p>We can now check what happened on the filesystem:<\/p>\n<pre>\r\nroot@smtp1.service.domain.com:~# find \/srv\/vmail\/\r\n\/srv\/vmail\/\r\n\/srv\/vmail\/test@domain.com\r\n\/srv\/vmail\/test@domain.com\/Maildir\r\n\/srv\/vmail\/test@domain.com\/Maildir\/cur\r\n\/srv\/vmail\/test@domain.com\/Maildir\/new\r\n\/srv\/vmail\/test@domain.com\/Maildir\/new\/1459247005.M110518P26261.smtp1.service.domain.com,S=412,W=423\r\n\/srv\/vmail\/test@domain.com\/Maildir\/tmp\r\n\/srv\/vmail\/test@domain.com\/Maildir\/dovecot.index.log\r\n\/srv\/vmail\/test@domain.com\/Maildir\/dovecot-uidvalidity.56fa579d\r\n\/srv\/vmail\/test@domain.com\/Maildir\/dovecot-uidvalidity\r\n\/srv\/vmail\/test@domain.com\/Maildir\/dovecot-uidlist\r\n\/srv\/vmail\/test@domain.com\/Maildir\/dovecot.index.cache\r\n<\/pre>\n<p>Now we can test IMAP login will the following transcript using telnet:<\/p>\n<pre>telnet 127.0.0.1 143<\/pre>\n<pre>\r\n. LOGIN test@domain.com testpassword\r\n. EXAMINE INBOX\r\n. FETCH 1 BODY[]\r\n. LOGOUT\r\n<\/pre>\n<p>You should see the message body containing &#8220;test&#8221;. If so, we now have a fully working email server.<\/p>\n<h1>Enable doveadm service and replication plugin<\/h1>\n<p>Create a new file <strong>\/etc\/dovecot\/local.conf<\/strong> with the following content:<\/p>\n<pre>\r\n# Doveadm (used by sync service)\r\nservice doveadm {\r\n  inet_listener {\r\n    # any port you want to use for this:\r\n    port = 2727\r\n  }\r\n}\r\n\r\ndoveadm_port = 2727\r\ndoveadm_password = mysecretpasswordsharedamongservers\r\n\r\n# Fix permissions for vmail user\r\nservice aggregator {\r\n  fifo_listener replication-notify-fifo {\r\n    user = vmail\r\n    group = root\r\n    mode = 0660\r\n  }\r\n  unix_listener replication-notify {\r\n    user = vmail\r\n    group = root\r\n    mode = 0660\r\n  }\r\n}\r\n<\/pre>\n<p>Then we&#8217;ll configure the peer address for replication plugin in <strong>\/etc\/dovecot\/conf.d\/90-plugin.conf<\/strong>:<\/p>\n<pre>\r\nplugin {\r\n  mail_replica = tcp:5.6.7.8:2727\r\n}\r\n<\/pre>\n<p>Now we will globally enable the replication plugin as well as the notify one (required), in <strong>\/etc\/dovecot\/conf.d\/10-mail.conf<\/strong>:<\/p>\n<pre>\r\nmail_plugins = notify replication\r\n<\/pre>\n<p>And that&#8217;s it&#8230; Yes, really, we&#8217;re done here !<\/p>\n<h1>Replicate config to secondary server<\/h1>\n<p>Here is my synchronisation script<\/p>\n<pre>\r\n#!\/bin\/sh\r\n\r\nme=\"1.2.3.4\"\r\npeer=\"5.6.7.8\"\r\n\r\n# Postfix\r\nrsync -avz --delete \/etc\/postfix\/ root@${peer}:\/etc\/postfix\/\r\nssh root@${peer} 'postconf -e \"mydestination=`hostname -f`, `hostname -s`.localdomain, `hostname -s`, localhost.`hostname -d`, localhost.localdomain, localhost\"'\r\nssh root@${peer} 'postconf -e \"myhostname=`hostname -f`\"'\r\nrsync -vz \/etc\/aliases root@${peer}:\/etc\/aliases\r\nssh root@${peer} newaliases\r\nsystemctl restart postfix\r\nssh root@${peer} systemctl restart postfix\r\nsleep 1\r\nssh root@${peer} systemctl status postfix\r\n\r\n# Dovecot\r\nrsync -avz --delete \/etc\/dovecot\/ root@${peer}:\/etc\/dovecot\/\r\nssh root@${peer} \"sed -i \\\"s|mail_replica = tcp:${peer}|mail_replica = tcp:${me}|\\\" \/etc\/dovecot\/conf.d\/90-plugin.conf\"\r\nsystemctl restart dovecot\r\nssh root@${peer} systemctl restart dovecot\r\nsleep 1\r\nssh root@${peer} systemctl status dovecot\r\n<\/pre>\n<p>Basically it sync the whole Postfix and Dovecot postfix, replace the hostname by the secondary server one in Postfix configuration and change the address in Dovecot&#8217;s <strong>mail_replica<\/strong> setting.<\/p>\n<p>You can now run <strong>echo test | mail -s test test@domain.com<\/strong> on both server and check that both filesystems are updated with all emails \ud83d\ude42<\/p>\n<pre>\r\nroot@smtp1.service.domain.com:~# find \/srv\/vmail\/\r\n\/srv\/vmail\/\r\n\/srv\/vmail\/test@domain.com\r\n\/srv\/vmail\/test@domain.com\/Maildir\r\n\/srv\/vmail\/test@domain.com\/Maildir\/cur\r\n\/srv\/vmail\/test@domain.com\/Maildir\/new\r\n\/srv\/vmail\/test@domain.com\/Maildir\/new\/1459247005.M110518P26261.smtp1.service.domain.com,S=412,W=423\r\n\/srv\/vmail\/test@domain.com\/Maildir\/new\/1459248844.M932607P26622.smtp1.service.domain.com,S=412,W=423\r\n\/srv\/vmail\/test@domain.com\/Maildir\/new\/1459249870.M304816P27522.smtp1.service.domain.com,S=412,W=423\r\n\/srv\/vmail\/test@domain.com\/Maildir\/new\/1459250003.M334397P27770.smtp1.service.domain.com,S=412,W=423\r\n\/srv\/vmail\/test@domain.com\/Maildir\/new\/1459250051.M437424P14567.smtp2.service.domain.com,S=436,W=447\r\n\/srv\/vmail\/test@domain.com\/Maildir\/tmp\r\n\/srv\/vmail\/test@domain.com\/Maildir\/dovecot.index.log\r\n\/srv\/vmail\/test@domain.com\/Maildir\/dovecot-uidvalidity.56fa579d\r\n\/srv\/vmail\/test@domain.com\/Maildir\/dovecot-uidvalidity\r\n\/srv\/vmail\/test@domain.com\/Maildir\/dovecot-uidlist\r\n\/srv\/vmail\/test@domain.com\/Maildir\/dovecot.index.cache\r\n<\/pre>\n<p>Of course, you can now connect two Thunderbird instances against 1.2.3.4 and 5.6.7.8 and then create folder, move emails, toggle read flag. Both will show the change with a very little delay.<\/p>\n<p>Thanks for reading and I hope that will help<\/p>\n","protected":false},"excerpt":{"rendered":"<p>The purpose of this article is to explain how to create an hight availability email server with Dovecot. We will use internal plain text files as users backend but it can of course easily be extended to use LDAP or &hellip; <a href=\"https:\/\/blog.le-vert.net\/?p=160\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"_links":{"self":[{"href":"https:\/\/blog.le-vert.net\/index.php?rest_route=\/wp\/v2\/posts\/160"}],"collection":[{"href":"https:\/\/blog.le-vert.net\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.le-vert.net\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.le-vert.net\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.le-vert.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=160"}],"version-history":[{"count":16,"href":"https:\/\/blog.le-vert.net\/index.php?rest_route=\/wp\/v2\/posts\/160\/revisions"}],"predecessor-version":[{"id":176,"href":"https:\/\/blog.le-vert.net\/index.php?rest_route=\/wp\/v2\/posts\/160\/revisions\/176"}],"wp:attachment":[{"href":"https:\/\/blog.le-vert.net\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=160"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.le-vert.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=160"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.le-vert.net\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=160"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}