博客已经搭建了很多年了,一直想拥有一个自己的邮箱服务器,最近机缘巧合,给另外一个项目搭建了一个,刚好随手,就给自己的域名也搭建一个,拿来用一用装逼。
顺便,把整个流程记录下来。
1、以我的域名 stamhe.com 为例,要部署邮箱服务的IP地址为 149.28.109.196
2、建议购买vultr的主机,好处后面就知道了
主要参考文章为Linode的这篇文章:
https://www.linode.com/docs/email/postfix/email-with-postfix-dovecot-and-mysql/
到达率参考
http://lomu.me/post/SPF-DKIM-DMARC-PTR
一、申请SSL证书
通过Let’s Encrypt申请免费的SSL证书
cd /root wget https://dl.eff.org/certbot-auto && chmod a+x certbot-auto # 申请通配符域名 ./certbot-auto -d "*.stamhe.com" --manual --preferred-challenges dns-01 certonly # 申请单一域名 ./certbot-auto -d "mail.stamhe.com" --standalone certonly
按命令行提示进行操作,即可得到如下的证书
root@stamhe:~/certauto# ./certbot-auto certificates Saving debug log to /var/log/letsencrypt/letsencrypt.log - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Found the following certs: Certificate Name: stamhe.com Domains: *.stamhe.com Expiry Date: 2019-10-22 05:33:50+00:00 (VALID: 89 days) Certificate Path: /etc/letsencrypt/live/stamhe.com/fullchain.pem Private Key Path: /etc/letsencrypt/live/stamhe.com/privkey.pem
其中,fullchain.pem 为公钥文件, privkey.pem 为私钥文件.
Let’s Encrypt 是免费证书,有效期为 90 天,快到期前,需要执行下面的命令申请延期
./certbot-auto renew --manual-auth-hook certonly
注意: 如果服务器本身安装得有Web服务器,如Nginx、Apache之类的,在执行延期申请命令前,需要先停止在80、443端口的监听,延期成功后,再启动。
二、配置基本的DNS相关信息
类型 | 名称 | 值 |
A | 149.28.109.196 | |
MX | @ | mail.stamhe.com |
TXT | @ | v=spf1 mx:mail.stamhe.com ip4:149.28.109.196 ~all |
配置spf主要是为了防止发信被对方放垃圾邮箱的一个手段,后面会有详细介绍。
三、配置基础的MySQL账户信息
假设MySQL的连接信息如下:
localhost 3306 root 123456
创建库、表
create database mailserver; use mailserver; CREATE TABLE `virtual_domains` ( `id` int(11) NOT NULL auto_increment, `name` varchar(50) NOT NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE TABLE `virtual_users` ( `id` int(11) NOT NULL auto_increment, `domain_id` int(11) NOT NULL, `password` varchar(106) NOT NULL, `email` varchar(100) 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; CREATE TABLE `virtual_aliases` ( `id` int(11) NOT NULL auto_increment, `domain_id` int(11) 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;
插入两个测试用的邮箱账户信息
insert into virtual_domains(id,name) values(1,'mail.stamhe.com'); insert into virtual_domains(id,name) values(2,'stamhe.com'); insert into virtual_users(id,domain_id,password,email) values (1,2,ENCRYPT('123456'),'love@stamhe.com'); insert into virtual_users(id,domain_id,password,email) values (2,2,ENCRYPT('12345678'),'you@stamhe.com'); insert into virtual_aliases(id,domain_id,source,destination) values (1,2,'all@stamhe.com','love@stamhe.com'); insert into virtual_aliases(id,domain_id,source,destination) values (2,2,'all@stamhe.com','you@stamhe.com');
四、Postfix的安装以及相关配置
安装Postfix
apt-get install postfix postfix-mysql postfix-doc mailutils
安装过程中需要选择Postfix的类型,请选择Internet Site,还会需要输入System mail name,这里请输入你要收发邮件的域名地址,我这儿是输入: stamhe.com
Postfix配置项的官方文档
http://www.postfix.org/documentation.html
查看Postfix的版本号
postconf -d | grep mail_version
打开 /etc/postfix/main.cf
1、删除掉下面的所有默认配置
# TLS parameters smtpd_tls_cert_file=/etc/ssl/certs/ssl-cert-snakeoil.pem smtpd_tls_key_file=/etc/ssl/private/ssl-cert-snakeoil.key smtpd_use_tls=yes smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache
2、新增下面的配置
smtpd_tls_cert_file=/etc/letsencrypt/archive/stamhe.com/fullchain1.pem smtpd_tls_key_file=/etc/letsencrypt/archive/stamhe.com/privkey1.pem smtpd_use_tls=yes smtpd_tls_auth_only = yes smtp_tls_security_level = may smtpd_tls_security_level = may
3、新增下面的配置
smtpd_sasl_type = dovecot smtpd_sasl_path = private/auth smtpd_sasl_auth_enable = yes message_size_limit = 15728640 broken_sasl_auth_clients = yes smtpd_sasl_security_options = noanonymous, noplaintext smtpd_sasl_tls_security_options = noanonymous smtpd_helo_restrictions = permit_mynetworks, permit_sasl_authenticated, reject_invalid_helo_hostname, reject_non_fqdn_helo_hostname smtpd_recipient_restrictions = permit_mynetworks, permit_sasl_authenticated, reject_non_fqdn_recipient, reject_unknown_recipient_domain, reject_unlisted_recipient, reject_unauth_destination smtpd_sender_restrictions = permit_mynetworks, permit_sasl_authenticated, reject_non_fqdn_sender, reject_unknown_sender_domain smtpd_relay_restrictions = permit_mynetworks, permit_sasl_authenticated, defer_unauth_destination
4、修改mydestination
mydestination = localhost
注意:mydestination参数中,不能出现在前面 virtual_domains 表中出现的域名,否则创建的账户会无法收到邮件。
5、新增如下配置,告诉Postfix不要使用LDA「Local Delivery Agent」转而使用Dovecot的LMTP完成本地邮件投递
virtual_transport = lmtp:unix:private/dovecot-lmtp
6、新增如下配置,告诉Postfix去MySQL数据库种寻找域名、用户帐号密码及邮件别名等信息
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
7、配置连接MySQL相关的信息
# cat /etc/postfix/mysql-virtual-mailbox-domains.cf user = root password = 123456 hosts = 127.0.0.1 dbname = mailserver query = SELECT 1 FROM virtual_domains WHERE name='%s' # cat /etc/postfix/mysql-virtual-mailbox-maps.cf user = root password = 123456 hosts = 127.0.0.1 dbname = mailserver query = SELECT 1 FROM virtual_users WHERE email='%s' # cat /etc/postfix/mysql-virtual-alias-maps.cf user = root password = 123456 hosts = 127.0.0.1 dbname = mailserver query = SELECT destination FROM virtual_aliases WHERE source='%s'
执行下面的命令重启postfix
systemctl restart postfix
测试上面的MySQL连接信息
# postmap -q stamhe.com mysql:/etc/postfix/mysql-virtual-mailbox-domains.cf 1 # postmap -q love@stamhe.com mysql:/etc/postfix/mysql-virtual-mailbox-maps.cf 1 # postmap -q all@stamhe.com mysql:/etc/postfix/mysql-virtual-alias-maps.cf love@stamhe.com,you@stamhe.com
8、打开 /etc/postfix/master.cf 文件,去掉里面 submission和smtps所在的两行,并将其注释去掉。
submission inet n - y - - 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 smtps inet n - y - - smtpd -o syslog_name=postfix/smtps -o smtpd_tls_wrappermode=yes -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
9、再次重启postfix
10、完整的main.cf配置文件如下
root@stamhe:~# cat /etc/postfix/main.cf # See /usr/share/postfix/main.cf.dist for a commented, more complete version # Debian specific: Specifying a file name will cause the first # line of that file to be used as the name. The Debian default # is /etc/mailname. #myorigin = /etc/mailname myhostname = stamhe alias_maps = hash:/etc/aliases alias_database = hash:/etc/aliases mydestination = $myhostname, stamhe, localhost.localdomain, , 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 inet_protocols = all html_directory = /usr/share/doc/postfix/html smtpd_banner = $myhostname ESMTP $mail_name (Ubuntu) biff = no # appending .domain is the MUA's job. append_dot_mydomain = no # Uncomment the next line to generate "delayed mail" warnings #delay_warning_time = 4h readme_directory = /usr/share/doc/postfix # TLS parameters smtpd_tls_cert_file=/etc/letsencrypt/archive/stamhe.com/fullchain1.pem smtpd_tls_key_file=/etc/letsencrypt/archive/stamhe.com/privkey1.pem smtpd_use_tls=yes smtpd_tls_auth_only = yes smtp_tls_security_level = may smtpd_tls_security_level = may # See /usr/share/doc/postfix/TLS_README.gz in the postfix-doc package for # information on enabling SSL in the smtp client. smtpd_sasl_type = dovecot smtpd_sasl_path = private/auth smtpd_sasl_auth_enable = yes message_size_limit = 15728640 broken_sasl_auth_clients = yes smtpd_sasl_security_options = noanonymous, noplaintext smtpd_sasl_tls_security_options = noanonymous smtpd_helo_restrictions = permit_mynetworks, permit_sasl_authenticated, reject_invalid_helo_hostname, reject_non_fqdn_helo_hostname smtpd_recipient_restrictions = permit_mynetworks, permit_sasl_authenticated, reject_non_fqdn_recipient, reject_unknown_recipient_domain, reject_unlisted_recipient, reject_unauth_destination smtpd_sender_restrictions = permit_mynetworks, permit_sasl_authenticated, reject_non_fqdn_sender, reject_unknown_sender_domain smtpd_relay_restrictions = permit_mynetworks, permit_sasl_authenticated, defer_unauth_destination 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 # Even more Restrictions and MTA params disable_vrfy_command = yes strict_rfc821_envelopes = yes smtpd_delay_reject = yes smtpd_helo_required = yes smtp_always_send_ehlo = yes smtpd_timeout = 30s smtp_helo_timeout = 15s smtp_rcpt_timeout = 15s smtpd_recipient_limit = 40 minimal_backoff_time = 180s maximal_backoff_time = 3h # Reply Rejection Codes invalid_hostname_reject_code = 550 non_fqdn_reject_code = 550 unknown_address_reject_code = 550 unknown_client_reject_code = 550 unknown_hostname_reject_code = 550 unverified_recipient_reject_code = 550 unverified_sender_reject_code = 550 # rate smtpd_client_connection_count_limit = 100 smtpd_client_connection_rate_limit = 100 smtpd_client_message_rate_limit = 100 smtpd_client_recipient_rate_limit = 100 smtpd_client_new_tls_session_rate_limit = 100 smtpd_client_auth_rate_limit = 100 root@stamhe:~#
五、Dovecot的安装及相关配置
Dovecot充当IMAP、POP服务器的角色,同时它也将负责用户登录时用户身份的验证「Dovecot会将真正的验证工作交给MySQL处理」。因为使用SSL,Dovecot将会使用993「IMAP协议」及995「POP协议」与外界通讯,所以需要允许放行993、995、465三个端口。
1、安装Dovecot
apt-get install dovecot-core dovecot-imapd dovecot-pop3d dovecot-lmtpd dovecot-mysql
2、修改 /etc/dovecot/dovecot.conf 配置文件
!include_try /usr/share/dovecot/protocols.d/*.protocol protocols = imap pop3 lmtp
3、修改 /etc/dovecot/conf.d/10-mail.conf 配置文件
mail_location = maildir:/var/mail/vhosts/%d/%n mail_privileged_group = mail
同时执行下面的命令,创建 mail_location需要的工作目录
# mkdir -p /var/mail/vhosts/stamhe.com # groupadd -g 5000 vmail # useradd -g vmail -u 5000 vmail -d /var/mail # chown -R vmail:vmail /var/mail
4、修改 /etc/dovecot/conf.d/10-auth.conf 配置文件
disable_plaintext_auth = yes auth_mechanisms = plain login
默认情况下,Dovecot是允许Ubuntu系统用户登录使用的,我们需要将其禁用。找到文件种如下内容并将其注释:
#!include auth-system.conf.ext
开启Dovecot的MySQL支持,取消!include auth-sql.conf.ext的注释符号:
#!include auth-system.conf.ext !include auth-sql.conf.ext #!include auth-ldap.conf.ext #!include auth-passwdfile.conf.ext #!include auth-checkpassword.conf.ext #!include auth-vpopmail.conf.ext #!include auth-static.conf.ext
5、修改 /etc/dovecot/conf.d/auth-sql.conf.ext 配置文件
passdb { driver = sql args = /etc/dovecot/dovecot-sql.conf.ext } userdb { driver = static args = uid=vmail gid=vmail home=/var/mail/vhosts/%d/%n }
6、修改 /etc/dovecot/dovecot-sql.conf.ext 配置文件
driver = mysql connect = host=127.0.0.1 dbname=mailserver user=root password=123456 default_pass_scheme = CRYPT password_query = SELECT email as user, password FROM virtual_users WHERE email='%u'
注意: default_pass_scheme代表使用的密码的加密存储算法,我们前面在SQL语句中使用的是encrypt函数,对应的就是CRYPT,当然也可以使用其他算法,自己研究。
7、修改一下目录权限
chown -R vmail:dovecot /etc/dovecot chmod -R o-rwx /etc/dovecot
8、修改 /etc/dovecot/conf.d/10-master.conf 配置文件
service imap-login { inet_listener imap { port = 0 } inet_listener imaps { port = 993 ssl = yes } } service pop3-login { inet_listener pop3 { port = 0 } inet_listener pop3s { port = 995 ssl = yes } } 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 = vmail #group = } user = dovecot } service auth-worker { user = vmail }
9、修改 /etc/dovecot/conf.d/10-ssl.conf 配置文件
ssl = required ssl_cert = </etc/letsencrypt/archive/stamhe.com/fullchain1.pem ssl_key = </etc/letsencrypt/archive/stamhe.com/privkey1.pem
注意: 这儿的证书路径最前面,有一个【<】开头,别漏了。。。
10、修改 /etc/dovecot/dovecot.conf 配置文件
postmaster_address = postmaster at stamhe.com
11、重启dovecot服务
systemctl restart dovecot
六、测试接收、发送邮件
建议使用 163、gmail来做测试对象, qq邮箱很多变态规则,在做下面的配置之前,可能你的很多发送都是失败的。。。
调试日志在
/var/log/mail.log
/var/log/mail.log /var/log/mail.err
七、邮件服务器添加SPF、DKIM、DMARC、PTR提高送达率
主要参考
http://lomu.me/post/SPF-DKIM-DMARC-PTR
1、SPF的配置
我们前面已经做了,在DNS中,新增下面的TXT记录即可
v=spf1 mx:mail.stamhe.com ip4:149.28.109.196 ~all
2、DMARC配置
在DNS中,新增下面的TXT记录
主机名: _dmarc 记录值: v=DMARC1;p=reject;rua=support@stamhe.com
3、PTR配置
如果你是使用的vultr,那就简单了,在Server Detail -> Setting下面,修改 Reverse DNS 为【mail.stamhe.com】即可。
如果是其他的主机厂商,问客服
使用如下命令测试结果
dig -x 你的邮箱服务器IP
4、DKIM配置
安装OpenDKIM
apt install opendkim opendkim-tools
A、修改 /etc/opendkim.conf 配置文件
在最后面追加如下配置内容
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
B、修改 /etc/default/opendkim 配置文件
SOCKET="inet:12301@localhost"
C、修改 /etc/postfix/main.cf 配置文件
milter_protocol = 6 milter_default_action = accept smtpd_milters = inet:localhost:12301 non_smtpd_milters = inet:localhost:12301
milter_protocol = 6 这个参数,根据下面的命令来
# postconf -d | grep mail_version 当postfix版本为2.6+,milter_protocol=6; 版本为2.3到2.5,milter_protocol=2;
D、创建目录
mkdir -p /etc/opendkim/keys
E、修改 /etc/opendkim/TrustedHosts 配置文件
127.0.0.1 localhost 192.168.0.1/24 *.stamhe.com
F、创建opendkim所需要的key
# cd /etc/opendkim/keys # mkdir stamhe.com # cd stamhe.com # opendkim-genkey -s mail –d stamhe.com # chown opendkim:opendkim mail.private
注意,有一些DNS服务商的TXT值有限制长度,opendkim-genkey默认生成的为2048的key,太长了,对于有长度限制的,可以使用 1024的key
# opendkim-genkey -s mail -d stamhe.com -b 1024
得到如下两个文件
total 16 drwxr-xr-x 2 root root 4096 Jul 24 08:05 ./ drwxr-xr-x 3 root root 4096 Jul 24 08:04 ../ -rw------- 1 opendkim opendkim 891 Jul 24 08:05 mail.private -rw------- 1 root root 308 Jul 24 08:05 mail.txt
G、修改 /etc/opendkim/KeyTable 配置文件
mail._domainkey.stamhe.com stamhe.com:mail:/etc/opendkim/keys/stamhe.com/mail.private
H、修改 /etc/opendkim/SigningTable 配置文件
*@stamhe.com mail._domainkey.stamhe.com
H、新增一条DNS记录
主机名: mail._domainkey 记录值: v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCptXy6RtzzWujOEfCAm96Kw/OAzGXGFXzky69T6crWOFl71R7Km8WDbJxLqmz1EfDwq5gVP7QP8lkKBbn/28KLIRlSmkzMaMB+JaZinZ3UJBvKZz6thBePSbAx9AuNU/IwLFlH1NXkK7DBk657EZusD3FgV3rx3sZzH6HcJ9O55wIDAQAB
记录值的来源:
root@stamhe:/etc/opendkim/keys/stamhe.com# cat mail.txt mail._domainkey IN TXT ( "v=DKIM1; k=rsa; " "p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCptXy6RtzzWujOEfCAm96Kw/OAzGXGFXzky69T6crWOFl71R7Km8WDbJxLqmz1EfDwq5gVP7QP8lkKBbn/28KLIRlSmkzMaMB+JaZinZ3UJBvKZz6thBePSbAx9AuNU/IwLFlH1NXkK7DBk657EZusD3FgV3rx3sZzH6HcJ9O55wIDAQAB" ) ; ----- DKIM key mail for stamhe.com
I、重启postfix、opendkim服务
systemctl restart postfix systemctl restart opendkim
测试opendkim的配置结果
opendkim-testkey -d stamhe.com -s mail -vvv
所有这些配置完毕,可以访问 下面的网站,用配置的账户信息,发送一封已经过去,测试一下得分情况。
http://www.mail-tester.com