【免费下载链接】Mailu
Insular email distribution - mail server as Docker images
本篇指南完整讲解 Mailu(以 Docker 镜像形式交付的邮件服务器分发版)的部署流程:先确认硬件与架构要求并选择合适版本,再按 Compose 等具体部署方式完成安装,随后进行 DNS(A/MX/PTR/SPF/DKIM/DMARC)与 TLS 证书配置,最后通过发送/接收测试、日志检查与开放中继检测确认可以安全上线。读完本文,你将掌握一套可直接复现的 Mailu 生产级部署清单,并能依据仓库源码理解各配置项背后的实际作用。
部署前的整体评估
Mailu 的成熟度与适用场景
Mailu 自 2016 年 1 月前后开始运行,已支撑数百个邮箱账户并投递超过一百万封邮件,但项目自身也明确承认:它并未经过大规模测试,在真正承担关键业务之前,应当逐项验证所有功能。
另外需要说明的是,Mailu 的设计理念源于 Poste.io 团队的工作。如果你的选型出发点不是自由软件,或者你需要长期的专业商业支持,应当考虑转向 Poste.io 而不是部署 Mailu。
准备运行环境
硬件架构支持
Mailu 发布的镜像是多架构的,设计上可运行于:
linux/amd64linux/arm64v8linux/armv7
因此只要主机有足够性能,几乎任何云服务器都可以运行。在 x86_64 平台上,需要确认你的处理器支持 SSE4.2 指令集——例如 2013 年之前的 Intel Atom CPU 就不支持 SSE4.2,相关细节可参考 常见问题 FAQ。
最小硬件与内存要求
根据 Compose 部署要求,主机(物理机或虚拟机)需兼容较新的 Linux 内核,最低内存与交换分区要求如下:
| 场景 | 内存 | Swap |
|---|---|---|
| 启用杀毒(clamav) | 3GB | 1GB |
| 不启用杀毒(clamav) | 1GB | 1GB |
操作系统与端口占用
邮件服务器以一组 Docker 容器运行,因此几乎与操作系统无关;由于绝大多数测试在 Debian stable 上完成,官方推荐使用 Debian stable 作为基础系统。安装时建议为根分区使用 ext4 或 btrfs,或将独立分区挂载到 /var/lib/docker(Docker 数据)与 /mailu(邮件数据)。
主机必须预留以下端口给 Mailu 服务:25、80、110、143、443、465、587、993、995、4190。任何监听这些端口的程序都应禁用或改到其他端口,同时确保防火墙放行这些端口。例如在默认 Debian 安装上:
apt-get autoremove --purge exim4 exim4-base
Docker 的端口转发重度依赖 iptables,应使用 iptables-persistent(或其他系统上的等价工具)管理持久规则;若已切换到 nftables,在 Docker 官方支持发布前需要回滚或自行维护规则集。
DNS 与 IP 前置条件
你需要至少一个 DNS 主机名和一个用于接收邮件的 DNS 域名。强烈建议为邮件服务器使用专用 IP 地址,并为该 IP 配置独立的、具备正向与反向 DNS 记录的主机名(垃圾邮件与信誉服务对此非常敏感)。具体 DNS 配置方法见下文与 DNS 设置指南。
安装 Docker 与 Docker Compose
Mailu 依赖较新的 Docker 特性,应从官方仓库而非发行版仓库安装 Docker。若使用 Compose 部署方式,还需安装 Docker Compose v2。安装完成后可验证:
docker version
docker compose version
选择 Mailu 版本
Mailu 提供多个版本分支,应根据部署目标选择:
2024.06:目前最新的稳定版本,官方推荐用于新部署,旧部署也应在可行时迁移。1.0、1.1等旧分支:不再接收补丁(稳定分支除外)。保守起见,可以按编号固定使用 stable 分支,在充分阅读 changelog 之前避免引入意外的新功能。latest:指向 master 开发分支的最新构建,很可能包含更多缺陷,绝不可用于生产服务器;欢迎用它搭建测试服务器并回报 bug。
按部署方式(flavor)执行安装
具体安装步骤按部署方式(Compose、Kubernetes 等)分别描述。完成上述前置要求后,即可进入对应方式的安装流程。本文以最常见的 Compose 方式为例展开。
准备目录
Mailu 将全部持久化数据存放在你选择的路径(默认 /mailu):
mkdir /mailu
cd /mailu
生成配置文件
Compose 配置存放在 docker-compose.yml 中,各类设置由 mailu.env 承载。仓库中的 setup/flavors/compose/mailu.env 是配置模板(由配置向导生成),docker-compose.yml 模板 展示了各服务的编排结构:front(nginx 入口)、redis、imap(Dovecot)、smtp(Postfix)、antispam(Rspamd)、antivirus、webdav、admin、webmail、fetchmail 等容器通过同一 SUBNET 组成的 bridge 网络互联。
官方推荐使用 setup 向导(setup.mailu.io)生成这两个文件,向导大部分步骤自解释。生成后打开 mailu.env 逐项复核变量,并参考 配置参考。
确定 TLS 证书方案(TLS_FLAVOR)
TLS_FLAVOR 决定 Mailu 如何获取 x509 证书,可选值:
| 值 | 说明 |
|---|---|
cert | 默认值,需要手动配置证书 |
letsencrypt | 自动使用 Let's Encrypt CA 签发证书 |
notls | 禁用 TLS,仅建议用于测试 |
注意:使用
letsencrypt时,HOSTNAMES中所有主机名的 DNS A/AAAA 记录必须与服务器 IP 一致,否则证书生成会失败,参见 DNS 设置。
配置绑定地址(BIND_ADDRESS)
绑定地址需要与服务器分配的公网 IP 匹配;IPv6 需使用 <global> 作用域地址。可用 ifconfig eth0 等命令查看。如果地址未直接配置在网卡上(NAT),或希望监听所有接口,可使用 0.0.0.0 与 ::——注意此模式不受官方支持并可能引发问题。
启用 hardened-malloc(可选)
若 CPU 支持高级向量扩展(x86_64 的 AVX2、ARM64 的 lrcpc),可在 mailu.env 中加入以下配置,让 hardened-malloc 更早介入启动过程:
LD_PRELOAD=/usr/lib/libhardened_malloc.so
手动配置证书(cert 模式)
Mailu 重度依赖 TLS,至少要为 mailu.env 中配置的主机名准备密钥对与证书。使用 cert 模式时,需在根目录创建 certs 目录并放置:
cert.pem:证书(可用TLS_CERT_FILENAME覆盖文件名)key.pem:私钥(可用TLS_KEYPAIR_FILENAME覆盖文件名)
若使用外部 Let's Encrypt 程序(certbot),不能直接拷贝 letsencrypt/live 目录——其中包含符号链接,容器内无法解析。正确做法是拷贝实际文件:
mkdir -p /mailu/certs
cp /etc/letsencrypt/live/domain.com/privkey.pem /mailu/certs/key.pem
cp /etc/letsencrypt/live/domain.com/fullchain.pem /mailu/certs/cert.pem
后续每次续期后需将新证书复制到 /mailu/certs 并重载 front 容器中的 nginx 进程;可借助 certbot 的 deploy hook 实现自动化,详见 维护指南。
启动 Mailu
在 Mailu 目录下执行:
docker compose up -d
创建管理员账号
启动后需要管理员账号,有两种方式:
方式一:自动创建。利用 INITIAL_ADMIN_* 环境变量,见 配置参考 中的"Admin account - automatic creation"。对应实现位于 core/admin/start.py:容器启动时会读取 INITIAL_ADMIN_ACCOUNT、INITIAL_ADMIN_DOMAIN、INITIAL_ADMIN_PW,并以 --mode 参数调用 flask mailu admin 完成创建。四个变量说明:
INITIAL_ADMIN_ACCOUNT:管理员用户名(邮箱 @ 前部分)INITIAL_ADMIN_DOMAIN:域名后缀,通常与DOMAIN相同INITIAL_ADMIN_PW:管理员密码INITIAL_ADMIN_MODE:创建模式,可选:create(默认):新建账号,已存在则抛异常ifmissing:账号不存在时才创建update:不存在则创建,存在则更新密码
示例:
INITIAL_ADMIN_ACCOUNT=me
INITIAL_ADMIN_DOMAIN=example.net
INITIAL_ADMIN_PW=password
INITIAL_ADMIN_MODE=ifmissing
建议将模式设为 update 或 ifmissing;保持默认值会导致系统重启时报错。
方式二:手动创建:
docker compose exec admin flask mailu admin me example.net 'password'
这会创建用户 me@example.net(密码 password)并授予管理权限,之后应登录 Web 管理界面将其改为强密码。
重要提醒:必须确保存在一个与
mailu.env中POSTMASTER同名的用户或别名,否则会出现各种奇怪的错误。
DNS 配置全流程
邮件系统是去中心化架构:发件方必须通过 DNS 发现收件服务器位置。在开始使用 Mailu 之前,必须至少为一个域名配置好 DNS 以接收邮件。完整的 DNS 设置指南 是部署的必读部分,下面按条目类型拆解。
邮件服务器主机名(A 记录)
为邮件服务器选择唯一主机名(FQDN),指向服务器 IP。建议选取有意义的名称,例如主邮件域是 mydomain.com(即配置中的 DOMAIN)时,可用 mail.mydomain.com 作为主机名,并写入 HOSTNAMES 配置。然后为它配置 A 记录:
mail.mydomain.com. IN A a.b.c.d
同时,a.b.c.d 应设置到 BIND_INTERFACE 配置中(除非服务器在 DMZ 中并通过端口转发暴露服务)。最后为主机名准备正确的 TLS 证书,并按上文"TLS 证书方案"安装。
MX 记录
对每个 Mailu 负责的域名,都需要在 DNS 中配置 MX 记录,其他邮件服务器据此发现负责接收的服务器主机名,再通过 A 记录解析其 IP。以 mydomain.com 为例:
mydomain.com. IN MX 10 mail.mydomain.com.
数字 10 是 MX 优先级,单邮件服务器时意义不大,但若有独立备份服务器则需调整。其他域名同样指向同一个唯一主机名:
myotherdomain.com. IN MX 10 mail.mydomain.com.
反向 DNS(PTR 记录)
强烈建议配置反向 DNS:mail.mydomain.com 解析到 a.b.c.d 时,a.b.c.d 也应解析回同一主机名。验证方式:
nslookup a.b.c.d
反向 DNS 必须由 IP 地址的"所有者"(通常是托管商)设置,可用 whois a.b.c.d 查询。反向 DNS 配置不正确时,多数邮件系统会把你的邮件当作垃圾邮件拒收。
SPF / DKIM / DMARC 记录
最后一步是到管理后台(或使用 CLI)重新生成 DMARC、SPF 与 DKIM 记录:
- 等待主机 DNS 变更生效(并确认 SSL/域名规则配置正确);
- 访问管理后台的域名详情页(如
https://example.com/admin/domain/details/example.com); - 点击 Regenerate Keys(重新生成密钥),将生成的记录添加到 DNS 提供商;
- 若已启用 DKIM/SPF/DMARC 却未添加这些条目,邮件可能无法投递。
DKIM/DMARC 的底层实现可在 core/admin/dkim.py 中查看:该模块负责生成 DKIM 密钥,并在管理后台提供重新生成 SPF/DKIM/DMARC 配置的能力。域名详情视图的对应实现位于 core/admin/ui/views/domains.py。
DOMAIN 与 HOSTNAMES 的区别
这是最常被问到的概念(见 FAQ):
DOMAIN是主邮件域,用于出站邮件的服务器标识与 DMARC 报告地址(POSTMASTER@DOMAIN)。它是纯粹的邮件域,不作为主机使用,不需要证书;但通常也会把它作为一个普通收件域加入。HOSTNAMES是用于连接服务器的主机名,所有列出的主机名都需要证书;TLS_FLAVOR=letsencrypt时会自动为这些域名申请证书。
例如:
DOMAIN=example.com
POSTMASTER=me
HOSTNAMES=mail.example.com,mail.foo.com,bar.com
TLS_FLAVOR=letsencrypt
效果是:DMARC 地址为 me@example.com;服务器发送邮件时以 @example.com 的 SMTP 服务器身份自报(反向 DNS 主机名必须是该域的一部分);三个主机名都会获得证书(需为它们创建指向服务器 IP 的 A/AAAA 记录);管理后台生成的 MX/SPF 示例指向 HOSTNAMES 第一项,仅为示例,可自行修改。IMAP、POP3、SMTP 与 Webmail 在 mail.example.com、mail.foo.com、bar.com 上均可访问。
mailu.env 关键配置变量详解
生成 mailu.env 后应逐项复核。配置参考 完整解释了各变量,下面按类别整理核心项(默认值以当前仓库文档与模板为准)。
公共配置(Common)
| 变量 | 默认值 | 说明 |
|---|---|---|
SECRET_KEY | (必须修改) | 16 字节随机值,用于保护认证 Cookie 等关键用途,可用 pwgen 16 1 生成 |
DOMAIN | — | 主邮件域,用于退信、postmaster 地址等技术地址 |
HOSTNAMES | — | 所有公网主机名,第一个为主主机名,通过 SMTP/IMAP 等暴露 |
SUBNET | — | Mailu Docker 网络的地址范围,不得与系统连接的任何网络冲突 |
POSTMASTER | — | postmaster 地址的 local part,建议设通用值再配置别名 |
WILDCARD_SENDERS | — | 允许从任意现有地址发信(伪造发件人)的用户邮箱逗号分隔列表 |
AUTH_RATELIMIT_IP | 5/hour | 针对特定 IP 子网(AUTH_RATELIMIT_IP_V4_MASK 默认 /24、AUTH_RATELIMIT_IP_V6_MASK 默认 /48)上、针对不存在账号的认证尝试限额,用于对抗密码喷洒攻击 |
AUTH_RATELIMIT_USER | 50/day | 任一账号在时间窗内的不同认证尝试上限,用于对抗密码暴力破解;同账号同密码多次尝试只计一次 |
AUTH_RATELIMIT_EXEMPTION_LENGTH | 86400 | 成功登录后该 IP 免于限速的秒数,避免 NAT 用户被单一错误客户端拖累 |
AUTH_RATELIMIT_EXEMPTION | '' | 不受限速的 CIDR 逗号分隔列表;设为 0.0.0.0/0, ::/0 可整体关闭限速 |
TLS_FLAVOR | — | 证书获取方式(cert/letsencrypt/notls) |
DEFAULT_SPAM_THRESHOLD | 80 | 新建用户默认的垃圾邮件容忍度 |
邮件设置(Mail)
| 变量 | 默认值 | 说明 |
|---|---|---|
MESSAGE_SIZE_LIMIT | 50000000(模板) | 单封邮件最大字节数,过低会丢合法邮件,过高会塞满磁盘 |
MESSAGE_RATELIMIT | 200/day | 单用户每日可发送邮件数上限;MESSAGE_RATELIMIT_EXEMPTION 为豁免名单,用于抑制账号被攻陷后的外发垃圾 |
RELAYNETS | 未设置 | 无需认证即可中继的网络列表。慎用:配置失误会把实例变成开放中继!客户端必须走 25 端口且无认证 |
RELAYHOST | — | 所有出站邮件的 smart host,格式 [HOST]:PORT;RELAYUSER/RELAYPASSWORD 用于认证 |
OUTBOUND_TLS_LEVEL | opportunistic | 出站 TLS 策略,可设 encrypt 或 secure;使用支持 TLS 的 relayhost 时强烈建议设置 |
DEFER_ON_TLS_ERROR | True | 不完整策略(无 DNSSEC 的 DANE、testing 的 MTA-STS)是否生效并在检查失败时延迟投递 |
INBOUND_TLS_ENFORCE | False | 入站是否强制 TLS。设为 True 对互联网主机是被 RFC 3207 禁止的,会阻止不支持 STARTTLS 的 MTA 投递 |
SCAN_MACROS | True | 是否拒收含恶意宏的文档,底层使用 oletools 的 mraptor 判断 |
FETCHMAIL_ENABLED | True | 启用 fetchmail 功能并在管理界面展示(容器仍需手动部署) |
FETCHMAIL_DELAY | — | fetchmail 拉取新邮件的间隔秒数:过短会被外部服务拉黑,过长则邮件不及时 |
RECIPIENT_DELIMITER | + | 分隔 localpart 与自定义地址部分的字符列表,如 +- 可让 localpart+custom@example.com 投递到 localpart@example.com,便于按自定义部分分类 |
DMARC_RUA / DMARC_RUF | — | DMARC 的 rua/ruf 地址 localpart |
DMARC_SEND_REPORTS | false | 启用 Rspamd 3.0+ 自动生成并发送每日 DMARC 聚合报告;报告于每日凌晨 2 点以 POSTMASTER@DOMAIN 名义发送前一日流量 |
FULL_TEXT_SEARCH | en | 逗号分隔的 ISO 639-1 语言代码(Dovecot 支持列表);设为 off 可关闭(如出于性能考虑) |
DEFAULT_QUOTA | — | 域未配置特定配额时使用的全局邮箱配额 |
Web 设置(Web)
WEB_ADMIN:管理界面路径(/admin)WEB_WEBMAIL:Web 邮件客户端路径(/webmail)WEB_API:RESTful API 路径(/api)WEBROOT_REDIRECT:所有未匹配请求的重定向目标;空值禁用重定向并恢复 404 行为;设为none可配合自定义的location /覆盖- 以上四项都需要以
/开头;WEBROOT_REDIRECT必须指向已启用服务的有效路径(如WEBMAIL=none时不能指向/webmail) SITENAME/WEBSITE:面板菜单与各 Web 界面的品牌定制LOGO_BACKGROUND:管理界面左上角品牌 logo 的背景色LOGO_URL:自定义 logo 的 URL
高级设置(Advanced)
| 变量 | 默认值 | 说明 |
|---|---|---|
AUTH_REQUIRE_TOKENS | False | 是否强制厚客户端使用令牌/应用专用密码而非密码认证 |
API_TOKEN | None | RESTful API 的认证令牌(至少 3 字符),通过请求头传递,是使用 API 的必需项 |
CREDENTIAL_ROUNDS | 13 | 密码哈希的轮数,可降低以提升认证速度或提高以增强防护(对抗离线破解与撞库) |
SESSION_COOKIE_SECURE | True | 管理界面 Cookie 的 secure 标志,仅当通过明文 HTTP 访问时才应关闭 |
SESSION_TIMEOUT | 3600 | 两次请求间的最长秒数,超过则会话失效 |
PERMANENT_SESSION_LIFETIME | 108000 | 会话未超时情况下可存活的最长秒数 |
LOG_LEVEL | — | Python 启动脚本的日志阈值:CRITICAL/ERROR/WARNING/INFO/DEBUG/NOTSET |
LETSENCRYPT_SHORTCHAIN | False | 握手时是否发送 ISRG Root X1 证书;对 Android 7.1.1 以下旧设备必需,但会拖慢现代设备 |
TLS_PERMISSIVE | true | 25 端口 STARTTLS 的密码套件/协议是否以最大兼容性优化;官方强烈建议不改,任何加密都优于不加密 |
COMPRESSION | 未设置 | 邮件落盘压缩:gz、bz2 或 zstd;COMPRESSION_LEVEL 含义依方法而异(gz 为 zlib 0-9,zstd 为 zstd level,bz2 为 100k 单位的块大小 1-9)。文件系统本身支持压缩时更推荐用文件系统压缩 |
REAL_IP_HEADER / REAL_IP_FROM | 未设置 | 反向代理场景下信任的客户端 IP 头与可信代理列表。只设前者不设后者存在安全隐患,攻击者可伪造来源地址 |
TZ | Etc/UTC | 容器时区,建议保持 UTC 以便与远程 MTA 对齐日志 |
PORTS | 25,80,443,465,993,995,4190 | 启用的服务端口列表;需重新启用 IMAP/POP3/Submission 可追加 110,143,587;25、465、993 不可关闭 |
PROXY_PROTOCOL | 未设置 | 前端容器启用 PROXY protocol 的端口列表,必须配合 REAL_IP_FROM 且 REAL_IP_HEADER 必须未设置;只信任可信来源,否则是严重的安全漏洞 |
杀毒与基础设施设置
ANTIVIRUS_ACTION:检测到病毒时的行为,默认discard(静默丢弃);设为reject时 rspamd 在 SMTP 对话中拒收,发件人收到拒信。*_ADDRESS系列(ADMIN_ADDRESS、ANTISPAM_ADDRESS、ANTIVIRUS_ADDRESS、FRONT_ADDRESS、IMAP_ADDRESS、REDIS_ADDRESS、SMTP_ADDRESS、WEBDAV_ADDRESS、WEBMAIL_ADDRESS):在脱离编排器单独运行容器时用于服务发现,值必须是不含端口号的 FQDN。
数据库设置
admin 与 roundcube 服务默认使用 SQLite 存储配置,官方推荐维持 SQLite(数据量小、更简单可靠):
SQLALCHEMY_DATABASE_URI:默认sqlite:////data/main.dbSQLALCHEMY_DATABASE_URI_ROUNDCUBE:默认sqlite:////data/roundcube.db
如需外部数据库,PostgreSQL 用 postgresql://mailu:mailu_secret_password@database/mailu,MariaDB/MySQL 用 mysql+mysqlconnector://mailu:mailu_secret_password@database/mailu。
Webmail 插件设置
ROUNDCUBE_PLUGINS 可指定逗号分隔的插件列表(如 acl、archive、carddav、enigma、mailu、managesieve、markasjunk、zipdownload 等,详见 配置参考)。未设置时默认启用 archive、carddav、enigma、mailu、managesieve、markasjunk、zipdownload;设为 mailu 可关闭全部插件。插件配置可通过向 roundcube 的 override 目录添加 *.inc.php 文件完成。
上线前的测试清单
完成部署与 DNS 配置后,务必先充分测试再上线:
- 尝试向外部服务发送一封邮件;
- 在外部服务端确认 DKIM 与 SPF 均标记为 passing;
- 尝试从外部服务接收一封邮件;
- 检查日志(
docker compose logs -f 服务名)中是否有警告或错误; - 使用 mxtoolbox 之类的开放中继检测工具,确认没有为互联网垃圾问题做贡献;
- 若启用 DMARC,检查收到的报告,确认合法邮件正常送达、伪造邮件被正确拦截。
常见问题与排障要点
结合 FAQ,部署中最常遇到的坑集中在以下几处:
mailu.env变更不生效:变量在容器创建时注入,必须docker compose down && docker compose up -d,仅 restart 容器无效。- TLS 证书问题导致 403:Mailu 在证书异常时会在安全端口拒绝服务。常见原因:
TLS_FLAVOR=notls、证书过期、letsencrypt模式证书签发失败(检查docker compose logs front与容器内/var/log/letsencrypt/letsencrypt.log,确认 80 端口可达、HOSTNAMES的 A/AAAA 记录正确、等待 DNS TTL 过期后再重试)、cert模式拷贝了带符号链接的 letsencrypt 目录。 - SMTP 横幅覆盖无效:所有与邮件相关的连接都由 front 容器代理,因此 SMTP Banner 也由 front 设置,
overrides/postfix.cf中的覆盖不生效。 - SPF 校验失败:多数是 Mailu 出站 IP 与 env 中配置的 IP 不一致(如 Docker NAT 导致),可检查收件方邮件头确认;如需显式 NAT 出站 SMTP,可用
iptables -t nat -A POSTROUTING -o eth0 -p tcp --dport 25 -j SNAT --to <你的 MX IP>。 - DNSSEC 要求:自 v1.9 起 Mailu 需要支持 DNSSEC 验证的解析器(用
dig @<ip> +adflag example.org A检查 AD 标志),推荐自带 unbound 解析器。 - IPv6 部署:必须先在
/etc/docker/daemon.json中设置"userland-proxy": false,否则可能变成开放中继;可选用 docker-ipv6nat 容器。 - 删除用户:Web 界面删除用户实际是"禁用";彻底清除数据需配合 scripts/purge_user.sh 完成 Dovecot 邮箱、roundcube 数据与数据库记录的清理。
总结
Mailu 的部署链路可以归纳为一条清晰的流水线:评估硬件与架构 → 选择稳定版本 → 准备 Compose 与 mailu.env → 配置 TLS → 启动并创建管理员 → 配置 DNS(A/MX/PTR/SPF/DKIM/DMARC)→ 按测试清单验证后上线。每一步都可以在仓库中找到对应的配置模板(setup/flavors/compose/mailu.env、docs/compose/docker-compose.yml)或实现源码(如 core/admin/start.py 的管理员自动创建、core/admin/dkim.py 的密钥生成)。遵循这条路径,你就能以最小的试错成本搭建一台可以安全收发电邮的 Mailu 服务器。
【免费下载链接】Mailu
Insular email distribution - mail server as Docker images
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



