上网不是目的。而且很多时候,一心想着如何上网,反而忽略了更重要的数据安全问题。


两年以前买了一台联想笔记本,送了1年的office365. Foxiang同学送的移动硬盘也送了1年的office365,于是就一直用着onedrive,用了两年。

期间dropbox的空间满了,amazon的云盘不再无限空间了,box用过一段时间,被公司放弃了。现在用的是Zoolz来做冷备份(后端还是amazon),下载文件需要等待24小时,不算是可以实时工作的版本。evernote国际版也在用,主要是翻译项目的协调。

于是渐渐将所有存储都转到了onedrive。因为翻译用MemoQ,只能在windows上工作,所以这样的方式倒也方便。

几天前终于收到微软的通知,office365要到期了,如果续费,每年99美元,1T存储,吸引力不大。但是更重要的是,完全倚靠微软或者谷歌或者百度阿里云之类的数字集权实体,实在是毫无安全性可言。而且,上传的数据越多,使用越久,依赖性越强,就越发难以更换系统了。想想看,一直用的gmail上保存着我12年前的邮件,大概有6千封邮件,涉及数千人。这些东西作为google的资产,会为这家公司作出多大的贡献呀。从前觉得这是我自己的历史记录,凡事都要保留,但如今却觉得这无疑是一项负资产,早晚还是删除了干净。

我现在也几乎不再在微信上或者任何社交媒体上发孩子们的照片,把超过数万张照片存在微软的服务器上,也完全没有任何实际的理由。

思前想后,于是横下一条心,将整个存储和邮件系统全部更换了。本文是为了自我存档和自我教育,如果你不是一个系统管理员,下面的内容不需要阅读了。


服务器

订购了一台OVH的低端品牌Kimsufi的独立服务器。个人使用,不需要太多的资源。我用的这台是4G内存,2T sata硬盘。

安装

  1. 一个干净的ubuntu 16. 升级为18.04。
    注意:服务器和客户端不一样。我把/boot 和/swep以外的所有剩余硬盘空间都分配给根目录分区。因为作为服务器,/home不太需要空间,而其他目录则需要许多数据存储。

  2. 当然,关闭root远程登录,修改远程登录到随机端口,创建sudo用户,用putty生成密钥对,作好安全方面的预备。

  3. 修改时区。

    sudo timedatectl set-timezone America/New_York
    sudo timedatectl set-ntp on

postfix 邮件服务器

其实iredmail可能是更好的集成。但是,为了体会unix的pipeline设计之美好,还是有必要自己试试postfix的安装。

以下过程参考LinuxBabe所写非常详细的教程以及其他一些参考资料。

dns和hostname

  1. 因为我想使用[email protected]收发邮件,在dns上增加两条mx记录mail.eddyemma.com:

mail MX 1h 10 mail.eddyemma.com
@ MX 1h 10 mail.eddyemma.com

  1. 增加一条A记录,指向mail.eddyemma.com的工作ip。
  2. 因为我不想用[email protected]发邮件,所以修改服务器的hostname:

sudo hostnamectl set-hostname eddyemma.com

这样,postfix自动认为邮件是通过@eddyemma.com发出去的。

  1. 设置系统时间和时区。

这样,服务器就预备好了。

配置postfix

这一步很简单,几乎就是安装postfix而已。

sudo apt-get update
sudo apt-get install postfix -y
sudo systemctl start postfix
sudo systemctl enable postfix

现在就可以用sendmail发邮件了。如果需要测试,安装mailutils

sudo apt install mailutils

然后就可以用mail命令发邮件。

**注意:不要用root账户发邮件。**非常危险。

为此,修改Postfix的别名文件:

sudo vi /etc/postfix/aliases

增加这样两行(请自行将本文中所有eddyemma.com替换为你自己的域名):

abuse: [email protected], [email protected], postmaster
root: eddy

保存文件。然后运行:

sudo newaliases

配置TLS加密

TLS是基本的加密服务。没有TLS,邮件就是明文在网络上传输,几乎人人都可以读取。

为了配置TLS,需要一个数字证书。现在基本上大家都使用免费的电子前线基金会证书

为了简便起见,我安装了apache服务器。虽然nginx速度快一些,但是在支持nextcloud上,略微有点麻烦。

sudo apt-get install apache2
sudo vim /etc/apache2/sites-available/mail.eddyemma.com.conf

然后随便设定一个网站,仅作认证用:

ServerName mail.eddyemma.com DocumentRoot /var/www/mail.eddyemma.com

关闭文件。创建根目录:

sudo mkdir /var/www/mail.eddyemma.com
sudo chown www-data:www-data /var/www/mail.eddyemma.com -R

顺手给一个管理员的支持邮件:

echo “mail.eddyemma.com

support: [email protected]” > /var/www/mail.eddyemma.com/index.html

启动apache2:

sudo a2enmod rewrite
sudo a2enmod headers
sudo a2enmod env
sudo a2enmod dir
sudo a2enmod mime
sudo a2ensite mail.eddyemma.com.conf
sudo systemctl reload apache2

安装certbot脚本:

sudo apt install software-properties-common
sudo add-apt-repository ppa:certbot/certbot
sudo apt update
sudo apt install certbot python3-certbot-apache

安装证书:

sudo certbot –apache –agree-tos –redirect –hsts –email [email protected] -d mail.eddyemma.com

设定证书自动更新任务:

sudo crontab -e

在文件最后增加一行(前面两个数字是随机的分和小时,不要和我一样):

32 3 * * * certbot renew –post-hook “systemctl reload apache2” >> /var/log/letsencrypt/renew.log

##配置postfix的imap支持
为了支持邮件客户端,需要开放postfix的邮件提交服务submission.

可以将postfix理解为一个邮件服务调度中心,smtp负责邮政收发,而submission则像一个开放的邮局,允许人来投递邮件。

postfix的所有服务,都在一个叫master.cf的配置文件中。只要开发这个配置文件相应的服务,并用管道形式一个一个连起来,加上必要的参数即可。

sudo vim /etc/postfix/master.cf

找到被注释掉的#submission一行,取消注释,在下面加上收件参数(注意,参数以 -o 开始,前面至少要有一个空格或tab):

submission inet n – y – – smtpd
-o syslog_name=postfix/submission
-o smtpd_tls_security_level=encrypt
-o smtpd_tls_wrappermode=no
-o smtpd_sasl_auth_enable=yes
-o smtpd_relay_restrictions=permit_sasl_authenticated,reject
-o smtpd_recipient_restrictions=permit_mynetworks,permit_sasl_authenticated,reject
-o smtpd_sasl_type=dovecot
-o smtpd_sasl_path=private/auth

这个参数组说的是:用submission来收邮件,转交给smtpd处理。处理日志按照“postfix/submission”为标题,所有递交的邮件需要加密,需要认证,认证的类型是dovecot,unix管道是private/auth

submission的通讯端口是587, 这也是将来webmail客户端roundcube登录smtp的端口。

保存关闭master.cf文件。打开postfix主要的配置文件main.cf:

sudo vim /etc/postfix/main.cf

然后配置TLS参数(前两行是数字eff.org的签名文件)。:

smtpd_tls_cert_file=/etc/letsencrypt/live/mail.eddyemma.com/fullchain.pem
smtpd_tls_key_file=/etc/letsencrypt/live/mail.eddyemma.com/privkey.pem

smtpd_tls_security_level=may
#smtpd_tls_protocols = !SSLv2, !SSLv3 !TLSv1
smtpd_tls_loglevel = 1
smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache

smtp_tls_security_level = may
smtp_tls_loglevel = 1
smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache

注意,

smtpd_tls_protocols = !SSLv2, !SSLv3 !TLSv1

这一行被我注释掉了。因为有些客户端使用TLS1.1,但是最新的ssl库已经不再支持这种加密方式,所以许多从旧的苹果或者outlook发来的邮件会收不到。

关于TLS1.0客户端的问题,使用TLS2.0/3.0缺省参数。

配置dovecot服务

postfix只能收发邮件,等于一个邮局。但是,现代的邮件客户端需要通过web或者通过pop3,imap等协议来访问邮局。

dovecot就是一个这样的加密邮件服务系统。

sudo apt install dovecot-core dovecot-imapd dovecot-lmtpd

注意,如果需要支持pop3,请增加dovecot-pop3.
这就是postfix和dovecot配置上的灵活之处。

接下来修改dovecot配置文件,增加支持的两种协议:

sudo vim /etc/dovecot/dovecot.conf

在文件中增加或者取消注释,或者补充协议:

protocols = imap lmtp

修改dovecot的邮箱配置文件,设定邮箱的目录:

sudo vim /etc/dovecot/conf.d/10-mail.conf

取消注释这一行:

mail_location = mbox:~/mail:INBOX=/var/mail/%u

保存关闭文件。分配dovecot读目录的权限:

sudo gpasswd -a dovecot mail

打开认证文件,设定TLS认证方式:

sudo vim /etc/dovecot/conf.d/10-auth.conf

取消注释下面一行(不允许明文登录):

disable_plaintext_auth = yes

修改下面的配置(使用邮件全名登录。例如:[email protected]. 采用plain或login登录授权):

auth_username_format = %n
auth_mechanisms = plain login

关闭上述文件。打开SSL/STL配置文件:

sudo vim /etc/dovecot/conf.d/10-ssl.conf

修改密钥文件,强制SSL认证:

ssl = required
ssl_cert = </etc/letsencrypt/live/mail.eddyemma.com/fullchain.pem
ssl_key = </etc/letsencrypt/live/mail.eddyemma.com/privkey.pem

关闭上述文件。打开dovecot主配置文件,设定unix管道,让dovecot可以和postfix通讯:

sudo vim /etc/dovecot/conf.d/10-master.conf

修改service auth段(注意,前后两行本来已经存在。只需要修改unix_listener等四行即可):

service auth {
unix_listener /var/spool/postfix/private/auth {
mode = 0660
user = postfix
group = postfix
}
}

保存关闭上述文件。打开imap邮箱配置文件:

sudo vim /etc/dovecot/conf.d/15-mailboxes.conf

在每个邮箱上增加 auto = create(注意,下面仅是示例。其他mailbox也需要自动创建。):

mailbox Trash {
auto = create
special_use = \Trash
}

最后,修改postfix的主参数配置文件,设定lmtp为本地邮件投递服务,可以分门别类将邮件投递到inbox, junk, trash等邮箱之中:

sudo vim /etc/postfix/main.cf

在文件最后增加两行:

virtual_transport = lmtp:unix:private/dovecot-lmtp
mailbox_transport = lmtp:unix:private/dovecot-lmtp

保存关闭文件。好了,重启服务就行了:

sudo systemctl restart dovecot
sudo systemctl restart postfix

关于lmtp的配置,放到后面再讨论。

至此,邮件客户端可以通过 imap/993, smtp/587登录服务器,查询和发送邮件了。

垃圾邮件过滤

如果配置自己的邮件系统仅仅是这样简单,我早就配置了。要不要配置自己的邮件服务器,争议的问题很多。比如:
反方意见
正方意见
更多正方意见
我考虑的益处:
1. 邮箱大小没有限制了。
2. 不用付费邮件服务了。
3. 不用翻墙了。
4. 隐私和安全都在自己控制之下。出问题谁也不怪了。事实上,我安装服务的时候的确出现很多问题,只有自己解决。
5. 贝叶斯模型!!!我可以自己写垃圾邮件过滤器了。

要解决的问题:
1. 垃圾邮件过滤。
2. 病毒防范。
3. 被人攻陷,变成垃圾邮件中继站。

下面就逐一解决(或者整体解决)。

发送邮件的身份证明问题

首先解决发送邮件的问题。现代社会,要发送一封电子邮件,必须证明三件事:
1. eddyemma.com这个域名确实是我的,这封邮件是从我的服务器发出来的,不是伪造的(spf策略)。
2. 我在dns上发布一个公钥,然后用私钥签名,任何邮件接受服务器都可以去验证这确实是我发出来的邮件,其他人不能伪造(DKIM签名)。
3. 使用DMARC政策,告诉别的邮件服务器,我已经实施了spf和dkim。如果收到的邮件没有这两样,他们可以如何处理和报告。

spf策略

在dns上增加一条记录:
TXT @ “v=spf1 mx ~all”

表示:spf版本是1.0,所有属于mx记录的机器和ip可以用eddyemma.com发送邮件,~all表示软过,也就是说如果不是从这些机器出来的邮件,只是标注警告,不要拒绝。
SPF语法详见这个文件

本地接受邮件的spf策略

相应地,本地接受服务也需要实施spf策略,验证一封邮件是否是真实从声称的服务器发出来的。

  1. 首先,安装spf-python策略服务:

    sudo apt install postfix-policyd-spf-python

  2. 修改Postfix主服务调度文件:

    sudo vim /etc/postfix/master.cf

在文件末尾增加下面两行:

policyd-spf unix – n n – 0 spawn
user=policyd-spf argv=/usr/bin/policyd-spf

保存关闭。修改主参数文件:

sudo vim /etc/postfix/main.cf

在文件最后加上这样几行。
policyd-spf_time_limit = 3600
smtpd_recipient_restrictions =
reject_unauth_destination,
check_policy_service unix:private/policyd-spf

增加其他垃圾过滤方式

既然已经写了smtpd_recipient_restrictions策略,不妨顺手再增加几个。
这些策略来自邮件过滤策略,包括病毒扫描和垃圾邮件过滤。

安装软件

  1. Amavisd-new:内容过滤调度服务。
  2. Spamassassin:贝叶斯网络学习系统。我的博士论文就研究过这个东东。
  3. ClamAV:病毒扫描服务。
  4. opendkim:dkim签名验证服务。
  5. python-policyd-spf:前面已经实施了的spf验证服务。

工作流程:

  1. postfix受到一封邮件。
  2. 对邮件头部进行opendkim和spf验证。
  3. Amavisd-new进行内容过滤。
  4. ClamAV 做病毒扫描。如果有病毒,直接统治postfix拒绝。
  5. 干净的邮件,交给Spamassassin做垃圾邮件分类。标注X-Header。
  6. 根据Spamassassin,dovecot的sieve服务将邮件递交到相应邮箱(inbox/junk)。

安装

sudo apt install amavisd-new spamassassin clamav-daemon pyzor razor
sudo apt install opendkim postfix-policyd-spf-python

安装附件解压程序,供病毒扫描用:

sudo apt install arj cabextract cpio lhasa nomarch pax rar unrar unzip zip p7zip

配置

ClamAV

病毒扫描,直接用缺省配置。只要可以和amavis互相访问即可。

sudo adduser clamav amavis
sudo adduser amavis clamav

Spamassassin

启动服务:

sudo vim /etc/default/spamassassin

设置ENABLED=1,然后启动服务:

sudo systemctl start spamassassin.service

Amavisd-new

修改内容过滤模式:

sudo vim /etc/amavis/conf.d/15-content_filter_mode

开放病毒扫描和垃圾邮件分类:

use strict;

You can modify this file to re-enable SPAM checking through spamassassin

and to re-enable antivirus checking.

Default antivirus checking mode

Uncomment the two lines below to enable it

@bypass_virus_checks_maps = (
\%bypass_virus_checks, \@bypass_virus_checks_acl, \$bypass_virus_checks_re);

Default SPAM checking mode

Uncomment the two lines below to enable it

@bypass_spam_checks_maps = (
\%bypass_spam_checks, \@bypass_spam_checks_acl, \$bypass_spam_checks_re);

1; # insure a defined return

保存关闭。修改垃圾邮件分类参数:

sudo vim /etc/amavis/conf.d/20-debian_defaults

$final_spam_destiny设为D_DISCARD
修改下面的参数:

$sa_tag_level_deflt = -999; # add spam info headers if at, or above that level
$sa_tag2_level_deflt = 6.0; # add ‘spam detected’ headers at that level
$sa_kill_level_deflt = 21.0; # triggers spam evasive actions
$sa_dsn_cutoff_level = 4; # spam level beyond which a DSN is not sent

因为我们希望用eddyemma.com发送邮件,而不是用mail.eddyemma.com发送,修改 /etc/amavis/conf.d/50-user

sudo vim /etc/amavis/conf.d/50-user

$myhostname = ‘mail.eddyemma.com’;
@local_domains_acl = ( “eddyemma.com”, “cloud.eddyemma.com”, “mail.eddyemma.com” );

重新启动服务:

sudo systemctl restart amavis.service
sudo systemctl enable amavis.service

配置postfix

main.cf中增加内容过滤机制。

sudo postconf -e ‘content_filter = smtp-amavis:[127.0.0.1]:10024’

修改master.cf
在文件末尾增加:

smtp-amavis unix – – – – 2 smtp
-o smtp_data_done_timeout=1200
-o smtp_send_xforward_command=yes
-o disable_dns_lookups=yes
-o max_use=20

127.0.0.1:10025 inet n – – – – smtpd
-o content_filter=
-o local_recipient_maps=
-o relay_recipient_maps=
-o smtpd_restriction_classes=
-o smtpd_delay_reject=no
-o smtpd_client_restrictions=permit_mynetworks,reject
-o smtpd_helo_restrictions=
-o smtpd_sender_restrictions=
-o smtpd_recipient_restrictions=permit_mynetworks,reject
-o smtpd_data_restrictions=reject_unauth_pipelining
-o smtpd_end_of_data_restrictions=
-o mynetworks=127.0.0.0/8
-o smtpd_error_sleep_time=0
-o smtpd_soft_error_limit=1001
-o smtpd_hard_error_limit=1000
-o smtpd_client_connection_count_limit=0
-o smtpd_client_connection_rate_limit=0
-o receive_override_options=no_header_body_checks,no_unknown_recipient_checks,no_milters

并告诉系统缺省的收件服务pickup不要再做过滤。
pickup服务下,添加参数:
>
-o content_filter=
-o receive_override_options=no_header_body_checks

修改main.cf,增加各种策略:

smtpd_helo_required = yes
disable_vrfy_command = yes
strict_rfc821_envelopes = yes
invalid_hostname_reject_code = 554
multi_recipient_bounce_reject_code = 554
non_fqdn_reject_code = 554
relay_domains_reject_code = 554
unknown_address_reject_code = 554
unknown_client_reject_code = 554
unknown_hostname_reject_code = 554
unknown_local_recipient_reject_code = 554
unknown_relay_recipient_reject_code = 554
unknown_sender_reject_code = 554
unknown_virtual_alias_reject_code = 554
unknown_virtual_mailbox_reject_code = 554
unverified_recipient_reject_code = 554
unverified_sender_reject_code = 554

smtpd_sender_restrictions =
permit_mynetworks
permit_sasl_authenticated
reject_unknown_sender_domain
reject_unknown_reverse_client_hostname
reject_unknown_client_hostname
smtpd_helo_restrictions =
permit_mynetworks
permit_sasl_authenticated
reject_non_fqdn_helo_hostname
reject_unknown_helo_hostname
policyd-spf_time_limit = 3600
smtpd_recipient_restrictions =
reject_invalid_hostname,
reject_unknown_recipient_domain,
reject_unauth_pipelining,
permit_mynetworks,
permit_sasl_authenticated,
reject_unauth_destination,
check_policy_service unix:private/policyd-spf
reject_rbl_client multi.uribl.com,
reject_rbl_client dsn.rfc-ignorant.org,
reject_rbl_client dul.dnsbl.sorbs.net,
reject_rbl_client sbl-xbl.spamhaus.org,
reject_rbl_client bl.spamcop.net,
reject_rbl_client dnsbl.sorbs.net,
reject_rbl_client cbl.abuseat.org,
reject_rbl_client ix.dnsbl.manitu.net,
reject_rbl_client combined.rbl.msrbl.net,
reject_rbl_client rabl.nuclearelephant.com,
permit

smtpd_relay_restrictions = permit_mynetworks permit_sasl_authenticated defer_unauth_destination

rbl_client是各个维护垃圾邮件列表的服务器。凡是命中的地址,直接拒绝。如果你有同伴用gmail的企业邮箱,不要用sorbs.net,因为sorbs会屏蔽google的ip,所以比如我就收不到mailbox.ciu.edu的邮件了。

重新启动服务:

sudo systemctl restart postfix.service

现在已经可以很好地控制垃圾邮件和病毒了。

opendkim签名认证

安装软件

sudo apt-get install opendkim opendkim-tools

配置

参考linode的文章

Greylists

灰名单是拒绝一次不认识的邮件服务器。一般的邮件服务器都会重发邮件,但是垃圾邮件服务器就多半会放弃了。这样会延迟几分钟收到邮件,但是收到垃圾邮件的可能性更小。

sudo apt install postgrey

修改main.cf

sudo vim /etc/postfix/main.cf

smtpd_recipient_restrictions一节下面插入下面一行:

check_policy_service inet:127.0.0.1:10023

好了。重启系统:

sudo systemctl restart postfix

其他参考文献

autoloean=no
学习机制

垃圾邮件自动分类

白名单


测试邮件系统

访问 邮件测试系统
网站会随机给出一个邮件地址。向这个地址发送一封真实的邮件,html格式,有比较长的内容。然后可以得到测试的报告。目前eddyemma.com的得分是10/10.

太长了。以后有时间再讨论webmail系统roundcube, pgp签名和加密,以及nextcloud配置问题。

感恩节快乐。