The Funtoo Linux project has transitioned to "Hobby Mode" and this wiki is now read-only.
Mail Server
How to set up a simple, secure, lightweight email server using Postfix and Dovecot
Running one's own email server doesn't have to be mystical and impenetrable; using a simple MTA like Postfix along with an LDA like Dovecot makes the task relatively easy. Regrettably, good information on how to do this is hard to come by. What this guide will help you do is install a mail server which uses a database backend to manage domains and users, and features mail delivery via POP3 and/or IMAP.
__
Prerequisites
If you intend to run your own email server, you will need to have DNS with at least one MX record on a DNS server that can be seen by the Internet at large. Setting up such a thing is beyond the scope of this document.
Preparation
The following packages need to be installed first, before we can do anything: mail-mta/postfix
, net-mail/dovecot
, and dev-db/mariadb
. Before we emerge these, however, we must ensure some USE flags are properly set first:
/etc/portage/package.use/mail-server
- USE flagsmail-mta/postfix dovecot-sasl pam ssl
net-mail/dovecot bzip2 maildir pam ssl zlib
With USE flags properly set, we can emerge our packages:
root # emerge -avq postfix mariadb
Setting the dovecot-sasl
USE flag should pull in net-mail/dovecot
. If it does not, emerge this way:
root # emerge -avq postfix dovecot mariadb
Next, we need to set up the location on the server where email will be delivered:
root # mkdir /mailstore root # chgrp mail /mailstore root # chmod -R g+rw /mailstore
Configuration
Now we come to the meat of the project. First we will have to set up the mail user/domain database, then we will have to configure Postfix, then finally, configure Dovecot. At the end of this procedure, we should have a fully functioning mail server.
Setting up the Database
First step is to set up the database for the virtual domain/user tracking. We need to set up the database's root user and get the database up and running (be sure to replace <strong-password> with a real, strong password):
root # mysqladmin -u root password '<strong-password>' root # rc-update add mysql default root # rc
Next, we need to login to MySQL (you will have to enter the <strong-password> you set above):
root # mysql -p
Now, we create the database and its tables (again, replace <mailuserpass> with a real password):
mysql> CREATE DATABASE mailserver; mysql> USE mailserver; mysql> GRANT SELECT ON mailserver.* TO 'mailuser'@'127.0.0.1' IDENTIFIED BY '<mailuserpass>'; mysql> FLUSH PRIVILEGES; mysql> CREATE TABLE virtual_domains (id INT(11) NOT NULL AUTO_INCREMENT, root ##i## name VARCHAR(50) NOT NULL, PRIMARY KEY (id)) ENGINE=InnoDB DEFAULT CHARSET=utf8; mysql> CREATE TABLE virtual_users (id INT(11) NOT NULL AUTO_INCREMENT, root ##i## domain_id INT(11) NOT NULL, password VARCHAR(106) NOT NULL, email VARCHAR(100) NOT NULL, root ##i## PRIMARY KEY (id), UNIQUE KEY email (email), FOREIGN KEY (domain_id) REFERENCES virtual_domains(id) root ##i## ON DELETE CASCADE) ENGINE=InnoDB DEFAULT CHARSET=utf8; mysql> CREATE TABLE virtual_aliases (id INT(11) NOT NULL AUTO_INCREMENT, root ##i## domain_id INT(11) NOT NULL, source VARCHAR(100) NOT NULL, destination VARCHAR(100) NOT NULL, root ##i## PRIMARY KEY (id), FOREIGN KEY (domain_id) REFERENCES virtual_domains(id) ON DELETE CASCADE) root ##i## ENGINE=InnoDB DEFAULT CHARSET=utf8;
Now that we've created our database and tables, we need to put our domain into it. Replace <my.fqdn.com> with the FQDN of that will go to the right of the '@' sign in email addresses on your mail domain:
mysql> INSERT INTO virtual_domains VALUES (DEFAULT, '<my.fqdn.com>');
If you're planning on receiving mail for more than one domain, you can add them by reusing the previous query and changing <my.fqdn.com> to the other domain(s); you will have to enter one query for each extra domain.
Next, we need to populate that database with users (the part that goes on the left side of the '@' sign). Again, these need to be added one at a time. For each entry in the database, we will need a username and a password; since we want these passwords to be strong, we will use doveadm to generate them:
root # doveadm pw -s SHA512-CRYPT Enter new password: Retype new password: {SHA512-CRYPT}$6$dMNWSDK.CYzDfADO$LLSqttmYD/3WDBIEwxLjzae1s0G.eQw6EU8U7cjysPDK/z3Pntz8gxabfrYmLzpdc.L3gMyxaoI4V9ci4zruM.
You will be prompted to enter the password twice before it gives back the hash. The part that comes after {SHA512-CRYPT
} is the password that will need to go into the database (it will always start with $6$
).
The password you will distribute to your users is the one you typed into doveadm
; the hash that it outputs is what will go into the virtual_users
table.
Replace <pw_hash> with the output of doveadm
(starting with $6$
), and <user@my.fqdn.com> with the email address for the user you're creating:
mysql> INSERT INTO virtual_users VALUES (DEFAULT, 1, '<pw_hash>', '<user@my.fqdn.com>');
The second field in the query above (the '1') is the ID of the entry in the virtual_domains
table. If you're only using one domain, you don't have to worry about changing it; otherwise, you will have to change it to correspond to the domain for that user. You can find out what IDs they have with the following query:
mysql> SELECT * FROM virtual_domains;
Once you are done entering users you can leave MySQL:
mysql> quit
Configuring Postfix
Now we have to configure Postfix. Pull up your favorite text editor and add the following lines to the bottom:
/etc/postfix/main.cf
- Postfix configuration# SASL config
smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth
smtpd_sasl_auth_enable = yes
smtpd_recipient_restrictions = permit_mynetworks, permit_sasl_authenticated, reject_unauth_destination
# TLS config
smtpd_tls_cert_file = /etc/ssl/certs/dovecot.pem
smtpd_tls_key_file = /etc/ssl/private/dovecot.pem
smtpd_use_tls = yes
smtpd_tls_auth_only = yes
smtp_tls_security_level = may
smtp_tls_loglevel = 2
smtpd_tls_received_header = yes
# Authentication config
virtual_transport = lmtp:unix:private/dovecot-lmtp
virtual_mailbox_domains = mysql:/etc/postfix/mysql-virtual-mailbox-domains.cf
virtual_mailbox_maps = mysql:/etc/postfix/mysql-virtual-mailbox-maps.cf
virtual_alias_maps = mysql:/etc/postfix/mysql-virtual-alias-maps.cf
local_recipient_maps = $virtual_mailbox_maps
Next, we have to change a few items in the same config file (change the defaults in the file to what's listed here):
/etc/postfix/main.cf
- More Postfix configurationcompatibility_level = 2
myhostname = <my.fqdn.com> # Replace <my.fqdn.com> with your mail server's FQDN
mydomain = <fqdn.com> # Replace <fqdn.com> with your mail server's domain
mydestination = localhost # This MUST be set to localhost
mynetworks = 192.168.0.0/24, 127.0.0.0/8 # Replace 192.168.0.0/24 with your LAN's IP/mask
Next, we have to create the files referenced above as part of the 'Authentication config'. First, we have to create /etc/postfix/mysql-virtual-mailbox-domains.cf
:
/etc/postfix/mysql-virtual-mailbox-domains.cf
- MySQL/virtual domains Postfix configurationuser = mailuser
password = mailuserpass
hosts = 127.0.0.1
dbname = mailserver
query = SELECT 1 FROM virtual_domains WHERE name='%s'
Next, we have to create /etc/postfix/mysql-virtual-mailbox-maps.cf
:
/etc/postfix/mysql-virtual-mailbox-maps.cf
- MySQL/virtual maps Postfix configurationuser = mailuser
password = mailuserpass
hosts = 127.0.0.1
dbname = mailserver
query = SELECT 1 FROM virtual_users WHERE email='%s'
And finally, we have to create /etc/postfix/mysql-virtual-alias-maps.cf
:
/etc/postfix/mysql-virtual-alias-maps.cf
- MySQL/virtual alias maps Postfix configurationuser = mailuser
password = mailuserpass
hosts = 127.0.0.1
dbname = mailserver
query = SELECT destination FROM virtual_aliases WHERE source='%s'
Now lets start Postfix and make sure that our authentication queries are working:
root # /etc/init.d/postfix start root # postmap -q <my.fqdn.com> mysql:/etc/postfix/mysql-virtual-mailbox-domains.cf 1 root # postmap -q <user>@<my.fqdn.com> mysql:/etc/postfix/mysql-virtual-mailbox-maps.cf 1
Assuming both postmap
commands returned 1, we can go on to configuring Dovecot.
Configuring Dovecot
Now that Postfix is properly configured, it's time to tackle Dovecot. The first file we want to look at is /etc/dovecot/dovecot.conf
. In particular, we want to make sure the protocols
line has imap
, pop3
, and lmtp
enabled:
/etc/dovecot/dovecot.conf
- Dovecot configurationprotocols = imap pop3 lmtp
Next we need to look at /etc/dovecot/conf.d/10-mail.conf
:
/etc/dovecot/conf.d/10-mail.conf
- Dovecot configurationmail_location = maildir:/decrypted-mail/%d/%n
mail_privileged_group = mail
first_valid_uid = 0
On to /etc/dovecot/conf.d/10-auth.conf
:
/etc/dovecot/conf.d/10-auth.conf
- Dovecot authorization configdisable_plaintext_auth = yes
auth_mechanisms = plain login
#INSERT a hashtag in front of the following import. This separates your mail server's login from UNIX logins.
#!include auth-system.conf.ext
#REMOVE the hashtag in front of the following import. This points it at mysql for authentication.
!include auth-sql.conf.ext
On to /etc/dovecot/conf.d/auth-sql.conf.ext
:
/etc/dovecot/conf.d/auth-sql.conf.ext
- Dovecot SQL configpassdb {
driver = sql
args = /etc/dovecot/dovecot-sql.conf.ext
}
userdb {
driver = static
args = uid=mail gid=mail home=/decrypted-mail/%d/%n
}
On to /etc/dovecot/dovecot-sql.conf.ext
:
/etc/dovecot/dovecot-sql.conf.ext
- More Dovecot SQL configdriver = mysql
connect = host=127.0.0.1 dbname=mailserver user=mailuser password=mailuserpass
default_pass_scheme = SHA512-CRYPT
password_query = SELECT email as user, password FROM virtual_users WHERE email='%u';
Next up is /etc/dovecot/conf.d/10-master.conf
:
/etc/dovecot/conf.d/10-master.conf
- Dovecot master config fileservice imap-login {
inet_listener imap {
port = 0
}
…
service pop3-login {
inet_listener pop3 {
port = 0
}
…
service lmtp {
unix_listener /var/spool/postfix/private/dovecot-lmtp {
mode = 0666
group = postfix
user = postfix
}
# Create inet listener only if you can't use the above UNIX socket
#inet_listener lmtp {
# Avoid making LMTP visible for the entire internet
#address =
#port =
#}
user=mail
}
service auth {
# auth_socket_path points to this userdb socket by default. It's typically
# used by dovecot-lda, doveadm, possibly imap process, etc. Its default
# permissions make it readable only by root, but you may need to relax these
# permissions. Users that have access to this socket are able to get a list
# of all usernames and get results of everyone's userdb lookups.
unix_listener /var/spool/postfix/private/auth {
mode = 0666
user = postfix
group = postfix
}
unix_listener auth-userdb {
mode = 0600
user = mail
#group =
}
# Postfix smtp-auth
#unix_listener /var/spool/postfix/private/auth {
# mode = 0666
#}
# Auth process is run as this user.
user = dovecot
}
service auth-worker {
# Auth worker process is run as root by default, so that it can access
# /etc/shadow. If this isn't necessary, the user should be changed to
# $default_internal_user.
user = mail
}
And last, but not least, /etc/dovecot/conf.d/10-ssl.conf
:
/etc/dovecot/conf.d/10-ssl.conf
- Dovecot SSL configssl_cert = </etc/ssl/certs/dovecot.pem
ssl_key = </etc/ssl/private/dovecot.pem
ssl = required
We now need to generate the SSL certificates that Postfix and Dovecot are looking for. When it asks for a FQDN for the certificate, make sure to put in the FQDN of the mail server:
root # openssl req -new -x509 -days 1000 -nodes -out "/etc/ssl/certs/dovecot.pem" -keyout "/etc/ssl/private/dovecot.pem"
Yes, they are self-signed certificates; if that bothers you feel free to buy one from GoDaddy or some other CA. It won't make things more secure (self-signed certificates have an undeserved bad reputation), but it will make you slightly poorer and the CA slightly richer.
Finally, we set the permissions on the Dovecot config files so they belong to mail:dovecot
and nobody else:
root # chown -R mail:dovecot /etc/dovecot root # chmod -R o-rwx /etc/dovecot
Final Steps
We want Postfix and Dovecot to come up when our server boots up, so we need to add them to the server's startup; once that's done, we'll start Postfix and Dovecot with the rc
command:
root # rc-update add postfix default root # rc-update add dovecot default root # rc