【Arch Linux】maddy 邮件服务器搭建

maddy 是一个开源的轻量级“可组合”(composable)多合一邮件服务器,支持通过 IMAP/SMTP 等协议和 DKIM、SPF、DMARC、DANE、MTA-STS 等安全模式收发邮件。本文将以官方文档为主线,整理 maddy 服务器配置流程。

准备

为保证 maddy 的正常运行,请先明确一些建议满足的前提条件:

  • 具有公网地址(本文以 IPv4 为例)并开放 25、143、465(TLS)、587、993(TLS)等端口(一些 VPS 提供商如谷歌云不支持)的服务器;
  • 拥有一个域名(最好是付费二级域名,避免一些 DNS 服务商如 Cloudflare 封禁对其的 API 操作),并接入 DNS 服务商(本文以 Cloudflare 为例);
  • TLS 证书(本文以 Let’s Encrypt 和一款证书获取软件 certbot 为例)。

为叙述方便,本文假设邮件服务器的主域名为 example.org,邮件交换MX)域名为 mx1.example.org,公网 IPv4 地址为 10.2.3.4,邮件账户为 postmaster@example.org

同时需要在服务器上至少安装如下的软件包:

  • maddy
  • certbot
    • certbot-dns-cloudflare
  • nginx(或其他 Web 服务端)

除 maddy 外,其他的软件包都可以使用 pacman 直接安装。

安装

可以在 GitHub 的 Releases 页面获取 maddy 最新版本的源码和预编译程序。也可以参照官方文档的说明,从源码构建、AUR 处获取或 Docker 镜像部署。

注意:从 AUR 处获取需要下载体积很大的 golang 编译器。为节约下载并安装编译器的时间,读者可以直接使用 GitHub 的预编译程序。本文也以此为例。

在服务器终端中执行如下命令,以下载 maddy 的预编译程序:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 安装 zstd 包,以解压 *.zst 类型的文件
sudo pacman -S zstd --needed
# 下载地址,可以任意选择
cd ~/Downloads
wget https://github.com/foxcpp/maddy/releases/download/v0.5.4/maddy-0.5.4-x86_64-linux-musl.tar.zst
# 参考 zsh 的 extract 插件
tar --zstd -xvf maddy-0.5.4-x86_64-linux-musl.tar.zst || zstdcat maddy-0.5.4-x86_64-linux-musl.tar.zst | tar xvf -
cd maddy-0.5.4-x86_64-linux-musl
# 复制服务
sudo cp systemd/*.service /etc/systemd/system
# 复制可执行文件
sudo cp maddy maddyctl /usr/local/bin
# 复制配置文件
sudo mkdir -p /etc/maddy
sudo cp maddy.conf /etc/maddy
# 复制 man 文件
sudo cp man/*.1 /usr/share/man/man1
sudo cp man/*.5 /usr/share/man/man5

启动服务前,先加载所有新增服务:

1
sudo systemctl daemon-reload

若要开机自启:

1
sudo systemctl enable maddy

因为 maddy 运行在非 root 用户上,还需要创建一个用户用以运行 maddy 服务:

1
sudo useradd -mrU -s /sbin/nologin -d /var/lib/maddy -c "maddy mail server" maddy

配置

域名

使用任何编辑器打开 /etc/maddy/maddy.conf,修改 $(hostname)$(primary_domain) 变量的值为 mx1.example.orgexample.org

TLS 证书

获取

Let’s Enccrypt 签发的 TLS 证书可以通过 certbot 获取。根据 certbotcertbot-dns-cloudflare 的官方文档,首先需要在 Cloudflare 的 API Token 配置页面新建一个 Token,选择“Edit zone DNS”的模板,在“Zone Resources”选择目标二级域名(本文则是“example.org”)即可。

注意:Token 只会显示一次,在配置好证书前,请务必牢记。

随后,可以在服务器上存储 Token 以方便后续使用。在终端中执行:

1
2
mkdir -p ~/.secrets/certbot
echo '<TOKEN>' > ~/.secrets/certbot/cloudflare.ini # 替换为获取到的 Token

并设置权限提高安全性:

1
chmod 600 ~/.secrets/certbot/cloudflare.ini

再使用 certbot 获取证书:

1
sudo certbot certonly --dns-cloudflare --dns-cloudflare-credentials ~/.secrets/certbot/cloudflare.ini -d '*.example.org' -d 'example.org'

注意:可以选择不为含通配符域名,而是根据后文实际需要指定必要的三级域名签发证书。

首次获取证书需要填写邮箱等个人信息。签发完毕后则可以通过 sudo certbot certificates 获取证书的详细信息和存储位置。一般存储位置在 /etc/letsencrypt/live/example.org,其中证书文件名为 fullchain.pem,私钥路径为 privkey.pem

配置

编辑 /etc/maddy/maddy.conf,修改 tls file 一行为

1
tls file /etc/letsencrypt/live/$(primary_domain)/fullchain.pem /etc/letsencrypt/live/$(primary_domain)/privkey.pem

/etc/letsencrypt/live 文件夹默认权限为 750,maddy 无法访问,故需要使用 ACL 进行权限控制:

1
sudo setfacl -R -m u:maddy:rX /etc/letsencrypt/{live,archive}

此时可以启动 maddy 服务来测试:

1
sudo systemctl start maddy

若服务未报错,则可以继续进行配置。

DNS

进入 Cloudflare 的 DNS 配置页,作出如下所示的配置:

1
2
3
4
5
6
7
8
9
example.org.   A     10.2.3.4
example.org. MX 10 mx1.example.org.
mx1.example.org. A 10.2.3.4
example.org. TXT "v=spf1 mx ~all"
mx1.example.org. TXT "v=spf1 mx ~all"
_dmarc.example.org. TXT "v=DMARC1; p=quarantine; ruf=mailto:postmaster@example.org"
_mta-sts.example.org. TXT "v=STSv1; id=1"
_smtp._tls.example.org. TXT "v=TLSRPTv1;rua=mailto:postmaster@example.org"
default._domainkey.example.org. TXT "v=DKIM1; k=ed25519; p=nAcUUozPlhc4VPhp7hZl+owES7j7OlEv0laaDEDBAqg="

其中最后一条记录的值需要用

1
sudo cat /var/lib/maddy/dkim_keys/example.org_default.dns

的输出替换。若显示文件不存在,请确认 maddy 服务是否曾成功运行过至少一次。

MTA-STS

MTA-STS 要求访问 https://mta-sts.example.org/.well-known/mta-sts.txt 时能输出类似如下的文本:

1
2
3
4
version: STSv1
mode: enforce
max_age: 604800
mx: mx1.example.org

对于已经安装 HTTP Echo 模块的 Nginx,直接在 /etc/nginx/nginx.conf 中添加如下条目:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
server {
listen 443 ssl http2;
server_name mta-sts.example.org;
error_log /var/log/nginx/log.log;
ssl_certificate /etc/letsencrypt/live/example.org/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.org/privkey.pem;
ssl_session_timeout 5m;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
ssl_prefer_server_ciphers on;
location /.well-known/mta-sts.txt {
echo 'version: STSv1';
echo 'mode: enforce';
echo 'max_age: 604800';
echo 'mx: mx1.example.org';
}
}

对于未安装该模块的 Nginx,先添加如下条目:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
server {
listen 443 ssl http2;
server_name mta-sts.example.org;
error_log /var/log/nginx/log.log;
ssl_certificate /etc/letsencrypt/live/example.org/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.org/privkey.pem;
ssl_session_timeout 5m;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
ssl_prefer_server_ciphers on;
location /.well-known/mta-sts.txt {
root /usr/share/nginx/mta-sts; # /usr/share/nginx 是 Nginx 的静态资源默认位置
index /mta-sts.txt;
}
}

再新建 /usr/share/nginx/mta-sts 文件夹,将指定文本写入 mta-sts.txt 文件中:

1
2
3
4
5
6
sudo cat <<EOF
version: STSv1
mode: enforce
max_age: 604800
mx: mx1.example.org
EOF > /usr/share/nginx/mta-sts/mta-sts.txt

重启 Nginx 服务:

1
sudo systemctl restart nginx

检查上述网络路径是否能够正常访问。

DANE

设置 TLSA(DANE)需要在 https://www.huque.com/bin/gen_tlsa 生成对应的 DNS 记录。

进入页面后,在“Enter/paste PEM format X.509 certificate here:”下的文本框中输入上文中获取的证书的内容:

1
sudo cat /etc/letsencrypt/live/example.org/fullchain.pem

注意:该证书很长,务必复制完全。

下方的“Port Number:”填写 25Transport Protocol: 填写 tcpDomain Name: 填写 mx1.example.org。再点击“Generate”生成记录。将 DNS 记录写入 Cloudflare 中。

创建邮件账户

在服务器终端中:

1
2
maddyctl creds create postmaster@example.org
maddyctl imap-acct create postmaster@example.org

此时,邮件账户的用户名为“postmaster@example.org”,密码则在创建账户时要求设置。该账户已经可以在邮件客户端(如 Thunderbird 和 Outlook)中配置并使用。

(可选)开启 DNSSEC 认证

DNSSEC(Domain Name System Security Extensions),即域名系统安全扩展,对DNS提供给DNS客户端(解析器)的DNS数据来源进行认证,并验证不存在性和校验数据完整性验证。

Arch Wiki 中给出了一些验证方法。安装 ldns 包后:

1
2
3
4
$ drill -DT example.org  # 替换为二级域名
# 省略多行
[T] example.org. 60 IN A 10.2.3.4
;;[S] self sig OK; [B] bogus; [T] trusted

如果命令执行结果如上所示(域名前的 flag 值为“T”),则说明 DNSSEC 认证已开启;反之,请参考 Install a DNSSEC-validating resolver 章节,或参考 DNS 服务商的文档。

以下简单介绍 Cloudflare 为域名开启 DNSSEC 的方法:进入 Cloudflare 控制台后,进入目标域名的详情页面,点击左侧的“DNS”选项卡,在页面尾部的“DNSSEC”部分点击“Enable DNSSEC”。随后 Cloudflare 将给出域名的 DS Record。再进入域名注册商的域名管理页面设置 DS Record。具体设置方法参照 Cloudflare 的官方文档

【Arch Linux】maddy 邮件服务器搭建

https://blog.tamako.work/techdev/arch/maddy/

Posted on

2022-05-16

Updated on

2022-07-13

Licensed under

Comments