在Ubuntu下基于Postfix/Dovecot安装自有邮箱服务

博客已经搭建了很多年了,一直想拥有一个自己的邮箱服务器,最近机缘巧合,给另外一个项目搭建了一个,刚好随手,就给自己的域名也搭建一个,拿来用一用装逼。

顺便,把整个流程记录下来。

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相关信息

类型名称
Amail149.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

在Ubuntu下基于Postfix/Dovecot安装自有邮箱服务》有1个想法

发表评论

电子邮件地址不会被公开。 必填项已用*标注

*

code

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据