一直想用自己的域名搭建一个的邮箱,但传统的Dovecot+Postfix方案十分复杂,封装起来的docker-mailserver虽整洁不少,但仍然存在占用资源很高的问题。
想起Golang效率挺高的,也已经有了不错的生态,于是找到了Maddy,一个使用Golang编写的一体化邮件服务器,占用较少,也免去了各种模块相互配合的。它充当了MTA(中转服务器)和MDA(投递服务器)的角色。
而Rainloop则是一个PHP写成的webmail,可以作为一个类似于Gmail的网页端。
一般的VPS都可以搭建邮件服务器,不过某些服务商会屏蔽必要的25端口,可能需要发工单解决,不过上网搜一下一般就能知道。
本文以Nginx 1.20.2、PHP 8.1.1、Ubuntu 18.04 LTS为例
邮件服务器:Maddy
下载与安装
Maddy的文档说得其实挺明白的,但如果你不想看英语,也可以跟我走。这里使用预编译的二进制文件来搭建。
首先要从GitHub Releases下载最新的二进制文件到服务器中,文件名为maddy-x.x.x-x86_64-linux-musl.tar.zst。
解压zst文件需要zstd依赖(Debian系可直接用apt安装),安装后使用
tar --use-compress-program=unzstd -xvf archive.tar.zst
来指定zstd程序解压这个文件。然后将文件夹内的maddy和maddycli复制到/usr/local/bin目录下。
除此之外,Maddy无法以root用户运行,所以你还需要新建一个用户:
sudo useradd -mrU -s /sbin/nologin -d /var/lib/maddy -c "maddy mail server" maddy
预编译二进制文件的压缩包内还带有systemd服务,可以直接拷贝到系统文件夹内使用:
sudo cp ./systemd/*.service /etc/systemd/system
sudo systemctl reload
将压缩包内附带的maddy.conf
复制到etc目录下,然后用你喜欢的文本编辑器打开。暂时只需要编辑Base variables部分,记得要将上面的内容都换成你对应的。
$(hostname) = mx1.example.org # 外界通过这个域名找到你的邮件服务器。
$(primary_domain) = example.org # 你的邮箱@后面的域名,比如test@example.org,而不一定是test@mx1.example.org
$(local_domains) = $(primary_domain) # @后面可以添加的其他域名,比如test@one.example.org。你需要在几个域名中选一个主要的,将其填入primary domain。
tls file /etc/maddy/certs/$(hostname)/fullchain.pem /etc/maddy/certs/$(hostname)/privkey.pem # TLS证书文件。
对于证书文件,如果你使用Certbot获取hostname的TLS证书,你可以直接进行一个软连接,使得Maddy可以识别,而且要确保其有权限读取:
ln -s /etc/letsencrypt/live /etc/maddy/certs
sudo setfacl -R -m u:maddy:rX /etc/letsencrypt/{live,archive}
如果由其他方法获取证书,可以将文件拷贝至/etc/maddy/certs并用相似的命令赋予maddy用户读取权限。
现在我们可以将其启动了:
systemctl start maddy
配置DNS
首先是各个domain的A/AAAA record,即上面提到example.org和one.example.org的指向。这个没必要指向你的邮件服务器IP,也就是说你可以拿这些域名指向其他服务器建个站什么的,但如果没有另外的用处,不设置应该也没什么问题。
然后仍然是上面几个domain,这次是MX record。它由domain指向hostname。举个例子,将example.org的MX记录指向mx1.example.org,意思是任何发送到@example.org的邮件服务都由mx1.example.org来处理。如果你有多个domain,那么需要逐个设置。
之后设置hostname即邮件服务器的A/AAAA记录。它需要将类似于mx1.example.org的地址解析为IP地址。
要设置MTA-STS(后面会讲),需要将mta-sts.example.org和mta-sts.one.example.org(即各个domain)的A/AAAA记录指向邮件服务器IP。
还有一系列的TXT类型的解析如下。
SPF 为domain和hostname(非必要)都添加txt解析,内容如下。用于表明MX解析的域名是可以发邮件的。
v=spf1 mx ~all
DMARC 用于处理损坏的邮件。需要为所有_dmarc.yourdomain(如_dmarc.example.org和_dmarc.one.example.org)添加。
v=DMARC1; p=quarantine; ruf=mailto:postmaster@example.org
MTA-STS标记 加上之后,失败的报告会被送到指定的邮箱(默认postmaster)。为_mta-sts.example.org添加(其他domain不要漏下)
v=STSv1; id=1
然后为_smtp._tls.example.org添加
v=TLSRPTv1;rua=mailto:postmaster@example.org
DKIM Key 在/var/lib/maddy/dkim_keys/example.org_default.dns(文件名因人而异)找到该项TXT记录值,并将其给予default._domainkey.example.org的TXT解析。
MTA-STS保护
其实包括MTA-STS和DKIM等措施,对于发送邮件来说并不是必要的,但如果没有这几个措施,那么一些大电子邮件服务商(比如Gmail)会认为从你的服务器发出的是垃圾邮件。
MTA-STS(RFC 8461)是一个预防中间人攻击的防护措施。它的标记已经在上一步做好。然后,我们需要使用一个网页服务器来返回一串文本。
官方文档推荐的方式是serve一个文本文档,内容如下:
version: STSv1
mode: enforce
max_age: 604800
mx: mx1.example.org
当访问https://mta-sts.example.org/.well-known/mta-sts.txt的时候,就返回它。
对于Nginx,也可以使用以下方式直接返回这串文字,在Nginx配置文件的HTTP块内加入一个server:
server {
server_name mta-sts.example.org;
listen 443 ssl http2;
listen [::]:443 ssl http2;
ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3;
ssl_certificate /path/to/fullchain.pem; # 路径因人而异,下同
ssl_certificate_key /path/to/privkey.pem;
location = /.well-known/mta-sts.txt {
default_type text/plain;
return 200 "version: STSv1\r\nmode: enforce\r\nmx: mx1.example.org\r\nmax_age: 604800\r\n";
}
}
当然,这之前需要确保你将mta-sts.example.org指向正确的IP,并申请其对应的TLS证书。
如果你使用Nginx、Caddy或Litespeed等网页服务器,请自行研究。
要验证是否添加成功,可以直接访问https://example.org/.well-known/mta-sts.txt,查看返回的内容。
TLSA/DANE记录这里不再指引,因为我使用的阿里云DNS是不能添加DLSA记录的,有兴趣的可以自行看官方文档。
添加账户
Maddy的账户体系是“虚拟用户”,也就是说验证账户和IMAP邮箱是分离开来的。
首先,要创建用户验证,使用命令:
maddyctl creds create example@example.org
输入账户密码,然后再创建它的邮箱:
maddyctl imap-acct create example@example.org
这样,一个传统意义上的邮件账户就创建完成了。
如果需要更多帮助,可以使用
maddyctl creds --help
maddyctl imap-acct --help
命令来获取。
到现在,你可以使用任何一个现代的邮件客户端,连接你刚刚创建的邮件服务器。IMAP协议即可,发送和接收可以全都选SSL。为安全起见,建议以后的邮件客户端全部启用SSL。
发一封邮件,如果你上述的安全措施做得比较好,发送给Gmail等对安全比较严格的邮箱,应该能够作为重要邮件,起码不会被作为垃圾邮件。使用IMAP+SMTP+SSL,收件端口号为993,发件端口号为465。
Webmail:RainLoop
大部分看这篇文章的人都应该是搭着玩的个人用户吧。如果不是,那么请首先参阅RainLoop的不同版本比较页面,他们针对不同用户有不同的版本和Licence。这里直接选对无盈利的个人免费的Standard Edition,因其带有比较简便的更新功能。
下载与安装
从这里可以下载两种版本到服务器上。下载下来是ZIP格式,所以我们需要安装unzip解压(apt包管理器内有,不带apt的发行版请自行想办法)。
然后输入以下命令,将RainLoop的文件拷贝至/var/www/rainloop,并设置权限。你也可以使用其他自己喜欢的路径,别忘了修改后面的配置文件对应部分。
unzip rainloop-latest.zip -d /var/www/rainloop
cd /var/www/rainloop
find . -type d -exec chmod 755 {} \;
find . -type f -exec chmod 644 {} \;
然后编辑Nginx配置文件,加入server块:
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name webmail.example.org;
ssl_certificate /path/to/fullchain.pem;
ssl_certificate_key /path/to/privkey.pem;
index index.html index.php;
root /var/www/rainloop;
client_max_body_size 2G;
error_log /var/log/nginx/rainloop.error.log;
access_log /var/log/nginx/rainloop.access.log;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ^~/data {
deny all;
}
location ~ \.php$ {
fastcgi_pass php-handler-https;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
其中你必须更改的是server_name
、ssl_certificate
和ssl_certificate_key
。你可以把页面直接放到邮件服务器上,也可以换个服务器或者域名,但如果你想直接用上文提到的mx1.example.org即hostname,那么可以做正向代理,但更推荐的做法是把RainLoop直接部署到邮件服务器上。其他root等项视情况更改。根据官方文档,data目录不能允许被外网访问从而直接获取配置文件,所以直接deny all。
然后使用nginx -t
测试配置文件,如果没有问题,就systemctl restart nginx
重启nginx,然后访问webmail.example.org(例)试试吧。
若仍提示no data folder write permission权限问题,大不了给对应目录文件直接777权限(问题不大、
初始配置
访问webmail.example.org/?admin来进行初始配置。默认管理员用户名为admin,密码为12345。
首先建议在“安全”选项卡中修改默认管理员密码。在“域名“选项卡中,你可以添加你刚刚架设好的邮件domain,也可以添加其他商用邮箱域名。添加之后点击测试,可以测试一下邮件服务器在此设定下能否连通。正常来说,你不需要勾选”使用短域名登录“。
此外,”白名单“功能能够限制某域中能登陆到Webmail的账户列表,如设置example.com的白名单为test@example.com,那么除上述邮箱外,后缀为@example.com的邮箱全部不能登录。
这两项基础设置做完之后,你就可以重新打开webmail.example.org,输入你的邮箱和密码,登录Webmail。如果无法登录,请检查你刚刚的初始配置。如果能够成功进入邮箱,那就……enjoy it!
参考文献