docker-mailserver Docker Compose 部署指南

docker-mailserver(ghcr.io 镜像 16.0.1)Docker Compose 部署指南:compose 逐段解析、端口映射表、数据卷目录、setup.sh 账号/域名/DKIM 初始化实测与常见问题(120 秒建号窗口、restart 与重建差异)。

docker-mailserverdocker-mailserver2026/10/18

docker-mailserver Docker Compose 部署指南

‍‍​​‌​> 目标:从零在一台 Ubuntu 服务器上以官方镜像部署 docker-mailserver(DMS)邮件服务器,覆盖 compose 逐段解析、端口映射、数据卷目录、setup.sh 初始化(账号/域名/DKIM)与部署期常见问题。全部命令与回显在 Ubuntu 22.04 + DMS 16.0.1 实测通过,数据目录 /opt/data/docker-mailserver/。

一、环境信息

  • 操作系统:Ubuntu 22.04(内核 6.8.x,x86_64)
  • Docker:29.8.1,Compose 插件 v2.40.3(docker compose version 实测)
  • docker-mailserver:16.0.1(ghcr.io/docker-mailserver/docker-mailserver:16.0.1)
  • 邮件域名:example.com,邮件主机名:mail.example.com(需有对应 DNS A 记录与 MX 记录)
  • 服务端口(宿主机实测监听):
$ ss -ltn | grep -E ':(13925|14587|14143)\s'
LISTEN 0      4096         0.0.0.0:14143      0.0.0.0:*
LISTEN 0      4096         0.0.0.0:13925      0.0.0.0:*
LISTEN 0      4096         0.0.0.0:14587      0.0.0.0:*
LISTEN 0      4096            [::]:14143         [::]:*
LISTEN 0      4096            [::]:13925         [::]:*
LISTEN 0      4096            [::]:14587         [::]:*
  • 数据目录:/opt/data/docker-mailserver/(mail-data 邮件存储 / state 状态与内部数据库 / config 账号与覆盖配置,另有 logs 日志与 ssl 证书两个可选目录)

二、镜像选型说明

docker-mailserver 官方镜像有两个仓库地址,选型结论如下(2026-10-18 manifest 实查):

仓库实测结论结论
ghcr.io/docker-mailserver/docker-mailserver16.0.1 标签存在(docker manifest inspect 通过)推荐,必选
docker.io/mailserver/docker-mailserver:latest 与 :16.0.1 均 manifest inspect 失败(Hub tag MISSING)不可用(旧命名空间已无有效标签)

版本标签策略:固定使用版本号标签(如 16.0.1)而非 latest,升级时显式改标签重建,避免不可控漂移。拉取与确认:

docker pull ghcr.io/docker-mailserver/docker-mailserver:16.0.1

启动后版本自报(实测日志首行):

2026-10-18 08:47:40+08:00 INFO  start-mailserver.sh: Welcome to docker-mailserver v16.0.1

三、前置条件

  1. DNS 记录(部署前在域名服务商处确认):
    • A 记录:mail.example.com → 服务器公网 IP;
    • MX 记录:example.com → mail.example.com(优先级 10);
    • SPF/DMARC/DKIM 记录在第四章 DKIM 生成后补齐(记录值实测生成,见 4.5)。
  2. 端口规划:本指南采用非标准高位端口映射(25→13925、587→14587、143→14143),适配 25 端口被云厂商限制或已有服务占用的情况。生产环境若可直用标准端口,把映射左侧改为 25/587/143/465/993 即可。
  3. 检查端口占用:
ss -ltn | grep -E ':(13925|14587|14143)\s' || echo 'ports free'

部署前实测:ports 13925/14587/14143 free(无输出即空闲)。 4. 创建数据目录:

mkdir -p /opt/data/docker-mailserver/{mail-data,state,config}
  1. 下载官方管理脚本与配置模板(与镜像版本同 tag):
curl -fLso /opt/data/docker-mailserver/setup.sh \
  https://raw.githubusercontent.com/docker-mailserver/docker-mailserver/v16.0.1/setup.sh
chmod a+x /opt/data/docker-mailserver/setup.sh
curl -fLso /opt/data/docker-mailserver/mailserver.env \
  https://raw.githubusercontent.com/docker-mailserver/docker-mailserver/v16.0.1/mailserver.env

四、部署步骤

4.1 编写 docker-compose.yml

完整文件(本指南实测所用,逐段解析见 4.2):

services:
  mailserver:
    image: ghcr.io/docker-mailserver/docker-mailserver:16.0.1
    container_name: dms-16.0.1-mail
    hostname: mail.example.com
    env_file: mailserver.env
    ports:
      - "13925:25"    # SMTP  (STARTTLS)
      - "14587:587"   # ESMTP submission (STARTTLS)
      - "14143:143"   # IMAP4 (STARTTLS)
    volumes:
      - ./mail-data/:/var/mail/
      - ./state/:/var/mail-state/
      - ./config/:/tmp/docker-mailserver/
      - ./logs/:/var/log/mail/
      - ./ssl/:/etc/dms/tls/
      - /etc/localtime:/etc/localtime:ro
    cap_add:
      - NET_ADMIN
    dns:
      - 192.168.112.53
    restart: always
    stop_grace_period: 1m

4.2 逐段解析

  • image:固定版本标签 16.0.1,选型依据见第二章;
  • container_name:dms-16.0.1-mail,便于日志与命令定位;
  • hostname:必须为邮件主机名(mail.example.com),Postfix/Dovecot 的 EHLO、证书校验、日志主机名都取自它;
  • env_file:加载官方 mailserver.env(第 4.3 节调整);
  • ports:三组映射,对应 SMTP 收信、认证提交、IMAP 收信;465(SMTPS)、993(IMAPS)、995(POP3S)端口在镜像内已监听(见第 4.6 端口表),如需对外暴露自行加映射;
  • volumes:五个挂载点——邮件存储、内部状态、账号配置、日志持久化、TLS 证书,全部 bind mount 到宿主机(第五章);
  • cap_add: NET_ADMIN:仅当启用 fail2ban(ENABLE_FAIL2BAN=1)时必需(封禁靠防火墙规则实现),未启用可删;
  • dns:本环境指向内部 DNS 192.168.112.53(发布测试域 SPF/DKIM/DMARC 记录的 dnsmasq);生产环境删除此段,使用宿主机默认解析即可;
  • restart: always:开机自启与异常自动拉起;
  • stop_grace_period: 1m:给 Postfix/Dovecot 一分钟优雅排空在途连接,避免强杀丢信。

4.3 调整 mailserver.env(本指南实测值)

从官方模板修改以下键(默认值与逐参数实测见《docker-mailserver 16.0.1 配置参数详解》):

TZ=Asia/Shanghai
ENABLE_RSPAMD=1
ENABLE_CLAMAV=1
ENABLE_OPENDKIM=0
ENABLE_OPENDMARC=0
ENABLE_POLICYD_SPF=0
ENABLE_AMAVIS=0

⚠️ 实测注意:模板默认 ENABLE_RSPAMD=0 且旧栈(Amavis/OpenDKIM/OpenDMARC/policyd-spf)为 1。实测同开两套栈时启动日志明确警告并存不推荐,DKIM/SPF/DMARC 应全部交由 Rspamd 承担,旧栈四项全部置 0。完整实测证据(警告原文与消除过程)见《docker-mailserver 安全加固指南》。

4.4 启动与验证

cd /opt/data/docker-mailserver
docker compose up -d

启动状态实测(docker compose ps):

NAME              IMAGE                                                COMMAND                   SERVICE      CREATED          STATUS                    PORTS
dms-16.0.1-mail   ghcr.io/docker-mailserver/docker-mailserver:16.0.1   "/usr/bin/dumb-init …"   mailserver   16 minutes ago   Up 16 minutes (healthy)   110/tcp, 465/tcp, 993/tcp, 995/tcp, 4190/tcp, 0.0.0.0:13925->25/tcp, [::]:13925->25/tcp, 0.0.0.0:14143->143/tcp, [::]:14143->143/tcp, 0.0.0.0:14587->587/tcp, [::]:14587->587/tcp

启动完成日志实测(docker logs dms-16.0.1-mail 节选):

2026-10-18 08:47:40+08:00 INFO  start-mailserver.sh: Welcome to docker-mailserver v16.0.1
2026-10-18 08:47:42+08:00 INFO  start-mailserver.sh: mail.example.com is up and running

看到 up and running 即部署完成。(healthy) 状态来自镜像内置健康检查(dms healthcheck),首次启动约需 30~60 秒。

4.5 setup.sh 初始化(账号 / 域名 / DKIM)

初始化全部通过 setup.sh 完成(命令在宿主机数据目录执行,脚本自动连接运行中的服务)。

第一步:创建邮箱账号(首次创建账号会自动登记邮件域 example.com):

./setup.sh email add admin@example.com q1w2e3r4
./setup.sh email add user@example.com q1w2e3r4

实测:两条命令静默返回(退出码 0,无输出)。列出账号确认(./setup.sh email list 实测回显):

* admin@example.com ( 8.0K / ~ ) [0%]
    [ aliases -> info@example.com ]

* user@example.com ( 5.0K / 1.0G ) [0%]

(~ 表示未设配额;user@example.com 的 1.0G 来自后续执行的 ./setup.sh quota set user@example.com 1G。)

第二步:生成 DKIM 密钥:

./setup.sh config dkim

实测结果:在 config/rspamd/dkim/ 下生成 RSA-2048 密钥对(选择器 mail),同时打印对应 DNS TXT 记录全文。生成文件实测清单:

config/rspamd/dkim/rsa-2048-mail-example.com.private.dns.txt
config/rspamd/dkim/rsa-2048-mail-example.com.public.dns.txt
config/rspamd/dkim/mail.example.com.key
config/rspamd/dkim/mail.example.com.pub

把 public.dns.txt 中的 mail._domainkey.example.com TXT 记录发布到 DNS 后,DKIM 签名即可被外部验证(收发实测与头字段验证见《docker-mailserver 安全加固指南》)。

第三步:别名与配额(按需):

./setup.sh alias add info@example.com admin@example.com   # 别名投递到 admin
./setup.sh quota set user@example.com 1G                  # 1G 配额

别名写入 config/postfix-virtual.cf(实测文件内容:info@example.com admin@example.com),投递改写实测日志:

2026-10-18T08:59:43.724810+08:00 mail postfix/lmtp[2442]: D91AA9005FF: to=<admin@example.com>, orig_to=<info@example.com>, relay=mail.example.com[/var/run/dovecot/lmtp], delay=0.87, delays=0.85/0.01/0.01/0.01, dsn=2.0.0, status=sent (250 2.0.0 <admin@example.com> eIbZKv8Z1GqLCQAAYIgGOA Saved)

4.6 端口表

容器端口协议用途宿主机映射(本指南)TLS 形态(实测)
25SMTP 收信13925STARTTLS(配置证书后出现在 EHLO 能力中)
587ESMTP 认证提交14587STARTTLS + AUTH LOGIN
143IMAP414143STARTTLS
465SMTPS 提交未映射(按需添加)隐式 TLS
993IMAPS未映射(按需添加)隐式 TLS(配置证书后实测监听)
995POP3S未映射(默认未启用 POP3)隐式 TLS
110POP3未映射(默认未启用)STARTTLS
4190ManageSieve未映射(按需添加)—

⚠️ 143/465/993 等端口在 docker compose ps 的 PORTS 列中始终显示(镜像 EXPOSE),对外是否可达取决于是否写 ports 映射与防火墙放行。

五、数据持久化说明

五个挂载目录与实测占用(du -sh 实测,启用 Rspamd + ClamAV 运行一阶段后):

目录容器内路径内容实测占用
mail-data//var/mail/邮件存储(Maildir,按域名/账号分目录)192K
state//var/mail-state/各组件内部状态与数据库112M
config//tmp/docker-mailserver/账号/别名/配额数据 + 覆盖配置 + DKIM 密钥56K
logs//var/log/mail/mail.log 等日志持久化404K
ssl//etc/dms/tls/TLS 证书与私钥20K

state/ 实测目录清单(各组件状态隔离存放,重建不丢状态):

lib-amavis  lib-clamav  lib-dovecot  lib-fail2ban  lib-logrotate
lib-postfix  lib-redis  lib-rspamd  spool-postfix

邮件目录结构实测示例:mail-data/example.com/admin/new/ 下为单封邮件文件(Maildir 格式),Junk 等子文件夹为 .Junk/ 隐藏目录。

六、环境变量表

以下为部署决策相关核心键(完整键集见官方 mailserver.env 模板,逐键实测与改值对比见《docker-mailserver 16.0.1 配置参数详解》):

变量默认本指南取值作用(实测依据)
TZ空Asia/Shanghai日志时区(实测日志带 +08:00)
ENABLE_RSPAMD01启用 Rspamd 反垃圾 + DKIM/SPF/DMARC
ENABLE_CLAMAV01启用病毒扫描
ENABLE_AMAVIS10旧内容过滤网关,Rspamd 启用后关闭
ENABLE_OPENDKIM10旧 DKIM 栈,交由 Rspamd
ENABLE_OPENDMARC10旧 DMARC 栈,交由 Rspamd
ENABLE_POLICYD_SPF10旧 SPF 栈,交由 Rspamd
SSL_TYPE空manual证书接入方式(letsencrypt/manual/self-signed)
SSL_CERT_PATH空/etc/dms/tls/fullchain.pem证书路径(配合 manual)
SSL_KEY_PATH空/etc/dms/tls/privkey.pem私钥路径(配合 manual)
ENABLE_FAIL2BAN01认证爆破封禁(需 NET_ADMIN 能力)
SPOOF_PROTECTION空1禁止认证身份与发件地址不匹配(实测 553 拒信)
PERMIT_DOCKERnonenone信任网段控制,保持 none 防开放中继
POSTMASTER_ADDRESS空空(按域名默认)管理员邮箱
MOVE_SPAM_TO_JUNK11垃圾自动归档 Junk(实测生效)

七、配置参数说明

配置体系分三层:mailserver.env 声明式总开关(第六章)→ config/ 下账号与域数据文件(setup.sh 自动维护,手工不编辑)→ 细粒度覆盖文件(config/postfix-main.cf、config/dovecot.cf、config/rspamd/override.d/)。第三层的改值→重启→行为对比实测、两层配置热加载边界(哪些文件改动即时生效、哪些必须重建)详见《docker-mailserver 16.0.1 配置参数详解》。

八、配置文件挂载

config/ 挂载到容器 /tmp/docker-mailserver/(这是官方约定路径,文档与工具均按此路径引用)。部署完成后实测目录内容:

postfix-accounts.cf     # 账号哈希(email add 自动写入)
postfix-virtual.cf      # 别名表(alias add 自动写入)
dovecot-quotas.cf       # 配额表(quota set 自动写入)
rspamd/dkim/            # DKIM 密钥与 DNS 记录(config dkim 生成)
rspamd/override.d/      # Rspamd 覆盖配置(可选,手工)
postfix-main.cf         # Postfix 主配置覆盖(可选,手工)
dovecot.cf              # Dovecot 配置覆盖(可选,手工)

⚠️ 这些文件随宿主机目录持久化,升级重建后账号/别名/密钥全部保留;postfix-accounts.cf 存的是口令哈希,禁止明文备份外传。

九、等价 docker run

与第五章 compose 等价的单命令启动形态(官方 README 同款写法,本指南实测通过;--env-file、卷路径按实际值填写):

docker run -d --name dms-16.0.1-run \
  --hostname mail.example.com \
  --env-file /opt/data/docker-mailserver/mailserver.env \
  -v /opt/data/docker-mailserver-equiv/mail-data/:/var/mail/ \
  -v /opt/data/docker-mailserver-equiv/state/:/var/mail-state/ \
  -v /opt/data/docker-mailserver-equiv/config/:/tmp/docker-mailserver/ \
  -v /opt/data/docker-mailserver/ssl/:/etc/dms/tls/:ro \
  -v /etc/localtime:/etc/localtime:ro \
  --restart always --stop-timeout 60 \
  ghcr.io/docker-mailserver/docker-mailserver:16.0.1

实测启动日志(全新空数据目录):

2026-10-18 09:11:54+08:00 INFO  start-mailserver.sh: Welcome to docker-mailserver v16.0.1
2026-10-18 09:11:54+08:00 WARN  start-mailserver.sh: You need at least one mail account to start Dovecot (120s left for account creation before shutdown)

倒计时窗口内创建账号后服务完成启动(实测 docker exec -i dms-16.0.1-run setup email add demo@example.com temp12345 后):

2026-10-18 09:13:16+08:00 INFO  start-mailserver.sh: mail.example.com is up and running

十、常用运维命令

docker compose ps                      # 状态与健康检查(实测 healthy)
docker logs -f dms-16.0.1-mail         # 实时日志(含每个账号创建、每封收发)
docker compose restart mailserver      # 重启(仅重启进程,不重新应用主配置覆盖)
docker compose up -d --force-recreate  # 重建实例(应用 postfix-main.cf/dovecot.cf 等主配置)
./setup.sh help                        # 管理命令总览

setup.sh 完整命令树(./setup.sh help 实测节选):

COMMAND := { email | alias | quota | dovecot-master | config | relay | debug } SUBCOMMAND

[SUB]COMMANDS
    COMMAND email :=
        setup email add <EMAIL ADDRESS> [<PASSWORD>]
        setup email update <EMAIL ADDRESS> [<PASSWORD>]
        setup email del [ OPTIONS... ] <EMAIL ADDRESS> [ <EMAIL ADDRESS>... ]
        setup email restrict <add|del|list> <send|receive> [<EMAIL ADDRESS>]
        setup email list
    COMMAND alias :=
        setup alias add <EMAIL ADDRESS> <RECIPIENT>
        setup alias del <EMAIL ADDRESS> <RECIPIENT>
        setup alias list
    COMMAND quota :=
        setup quota set <EMAIL ADDRESS> [<QUOTA>]
        setup quota del <EMAIL ADDRESS>
    COMMAND dovecot-master :=
        setup dovecot-master add <USERNAME> [<PASSWORD>]
        setup dovecot-master update <USERNAME> [<PASSWORD>]
        setup dovecot-master del [ OPTIONS... ] <USERNAME> [ <EMAIL ADDRESS>... ]
        setup dovecot-master list
    COMMAND config :=
        setup config dkim [ ARGUMENTS... ]
    COMMAND relay :=
        setup relay add-auth <DOMAIN> <USERNAME> [<PASSWORD>]

日常运维(巡检/排障/备份/升级)的完整实操见《docker-mailserver 日常运维手册》,安全加固见《docker-mailserver 安全加固指南》。

十一、常见问题

Q1:全新部署启动后 120 秒后自动退出? 这是设计行为:空账号环境启动时进入建号倒计时(实测日志 You need at least one mail account to start Dovecot (120s left for account creation before shutdown))。在窗口期内执行 ./setup.sh email add <地址> <密码> 即正常完成启动(见第九章实测流程)。

Q2:改了 config/postfix-main.cf 或 config/dovecot.cf 重启后不生效? 实测确认:docker compose restart 会跳过大部分初始化(日志实测:Container was restarted. Skipping most setup routines.),主配置覆盖文件只在实例重建时应用。改这两类文件后必须执行 docker compose up -d --force-recreate。实测对比:message_size_limit 默认 10240000,改写覆盖文件后 restart 无效,--force-recreate 后 postconf message_size_limit 返回 20480000、EHLO 能力同步显示 250-SIZE 20480000。

Q3:email list 对新账号报错? 实测:刚创建、尚未收到第一封邮件的账号执行 ./setup.sh email list 会输出:

doveadm(third@example.com): Error: cmd quota get: User doesn't exist
2026-10-18 08:58:58+08:00 ERROR listmailuser: Supplied non-number argument '' to '_bytes_to_human_readable_size()'
* third@example.com (  /  ) [%]

mailbox 目录生成后(收到第一封邮件)自动恢复正常,属无害告警。

Q4:启动日志警告 Rspamd 与 Amavis/OpenDKIM/OpenDMARC/policyd-spf 并存? v16 推荐 DKIM/SPF/DMARC 与评分全部由 Rspamd 承担,把 ENABLE_AMAVIS/ENABLE_OPENDKIM/ENABLE_OPENDMARC/ENABLE_POLICYD_SPF 全部置 0 后警告消失(实测)。

Q5:外部发件域不可解析时收不到信? 实测日志:450 4.1.8 <friend@external.test>: Sender address rejected: Domain not found——这是 Postfix 对发件域做 DNS 校验的默认行为(reject_unknown_sender_domain),属正常防护,请使用真实可解析的域名发信测试。

Q6:对外发送被拒 Relay access denied? 实测:来自非信任来源、收件人非本域的请求一律拒绝(实测日志 554 5.7.1 <nobody@dead.test>: Relay access denied),这是防开放中继的正确行为;对外投递请走 587/465 端口认证提交。

Q7:云服务器收不到 25 端口入站? 多数云厂商默认封禁入站 25。可先用本指南的高位端口映射跑通功能,再向厂商申请解封;或保留高位映射并配合中继(setup relay)出站。

十二、参考链接

  • 官方部署文档:https://docker-mailserver.github.io/docker-mailserver/latest/usage/
  • Compose 示例:https://github.com/docker-mailserver/docker-mailserver/blob/master/compose.yaml
  • 环境变量说明:https://docker-mailserver.github.io/docker-mailserver/latest/config/environment/
  • setup.sh 下载页(按 tag 取对应版本):https://raw.githubusercontent.com/docker-mailserver/docker-mailserver/v16.0.1/setup.sh
  • 官方 FAQ:https://docker-mailserver.github.io/docker-mailserver/latest/faq/