Are you sick of $BigDataCorporation spying on your emails?
Let's set up our own mail server using Postfix, Dovecot, and OpenDKIM!
- Postfix is the actual mail service itself. It receives mail and sends mail to and from external servers.
- Dovecot is a mail connector essentially. It allows you to store and access mail from remote devices via IMAP and SMTP, like from your phone or laptop.
- OpenDKIM is a mail signature verification system. Emails signed with DKIM tell the recipient that the email is genuine and originates from the real domain name. Google's Gmail will block all mail from unknown sources that do not have a DKIM signature, so we need to have this enabled.
-Initial Setup
First let's to install postfix, dovecot, and the MySQL connectors for them.
# apt install postfix postfix-mysql dovecot-core dovecot-imapd dovecot-lmtpd dovecot-mysql mysql-server
When postfix asks you, enter your domain name, and setup a root password for MySQL.
-MySQL
Go ahead and login to MySQL:# mysql -u root -p
Now let’s create the MySQL databases.
This will create the mail database. Change "securepassword" to a secure password for the mail user to connect to the database:
mysql> create database mail;
mysql> grant select on mail.* to 'mail'@'localhost' identified by 'securepassword';
mysql> flush privileges;
mysql> use mail;
mysql> CREATE TABLE `virtual_domains` (
`id` INT NOT NULL AUTO_INCREMENT,
`name` VARCHAR(50) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
This will create the users database:
mysql> CREATE TABLE `virtual_users` (
`id` INT NOT NULL AUTO_INCREMENT,
`domain_id` INT NOT NULL,
`password` VARCHAR(106) NOT NULL,
`email` VARCHAR(120) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `email` (`email`),
FOREIGN KEY (domain_id) REFERENCES virtual_domains(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
This will create the aliases database:
mysql> CREATE TABLE `virtual_aliases` (
`id` INT NOT NULL AUTO_INCREMENT,
`domain_id` INT NOT NULL,
`source` varchar(100) NOT NULL,
`destination` varchar(100) NOT NULL,
PRIMARY KEY (`id`),
FOREIGN KEY (domain_id) REFERENCES virtual_domains(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Now we can create our first email address. In this next command make sure to change "somepassword" to a secure password for your email account, and change the "[email protected]" to your name with your domain name.
mysql> INSERT INTO `mail`.`virtual_domains`
(`id` ,`name`)
VALUES
('1', 'yourdomain.com');
mysql> INSERT INTO `mail`.`virtual_users`
(`id`, `domain_id`, `password` , `email`)
VALUES
('1', '1', ENCRYPT('somepassword', CONCAT('$6$', SUBSTRING(SHA(RAND()), -16))),
'[email protected]');
And exit MySQLmysql> exit
-Postfix
Start by editing the main configuration:# nano /etc/postfix/main.cf
Delete everything in here. Hold CTRL and K to delete entire lines to make it go faster.
Put this in the file:
smtpd_tls_cert_file = /etc/letsencrypt/live/yourdomain.com/fullchain.pem
smtpd_tls_key_file = /etc/letsencrypt/live/yourdomain.com/privkey.pem
smtpd_use_tls = yes
smtpd_tls_auth_only = yes
smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth
smtpd_sasl_auth_enable = yes
smtp_tls_security_level = may
myhostname = vm-1.yourdomain.com
mydestination = yourdomain.com, vm-1.yourdomain.com, localhost.yourdomain.com, localhost
relayhost =
mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128
mailbox_size_limit = 0
recipient_delimiter = +
inet_interfaces = all
milter_protocol = 2
milter_default_action = accept
smtpd_milters = inet:localhost:12301
non_smtpd_milters = inet:localhost:12301
alias_maps = hash:/etc/aliases
alias_database = hash:/etc/aliases
myorigin = /etc/mailname
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,
mysql:/etc/postfix/mysql-virtual-email2email.cf
As always change "yourdomain" to your actual domain name.
Now do the same for these next few files. In these change "securepassword" to the password you used for the mail user to connect to the database earlier in the MySQL setup.# nano /etc/postfix/mysql-virtual-mailbox-domains.cf
user = mail
password = securepassword
hosts = 127.0.0.1
dbname = mail
query = SELECT 1 FROM virtual_domains WHERE name='%s'
# nano /etc/postfix/mysql-virtual-mailbox-maps.cf
user = mail
password = securepassword
hosts = 127.0.0.1
dbname = mail
query = SELECT 1 FROM virtual_users WHERE email='%s'
# nano /etc/postfix/mysql-virtual-alias-maps.cf
user = mail
password = securepassword
hosts = 127.0.0.1
dbname = mail
query = SELECT destination FROM virtual_aliases WHERE source='%s'
# nano /etc/postfix/mysql-virtual-email2email.cf
user = mail
password = securepassword
hosts = 127.0.0.1
dbname = mail
query = SELECT email FROM virtual_users WHERE email='%s'
And restart Postfix:# service postfix restart
Now let’s test the connection. Run this command with the email address you created earlier. If it returns a “1” then it was successful.# postmap -q [email protected] mysql:/etc/postfix/mysql-virtual-mailbox-maps.cf
Now let’s allow clients to connect with TLS for full encryption.# nano /etc/postfix/master.cf
Uncomment these lines:
submission inet 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=
-o smtpd_relay_restrictions=permit_sasl_authenticated,reject
-o milter_macro_daemon_name=ORIGINATING
Now append this to the recipient_restrictions
line before the closing quotes:
permit_mynetworks,permit_sasl_authenticated,reject
-Dovecot
First let’s make a user for it to run as (change "yourdomain"):# useradd -m yourdomain
Edit Dovecot's main config:# nano /etc/dovecot/dovecot.conf
Replace everything in here with this changing "yourdomain" as always:
!include_try /usr/share/dovecot/protocols.d/*.protocol
protocols = imap lmtp
service imap-login {
inet_listener imap {
port = 0
}
}
service lmtp {
unix_listener /var/spool/postfix/private/dovecot-lmtp {
mode = 0600
user = postfix
group = postfix
}
}
service auth {
unix_listener /var/spool/postfix/private/auth {
mode = 0666
user = postfix
group = postfix
}
unix_listener auth-userdb {
mode = 0600
user = yourdomain
#group =
}
#unix_listener /var/spool/postfix/private/auth {
# mode = 0666
#}
user = dovecot
}
service auth-worker {
user = yourdomain
}
disable_plaintext_auth = yes
auth_mechanisms = plain login
ssl = required
ssl_cert = </etc/letsencrypt/live/yourdomain.com/fullchain.pem
ssl_key = </etc/letsencrypt/live/yourdomain.com/privkey.pem
mail_location = maildir:/home/yourdomain/mail/%d/%n
mail_privileged_group = yourdomain
passdb {
driver = sql
args = /etc/dovecot/dovecot-sql.conf.ext
}
userdb {
driver = static
args = uid=yourdomain gid=yourdomain home=/home/yourdomain/mail/%d/%n
}
Now let’s make the folders for the domain and set the permissions on it:# mkdir /home/yourdomain/mail
# mkdir /home/yourdomain/mail/yourdomain.com
# chown -R yourdomain:yourdomain /home/yourdomain/mail
Connect it to the MySQL database:# nano /etc/dovecot/dovecot-sql.conf.ext
Add this into the file, changing "securepassword" to the mail database user password :
driver = mysql
connect = host=localhost dbname=mail user=mail password=securepassword
default_pass_scheme = SHA512-CRYPT
password_query = SELECT email as user, password FROM virtual_users WHERE email='%u';
Now we set permissions on the dovecot folder itself and the auth daemon:# chown -R yourdomain:dovecot /etc/dovecot
# chown -R yourdomain:dovecot /var/run/dovecot/auth-userdb
Restart dovecot:# service dovecot restart
Now we need to open some ports:# ufw allow 25
# ufw allow 587
# ufw allow 993
# ufw reload
-OpenDKIM
# apt install opendkim opendkim-tools
Edit the config:# nano /etc/opendkim.conf
Replace everything with:
AutoRestart Yes
AutoRestartRate 10/1h
UMask 002
Syslog yes
SyslogSuccess Yes
LogWhy Yes
Canonicalization relaxed/simple
ExternalIgnoreList refile:/etc/opendkim/TrustedHosts
InternalHosts refile:/etc/opendkim/TrustedHosts
KeyTable refile:/etc/opendkim/KeyTable
SigningTable refile:/etc/opendkim/SigningTable
Mode sv
PidFile /var/run/opendkim/opendkim.pid
SignatureAlgorithm rsa-sha256
UserID opendkim:opendkim
Socket inet:12301@localhost
OversignHeaders From
Edit the next config:# nano /etc/default/opendkim
And add this to the bottom:SOCKET="inet:12301@localhost"
Now let’s make folders to store keys in (change "yourdomain"):# mkdir /etc/opendkim
# mkdir /etc/opendkim/keys
# mkdir /etc/opendkim/keys/yourdomain.com
Now to specify trusted hosts:# nano /etc/opendkim/TrustedHosts
Add this in the file (change "yourdomain"):
127.0.0.1
localhost
::1
*.yourdomain.com
Edit the key table:# nano /etc/opendkim/KeyTable
Add (change "yourdomain"):
mail._domainkey.yourdomain.com yourdomain.comt:mail:/etc/opendkim/keys/yourdomain.com/mail.private
Now let’s create the keys:# cd /etc/opendkim/keys/yourdomain.com
# opendkim-genkey -s mail -d yourdomain.com
Set ownership on the key:# chown opendkim:opendkim mail.private
Now we need to read the key and add it to our DNS record for this domain:# cat mail.txt
Copy from “mail” to the closing parenthesis
Edit the DNS zone for your domain name:# nano /etc/bind/zones/db.yourdomain.com
Paste the key into the very bottom of the zone file. Remove the opening and closing parenthesis, and make sure it is all on a single line. It should look like this:
mail._domainkey IN TXT "v=DKIM1; k=rsa; p=AKLJBVEWBlKjbfhlkse1237098vfnkuNJHYGFASD978290NLNo920293480KBN8oy0324lnawlskn213098"
Now increment the serial number on line 6 of the zone file by 1.
Restart bind9, postfix, and opendkim:# service bind9 reload
# service postfix restart
# service opendkim restart
-Closing notes
If everything works you can now setup your email client. Use the full email address as the username, and connect to your domain name for the server. Make sure to enable SSL/TLS for inbound messages through IMAP, and STARTTLS for outbound messages through SMTP.
Now you have your own custom configured email server!
To add more email accounts, run the same command when you added the first email account. Make sure to increase the line number each time. This is the first number on the last line of this command. In the example below it is "2" for adding a second account. To add a third account run the same command with the 3rd email address and password you want and set this number to "3".
mysql> INSERT INTO `mail`.`virtual_users`
(`id`, `domain_id`, `password` , `email`)
VALUES
('2', '1', ENCRYPT('somepassword', CONCAT('$6$', SUBSTRING(SHA(RAND()), -16))), '[email protected]');
Thanks for reading! If you have any feedback let me know, or if you have any questions just ask.