{"id":286,"date":"2018-03-11T23:32:51","date_gmt":"2018-03-12T04:32:51","guid":{"rendered":"https:\/\/codemonkeyden.com\/blog\/?p=286"},"modified":"2023-11-10T23:01:35","modified_gmt":"2023-11-11T05:01:35","slug":"private-home-email-server","status":"publish","type":"post","link":"https:\/\/codemonkeyden.com\/?p=286","title":{"rendered":"Host Your Own Private Home Email Server"},"content":{"rendered":"<h3>Background<\/h3>\n<p>The availability and prevalence of high-quality gratis email providers has made people take for granted the true cost of using these services. These companies are hoping they can collect enough valuable information\u00a0from reading your emails that they can make up the difference of providing you the service at no cost. A necessary step to regain control over your email and maintain your privacy is to host your own private email server using free (as in freedom) software.<\/p>\n<p>There are several components involved in a email server and you have choices to make between alternative free software projects. At a high level, the the primary components are the MTA, MDA, and MUA.<\/p>\n<h5>Mail Transfer Agent (MTA)<\/h5>\n<p>A Mail Transer Agent (MTA) uses SMTP to send\/receive emails.\u00a0I recommend Postfix unless special circumstances require the features of the alternative MTAs.<\/p>\n<ul>\n<li><strong>Sendmail<\/strong> &#8211; perhaps the most well known MTA but notoriously hard to configure and\u00a0a poor history of security\u00a0breaches<\/li>\n<li><strong>qmail<\/strong> &#8211; ideal for size constrained environment but doesn&#8217;t support modern email standards<\/li>\n<li><strong>exim<\/strong> &#8211; very flexible, powerful, and general purpose, but not as fast as or secure as Postfix<\/li>\n<li><strong>Postfix<\/strong> &#8211; modern, secure, and efficient, but has a restricted feature set by design<\/li>\n<\/ul>\n<h5>Mail Delivery Agent (MDA)<\/h5>\n<p>A Mail Delivery Agent (MDA) receives messages from a MTA and delivers the mail to a local mailbox typically using either Post Office Protocol (POP) or Internet Message Access Protocol (IMAP). I recommend Dovecot over the alternatives.<\/p>\n<ul>\n<li><b>Cyrus &#8211;\u00a0<\/b>difficult to configure and non-standard format<\/li>\n<li><strong>Courier<\/strong> &#8211; consumes more server resources, slower, and less secure than dovecot<\/li>\n<li><strong>Dovecot<\/strong> &#8211; modern, fast, and secure<\/li>\n<\/ul>\n<h5>Mail User Agent (MUA)<\/h5>\n<p>A Mail User Agent (MUA) is a program used by the end user to read and process mail. A MUA can be a local email client such as Thunderbird or it can be a remote webmail server that provides access to clients via a web browser. If you want to host a webmail server, I recommend Roundcube unless you desire the additional features offered by Horde such as mobile email access.<\/p>\n<ul>\n<li><strong>Squirrelmail<\/strong> &#8211; very simple but doesn&#8217;t have spell check or support HTML composition<\/li>\n<li><strong>Horde<\/strong> &#8211; has more complete features such as mobile email access, advanced productivity features including event reminders, news feed, notes, and a calendar<\/li>\n<li><strong>Roundcube<\/strong> &#8211; very user friendly, modern, and pretty<\/li>\n<\/ul>\n<h3>Setup PHP and MySQL<\/h3>\n<h5>Prerequisites<\/h5>\n<p>On Debian 9 GNU\/Linux, install the following PHP and MySQL packages:<\/p>\n<pre>sudo apt-get install -y php5-fpm php5-imap php5-mysql\u00a0php5-mcrypt php5-intl mysql-server mysql-client<\/pre>\n<h5>Configuration<\/h5>\n<p>Set the timezone in the PHP configuration file:<\/p>\n<pre>sudo sed -i -e 's\/^;date\\.timezone =$\/date.timezone = America\\\/Chicago\/' \/etc\/php5\/fpm\/php.ini<\/pre>\n<p>Create\u00a0a new user and group:<\/p>\n<pre>sudo groupadd -g\u00a01001\u00a0g1001\nsudo useradd --no-create-home -g\u00a01001 -u\u00a01001\u00a0u1001<\/pre>\n<p>Create PHP fpm socket directory:<\/p>\n<pre>sudo mkdir -p \/etc\/php5\/fpm\/socks<\/pre>\n<p>Remove the default FastCGI Process Manager (FPM) pool:<\/p>\n<pre>sudo rm -f \/etc\/php5\/fpm\/pool.d\/www.conf<\/pre>\n<p>Create a new fpm pool configuration file \/etc\/php5\/fpm\/pool.d\/ssl_example.com.conf and copy into it the following content.<\/p>\n<pre>[ssl_example.com]\nlisten = \/etc\/php5\/fpm\/socks\/ssl_example.com.sock\nuser = u1001\ngroup = g1001\nlisten.owner = www-data\nlisten.group = www-data\nlisten.mode = 0666\npm = dynamic\npm.max_children = 50\npm.start_servers = 1\npm.min_spare_servers = 1\npm.max_spare_servers = 5\npm.max_requests = 0\nphp_admin_value[open_basedir]=\/\nphp_admin_value[session.save_path]=\/home\/clients_ssl\/example.com\/tmp\nphp_admin_value[upload_tmp_dir]=\/home\/clients_ssl\/example.com\/tmp\nphp_admin_value[disable_functions]=dl<\/pre>\n<p>Ensure that the file has the proper permissions:<\/p>\n<pre>sudo chmod 644 \/etc\/php5\/fpm\/pool.d\/ssl_example.com.conf<\/pre>\n<p>Start the PHP FPM service:<\/p>\n<pre>sudo systemctl start php5-fpm.service<\/pre>\n<h3>Setup Postfix<\/h3>\n<h5>Prerequisites<\/h5>\n<p>On Debian 9 GNU\/Linux, install the following Postfix packages:<\/p>\n<pre>sudo apt-get install -y posftfixadmin libsasl2-modules libsasl2-modules-sql postfix postfix-mysql<\/pre>\n<h5>Configuration<\/h5>\n<p>Create the postfix database.<\/p>\n<pre>sudo\u00a0mysql -u root -p\u00a0dbpassword1 -e \"CREATE DATABASE postfix; GRANT ALL PRIVILEGES ON postfix.* TO 'postfix_admin'@'%' IDENTIFIED BY 'dbpassword1'; GRANT SELECT ON postfix.* TO 'postfix'@'%' IDENTIFIED BY 'dbpassword2'; FLUSH PRIVILEGES;\"<\/pre>\n<p>Create \/etc\/postfix\/main.cf with the following contents:<\/p>\n<pre>myorigin = \/etc\/mailname\nsmtpd_banner = $myhostname ESMTP $mail_name (Debian\/GNU)\nbiff = no\nappend_dot_mydomain = no\nreadme_directory = no\nsmtpd_tls_cert_file=\/etc\/ssl\/certs\/ssl-cert-snakeoil.pem\nsmtpd_tls_key_file=\/etc\/ssl\/private\/ssl-cert-snakeoil.key\nsmtpd_use_tls=yes\nsmtp_tls_CAfile = \/etc\/ssl\/certs\/ca-certificates.crt\nsmtpd_tls_session_cache_database = btree:${data_directory}\/smtpd_scache\nsmtp_tls_session_cache_database = btree:${data_directory}\/smtp_scache\nsmtpd_relay_restrictions = permit_mynetworks permit_sasl_authenticated defer_unauth_destination\nmyhostname = myhost.example.com\nalias_maps = hash:\/etc\/aliases\nalias_database = hash:\/etc\/aliases\nmydestination = localhost\nrelayhost = [smtp.myisp.net]:587\nmynetworks = 127.0.0.0\/8 192.168.253.0\/24 [::ffff:127.0.0.0]\/104 [::1]\/128\nmailbox_command = procmail -a \"$EXTENSION\"\nmailbox_size_limit = 0\nrecipient_delimiter = +\ninet_interfaces = all\nvirtual_uid_maps = static:3000\nvirtual_gid_maps = static:3000\nvirtual_mailbox_base = \/home\/vmail\nvirtual_mailbox_domains = mysql:\/etc\/postfix\/mysql_virtual_mailbox_domains.cf\nvirtual_mailbox_maps = mysql:\/etc\/postfix\/mysql_virtual_mailbox_maps.cf\nvirtual_alias_maps = mysql:\/etc\/postfix\/mysql_virtual_alias_maps.cf\nrelay_domains = mysql:\/etc\/postfix\/mysql_relay_domains.cf\nvirtual_transport = lmtp:unix:private\/dovecot-lmtp\nsmtpd_recipient_restrictions =\n permit_mynetworks,\n permit_sasl_authenticated,\n reject_non_fqdn_hostname,\n reject_non_fqdn_sender,\n reject_non_fqdn_recipient,\n reject_unauth_destination,\n check_policy_service unix:private\/policyd-spf,\n reject_unauth_pipelining,\n reject_invalid_hostname\nsmtpd_sasl_auth_enable = yes\nsmtpd_sasl_security_options = noanonymous\nsmtp_sasl_auth_enable = yes\nsmtp_sasl_password_maps = hash:\/etc\/postfix\/sasl_passwd\nsmtp_sasl_security_options =\nsmtpd_sasl_type = dovecot\nsmtpd_sasl_path = private\/auth<\/pre>\n<p>Create\u00a0\/etc\/postfix\/mysql_virtual_mailbox_domains.cf\u00a0with the following contents:<\/p>\n<pre>hosts = 127.0.0.1\nuser = postfix\npassword = dbpassword\ndbname = postfix\nquery = SELECT domain FROM domain WHERE domain='%s' and backupmx = 0 and active = 1<\/pre>\n<p>Create\u00a0\/etc\/postfix\/mysql_virtual_mailbox_maps.cf\u00a0with the following contents:<\/p>\n<pre>hosts = 127.0.0.1\nuser = postfix\npassword = dbpassword\ndbname = postfix\nquery = SELECT maildir FROM mailbox WHERE username='%s' AND active = 1<\/pre>\n<p>Create\u00a0\/etc\/postfix\/mysql_virtual_alias_maps.cf\u00a0with the following contents:<\/p>\n<pre>hosts = 127.0.0.1\nuser = postfix\npassword = dbpassword\ndbname = postfix\nquery = SELECT goto FROM alias WHERE address='%s' AND active = 1<\/pre>\n<p>Create\u00a0\/etc\/postfix\/mysql_relay_domains.cf\u00a0with the following contents:<\/p>\n<pre>hosts = 127.0.0.1\nuser = postfix\npassword = dbpassword\ndbname = postfix\nquery = SELECT domain FROM domain WHERE domain='%s' and backupmx = 1<\/pre>\n<p>Create \/etc\/postfix\/master.cf\u00a0with the following contents:<\/p>\n<pre>smtp inet n - y - - smtpd -v\nsubmission inet n - y - - smtpd\n -o syslog_name=postfix\/submission\n -o smtpd_tls_security_level=encrypt\n -o smtpd_sasl_auth_enable=yes\n -o smtpd_client_restrictions=permit_sasl_authenticated,reject\n -o milter_macro_daemon_name=ORIGINATING\nsmtps inet n - y - - smtpd\n -o syslog_name=postfix\/smtps\n -o smtpd_tls_wrappermode=yes\n -o smtpd_sasl_auth_enable=yes\n -o smtpd_client_restrictions=permit_sasl_authenticated,reject\n -o milter_macro_daemon_name=ORIGINATING\npickup unix n - y 60 1 pickup\ncleanup unix n - y - 0 cleanup\nqmgr unix n - n 300 1 qmgr\ntlsmgr unix - - y 1000? 1 tlsmgr\nrewrite unix - - y - - trivial-rewrite\nbounce unix - - y - 0 bounce\ndefer unix - - y - 0 bounce\ntrace unix - - y - 0 bounce\nverify unix - - y - 1 verify\nflush unix n - y 1000? 0 flush\nproxymap unix - - n - - proxymap\nproxywrite unix - - n - 1 proxymap\nsmtp unix - - y - - smtp\nrelay unix - - y - - smtp\nshowq unix n - y - - showq\nerror unix - - y - - error\nretry unix - - y - - error\ndiscard unix - - y - - discard\nlocal unix - n n - - local\nvirtual unix - n n - - virtual\nlmtp unix - - y - - lmtp\nanvil unix - - y - 1 anvil\nscache unix - - y - 1 scache\nmaildrop unix - n n - - pipe\n flags=DRhu user=vmail argv=\/usr\/bin\/maildrop -d ${recipient}\nuucp unix - n n - - pipe\n flags=Fqhu user=uucp argv=uux -r -n -z -a$sender - $nexthop!rmail ($recipient)\nifmail unix - n n - - pipe\n flags=F user=ftn argv=\/usr\/lib\/ifmail\/ifmail -r $nexthop ($recipient)\nbsmtp unix - n n - - pipe\n flags=Fq. user=bsmtp argv=\/usr\/lib\/bsmtp\/bsmtp -t$nexthop -f$sender $recipient\nscalemail-backend unix - n n - 2 pipe\n flags=R user=scalemail argv=\/usr\/lib\/scalemail\/bin\/scalemail-store ${nexthop} ${user} ${extension}\nmailman unix - n n - - pipe\n flags=FR user=list argv=\/usr\/lib\/mailman\/bin\/postfix-to-mailman.py\n ${nexthop} ${user}\npolicyd-spf unix - n n - 0 spawn\n user=policyd-spf argv=\/usr\/bin\/policyd-spf<\/pre>\n<p>Create vmail user and group:<\/p>\n<pre>sudo\u00a0groupadd -g\u00a03000\u00a0vmail\nsudo\u00a0useradd -d \/home\/vmail -m -u\u00a03000 -g 3000\u00a0vmail\nsudo\u00a0adduser postfix sasl<\/pre>\n<p>Start the postfix service:<\/p>\n<pre>sudo systemctl start postfix.service<\/pre>\n<h3>Setup Dovecot<\/h3>\n<h5>Prerequisites<\/h5>\n<p>On Debian 9 GNU\/Linux, install the following Dovecot packages:<\/p>\n<pre>sudo apt-get install -y dovecot-core dovecot-mysql<\/pre>\n<h5>Configuration<\/h5>\n<p>Configure \/etc\/dovecot\/dovecot-sql.conf.ext:<\/p>\n<pre>driver = mysql\nconnect = host=127.0.0.1 dbname=postfix user=root password=dbpassword\ndefault_pass_scheme = MD5\nuser_query = \\\n SELECT '\/home\/vmail\/%d\/%n' as home, 3000 AS uid, 3000 AS gid \\\n FROM mailbox WHERE username = '%u'\npassword_query = \\\n SELECT password \\\n FROM mailbox WHERE username = '%u'<\/pre>\n<p>Configure \/etc\/dovecot\/conf.d\/10-auth.conf:<\/p>\n<pre>auth_mechanisms = plain login\n!include auth-sql.conf.ext<\/pre>\n<p>Configure \/etc\/dovecot\/conf.d\/10-mail.conf:<\/p>\n<pre>mail_location = maildir:\/home\/vmail\/%d\/%n:INDEX=\/home\/vmail\/%d\/%n\/indexes\nnamespace inbox {\n inbox = yes\n}<\/pre>\n<p>Configure \/etc\/dovecot\/conf.d\/10-ssl.conf:<\/p>\n<pre>ssl = no\nssl_cert = &lt;\/etc\/dovecot\/dovecot.pem\nssl_key = &lt;\/etc\/dovecot\/private\/dovecot.pem<\/pre>\n<p>Configure \/etc\/dovecot\/conf.d\/20-imap.conf:<\/p>\n<pre>protocol imap {\n mail_max_userip_connections = 10\n}<\/pre>\n<p>Configure \/etc\/dovecot\/conf.d\/auth-sql.conf.ext:<\/p>\n<pre>passdb {\n driver = sql\n args = \/etc\/dovecot\/dovecot-sql.conf.ext\n}\nuserdb {\n driver = sql\n args = \/etc\/dovecot\/dovecot-sql.conf.ext\n}<\/pre>\n<p>Configure \/etc\/dovecot\/conf.d\/10-master.conf:<\/p>\n<pre>service imap-login {\n inet_listener imap {\n }\n inet_listener imaps {\n }\n}\nservice pop3-login {\n inet_listener pop3 {\n }\n inet_listener pop3s {\n }\n}\nservice lmtp {\n unix_listener \/var\/spool\/postfix\/private\/dovecot-lmtp {\n mode = 0600\n user = postfix\n group = postfix\n }\n}\nservice imap {\n}\nservice pop3 {\n}\nservice auth {\n unix_listener auth-userdb {\n }\n unix_listener \/var\/spool\/postfix\/private\/auth {\n mode = 0666\n }\n}\nservice auth-worker {\n}\nservice dict {\n unix_listener dict {\n }\n}<\/pre>\n<p>Start the dovecot service:<\/p>\n<pre>sudo systemctl start dovecot.service<\/pre>\n<h3>Setup\u00a0Roundcube<\/h3>\n<h5>Prerequisites<\/h5>\n<p>On Debian 9 GNU\/Linux, install the following Roundcube packages:<\/p>\n<pre>sudo apt-get install -y\u00a0roundcube\u00a0roundcube-mysql<\/pre>\n<h5>Configuration<\/h5>\n<p>Create and populate roundcube database:<\/p>\n<pre>sudo mysql -u root -p\u00a0dbpassword1 -e \"CREATE DATABASE roundcube; GRANT ALL PRIVILEGES ON roundcube.* TO roundcube@localhost IDENTIFIED BY 'rcpassword'; FLUSH PRIVILEGES;\"\nsudo mysql -u roundcube -p rcpassword &lt; \/usr\/share\/roundcube\/SQL\/mysql.initial.sql<\/pre>\n<p>Enable roundcube and reload apache2 service:<\/p>\n<pre>sudo a2enconf roundcube\nsudo systemctl reload apache2<\/pre>\n<h3>Proxy MTA<\/h3>\n<p>One challenge you may face if hosting the server at your home is your residential ISP may block incoming connections to TCP port 25 which is required for receiving incoming email on your MTA. One way around this problem is to set your MX record to point at a virtual server that is running a proxy MTA. Then setup a VPN tunnel between your remote virtual server and your local MTA and have the proxy MTA forward all messages to your local MTA.<\/p>\n<h3>Conclusion<\/h3>\n<p>Hosting your own email server is only the first step to regaining your email privacy. A major challenge is that very few people have the skills, time, or motivation to host their own email servers. As a result, most people you send emails to will be using email providers that spy on their users. Thus, your communication with those people will still be subject to surveillance. Lastly, there is always the issue of plaintext emails being intercepted by a third party. To properly defend against this, you need to share GPG\u00a0encryption keys and encrypt the contents of the email.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Background The availability and prevalence of high-quality gratis email providers has made people take for granted the true cost of using these services. These companies are hoping they can collect enough valuable information\u00a0from reading your emails that they can make up the difference of providing you the service at no cost. A necessary step to [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":484,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[3],"tags":[],"class_list":["post-286","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-sysadmin"],"_links":{"self":[{"href":"https:\/\/codemonkeyden.com\/index.php?rest_route=\/wp\/v2\/posts\/286","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/codemonkeyden.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/codemonkeyden.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/codemonkeyden.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/codemonkeyden.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=286"}],"version-history":[{"count":1,"href":"https:\/\/codemonkeyden.com\/index.php?rest_route=\/wp\/v2\/posts\/286\/revisions"}],"predecessor-version":[{"id":495,"href":"https:\/\/codemonkeyden.com\/index.php?rest_route=\/wp\/v2\/posts\/286\/revisions\/495"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/codemonkeyden.com\/index.php?rest_route=\/wp\/v2\/media\/484"}],"wp:attachment":[{"href":"https:\/\/codemonkeyden.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=286"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/codemonkeyden.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=286"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/codemonkeyden.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=286"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}