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

https://blog.imakiseki.cf/techdev/arch/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,邮件账户为 [email protected]

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

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

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

安装

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

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

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

# 安装 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

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

sudo systemctl daemon-reload

若要开机自启:

sudo systemctl enable maddy

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

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 以方便后续使用。在终端中执行:

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

并设置权限提高安全性:

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

再使用 certbot 获取证书:

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 一行为

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

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

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

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

sudo systemctl start maddy

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

DNS

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

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:[email protected]"
_mta-sts.example.org.   TXT    "v=STSv1; id=1"
_smtp._tls.example.org. TXT    "v=TLSRPTv1;rua=mailto:[email protected]"
default._domainkey.example.org.    TXT   "v=DKIM1; k=ed25519; p=nAcUUozPlhc4VPhp7hZl+owES7j7OlEv0laaDEDBAqg="

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

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 时能输出类似如下的文本:

version: STSv1
mode: enforce
max_age: 604800
mx: mx1.example.org

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

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,先添加如下条目:

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 文件中:

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

重启 Nginx 服务:

sudo systemctl restart nginx

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

DANE

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

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

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

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

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

创建邮件账户

在服务器终端中:

maddyctl creds create [email protected]
maddyctl imap-acct create [email protected]

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

(可选)开启 DNSSEC 认证

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

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

$ 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 的官方文档

1 Like

弄证书的话还是建议用 finalssh ,以前电脑不在身边用手机ssh复制的证书和其他配置文件都有问题,找了好几才找到tab空格。 :c_diaoxie: