DKIM (DomainKeys Identified Mail,域名密钥识别邮件)是一种部署在服务器上使用公钥和私钥对电子邮件进行数字签名和验证的方法。启用 DKIM 机制后,服务器发出的邮件就可以被确切地确认来源从而防止别人伪造冒用自己的域名发送电子邮件。这也可以减少所发邮件被识别为垃圾邮件的情况。
OpenDKIM 是 DKIM 的一个开源实现。前些日子把它部署在了水景一页的服务器上。这里是部署过程的记录。期间参考了这两篇英文教程,
- http://www.linuxtechi.com/configure-domainkeys-with-postfix-on-centos-7/
- https://www.howtoforge.com/set-up-dkim-domainkeys-identified-mail-working-with-postfix-on-centos-using-opendkim
如果只有自己一个域名在主机上,照着第 1 篇来就行了,要在同一台服务器上针对多个邮件域名/子域名进行邮件认证需要结合这两篇文章的指导。
注:因时间过去太久,细节记不清楚了,回头再次配置的时候再修改。如果有朋友参考这篇文章的话还请注意。
下面的部署过程包括软件安装假设是在 CentOS 7 系统中进行。使用的邮件服务器程序是 Postfix (MTA)。假设 Postfix 已经安装并针对下面的邮件主机和域名启用:
邮件服务器主机名 Hostname 为 mail.cnzhx.net
域名 Domain 为 cnzhx.net
使用 EPEL 源¶
如果没有在系统中启用 EPEL 源,需要先启用他。详见这里。
安装 OpenDKIM¶
# yum install -y opendkim
生成密钥对并修改权限¶
使用下面的指令在系统的 /etc/opendkim/keys
文件夹下创建公钥和私钥。(请注意根据自己的情况调整路径和主机以及域名。)
# mkdir /etc/opendkim/keys/cnzhx.net # opendkim-genkey -D /etc/opendkim/keys/cnzhx.net/ -d cnzhx.net mail.cnzhx.net -s cnzhx
其中 -d
指定需要使用此密钥的域名,可以有多个,比如上面的 cnzhx.net
和 mail.cnzhx.net
;-s cnzhx
是指令生成的公钥/私钥文件的选择器(文件名,其实就是个标记),默认(即不使用 -s cnzhx
的情况下)是 default
。详见该指令的说明文档。一般情况下可不指定选择器,但是如果有个多个域名分别使用不同的公钥和私钥,那就肯定需要为它们指定不同的选择器了。该字符串将会包含在 DKIM 的签名中。
生成的文件中,default.private
(这里是 cnzhx.private
)是针对该域名的私钥;default.txt
(这里是 cnzhx.txt
)里面的文本是公钥。公钥将会通过域名解析系统的 TXT 记录公布到网上。
修改公钥/私钥文件权限使 opendkim
的用户和组可以访问它们,
# chown -R opendkim:opendkim /etc/opendkim/keys
编辑配置文件¶
然后就需要编辑(如果系统中没有就需要自己创建)下面这些文件:
- /etc/opendkim.conf — OpenDKIM 的主配置文件
- /etc/opendkim/KeyTable — 供签名用的密钥(及其路径)列表
- /etc/opendkim/SigningTable — 允许签名的域名以及账户列表(即如何使用对应的密钥)
- /etc/opendkim/TrustedHosts — 签名和验证时默认“信任”的服务器列表
注:以下未提到的参数使用默认配置即可。
编辑主配置文件¶
路径 /etc/opendkim.conf
。
设置如下参数:
Mode sv Canonicalization relaxed/simple UMask 022 # Selector cnzhx # 如果前面指定了 选择器 的话需要取消注释该行并填写正确的选择器。
编辑 KeyTable¶
路径 /etc/opendkim/KeyTable
。
替换其中的 example.com 为自己的域名。类似于,
cnzhx._domainkey.cnzhx.net cnzhx.net:cnzhx:/etc/opendkim/keys/cnzhx.net/cnzhx.private cnzhx._domiankey.mail.cnzhx.net mail.cnzhx.net:cnzhx:/etc/opendkim/keys/cnzhx.net/cnzhx.private
注意选择器的位置使用蓝色字体标出来了。
编辑 SigningTable¶
路径 /etc/opendkim/SigningTable
。
这里使用通配符 * 来指明针对使用特定电邮后缀(域名)的所有邮箱地址发送的邮件进行签名认证。
# WILDCARD EXAMPLE # Enables signing for any address on the listed domain(s), but will work only if # "refile:/etc/opendkim/SigningTable" is included in /etc/opendkim.conf. # Create additional lines for additional domains. *@cnzhx.net cnzhx._domainkey.cnzhx.net *@cnzhx.net cnzhx._domainkey.cnzhx.net
编辑 TrustedHosts¶
路径 /etc/opendkim/TrustedHosts
。
在 localhost IP (127.0.0.1
) 下面添加服务器的 FQDN 和域名。
# OPENDKIM TRUSTED HOSTS # To use this file, uncomment the #ExternalIgnoreList and/or the #InternalHosts # option in /etc/opendkim.conf then restart OpenDKIM. Additional hosts # may be added on separate lines (IP addresses, hostnames, or CIDR ranges). # The localhost IP (127.0.0.1) should always be the first entry in this file. 127.0.0.1 ::1 www.cnzhx.net mail.cnzhx.net test.cnzhx.net cnzhx.net #host.example.com #192.168.1.0/24
实际上水景一页的 VPS 目前配置成只有一个主域名(也是机器的域名)cnzhx.net
会发送邮件。其它域名和子域名只是托管在该主机上,并没有配置独立的邮件服务。所以实际上上面只填写一个 cnzhx.net
就可以了。
编辑 Postfix 配置文件¶
路径 /etc/postfix/main.cf
。
# vi /etc/postfix/main.cf
在文件内容最后添加下面的几行内容:
smtpd_milters = inet:127.0.0.1:8891 non_smtpd_milters = $smtpd_milters milter_default_action = accept
(重新)启动 OpenDKIM 和 postfix 服务¶
# systemctl start opendkim ; systemctl enable opendkim ; systemctl restart postfix
更新域名的 TXT 记录¶
使用前面生成的 default.txt
(或这里的 cnzhx.txt
) 文件的内容更新域名的 TXT 记录。这样别的服务器在收到邮件的时候就可以根据域名解析内容中的公钥来验证邮件是否确实由此服务器发出。
登录自己的域名管理服务,在 cnzhx.net
域名下新建一个 TXT 类型的记录。
Name 处填写,
cnzhx._domainkey
或者可能是(根据选择器)
default._domainkey
Value 处填写,
v=DKIM1; k=rsa; p=.........(那一串字符).........
TTL 可以直接取默认值。
发送一封测试邮件并检查日志¶
从当前 Linux 用户帐户发送(此时发送者为 username@domain.name),
# mail -s "test DKIM" info@cnzhx.net . # tail -f /var/log/maillog
配置多域名¶
配置 openDKIM¶
如果有另一个域名 cnzhxother.foo
也托管在同一个服务器上,并且需要通过自己的域名发送通知邮件(注意此服务器不接收邮件),需要给该域名按照前面的方法添加密钥对、在 SigningTable
和 KeyTable
中增加相应记录,还需要将该域名添加到 TrustedHosts
列表中。
测试从命令行发送邮件¶
从指定的另一个配置好的域名发送,
echo "test another account for mail sign" | mail -s "test opendkim" -r "other@cnzhxother.foo (Other)" info@cnzhx.net
如果没有错误就配置完成了。同样可以查看日志看是否有 DKIM-Signature field added
字样。
配置域名解析记录¶
然后还需要相应配置 cnzhxother.foo
的域名记录:
- 增加 MX 并将服务器设置为主域名,比如这里的
cnzhx.net
,反正不接收邮件,似乎问题不大。这样做的目的是,邮件服务器是有逆向域名解析 PTR 的(我这里设置为主域名了)。同时将子域名设置为mail
或其它。 - 增加
mail
(或其它)的 A/AAAA 记录:mail.cnzhxother.foo
到主机 IP 地址。 - 将上面生成的
cnzhxother.foo
的公钥default.txt
的内容添加到域名cnzhxother.foo
的 TXT 记录中。 - 再增加一个 SPF 记录为 DNS 的 TXT 记录,内容如下(假设只通过该服务器发送邮件),
v=spf1 mx ip4:<服务器 IPv4 地址> ~all
其中<服务器 IPv4 地址>
应该替换为实际的 IP 地址,如56.78.90.12
。然后可以用 https://mxtoolbox.com/spf.aspx 来测试一下。
这个地方 https://www.mail-tester.com/spf-dkim-check 可以测试 SPF 和 DKIM 是否已经配置并随 DNS 记录正确传递出去。
但是我配置的这另一个域名发送的邮件没有显示 mailed-by 和 (增加了 MX 之类的之后终于有 mailed-by 了)signed by,虽然也没有显示未加密之类的警告。暂时还不知道为什么邮件发送记录中有 DKIM-Signature 却在接收到的邮件中不显示这个 signed by。(补充)貌似是因为 DNS 解析记录还没有传递到,现在已经可以正确显示 mailed-by 和 signed by 了。
配置 Web 服务器¶
如果要从网络应用中通过托管的域名(非服务器 FQDN 域名)发送电子邮件,比如从 cnzhxother.foo
对应的 WordPress 中发送邮件通知,则还需要配置相应的 Web 服务器。
以 WordPress 为例,假设其服务器程序是 Apache 2 + php-fpm(水景一页就采用了这种配置方式)。WordPress 是 PHP 应用,需要配置 PHP 参数 sendmail_path
。该参数默认情况下是在 /etc/php.ini
中配置的。但是 /etc/php.ini
是全局的,也就是说,服务上所有域名对应的 WordPress 所用的 PHP 解释程序都使用这个配置。所以默认情况下, /etc/php.ini
中设置的默认发送者邮件地址肯定是属于主域名的,比如,
sendmail_path=/usr/sbin/sendmail -t -i -f info@cnzhx.net
那么 cnzhxother.foo
上的 WordPress 发送邮件的时候也会通过 info@cnzhx.net
发送,也就是说其 mailed-by 就是 cnzhx.net
而不是 cnzhxother.foo
。
为了让 cnzhxother.foo
上的 WordPress 在发送邮件的时候显示的 mailed-by 是 cnzhxother.foo
,可以在解释 PHP 的时候修改 PHP 参数 sendmail_path
。这里使用了 php-fpm 解析 PHP,所以修改其配置文件。假设 cnzhxother.foo
对应的配置文件为,
/etc/php-fpm.d/cnzhxother.conf
将其中(默认是靠近该文件结尾的位置),
;php_admin_value[sendmail_path] = /usr/sbin/sendmail -t -i -f www@my.domain.com
一行取消注释(删除行首的 ;
)。
然后修改该行最后的邮件地址为为该域名对应的邮件地址,比如,
php_admin_value[sendmail_path] = /usr/sbin/sendmail -t -i -f info@cnzhxother.foo
保存后重新启动 php-fpm 服务即可。©
本文发表于水景一页。永久链接:<https://cnzhx.net/blog/implementation-of-dkim-on-centos-7/>。转载请保留此信息及相应链接。
引用通告: 加密服务器发出的电子邮件 | 水景一页
引用通告: 记服务器上一个 HOSTS 配置错误 | 水景一页
引用通告: 「水景一页」邮件订阅变更 | 水景一页