AnonAddy 1.7.3 Docker Compose 部署指南
用 Docker Compose 编排 AnonAddy 1.7.3 全家桶(app + MariaDB + Redis),跑通 Web 控制台与完整别名邮件流
AnonAddy 1.7.3 Docker Compose 部署指南
目标:用 Docker Compose 一键编排 AnonAddy(addy.io)v1.7.3 全家桶(app + MariaDB + Redis),跑通 Web 控制台与「收信→别名转发→退信回执」完整邮件流。已在 Ubuntu 22.04 + Docker 29 环境实测通过。
一、环境信息
- 操作系统:Ubuntu 22.04 LTS,Docker Engine 29.9.2,Docker Compose v2
- 应用镜像:
anonaddy/anonaddy:1.7.3(官方镜像,内置 Nginx + PHP-FPM + Postfix + cron,s6-overlay 进程管理) - 数据镜像:
mariadb:12、redis:8-alpine - Compose 项目名:
anonaddy-1.7.3-stack;容器:anonaddy-1.7.3-app/-db/-redis - 端口:25(SMTP 收信)、8000(Web);演示管理员
admin/q1w2e3r4 - 域名约定:
example.com(主域)、mail.example.com(MX 主机)、app.example.com:8000(Web 访问)
二、镜像选型说明
| 镜像 | 角色 | 实测版本 | 说明 |
|---|---|---|---|
anonaddy/anonaddy:1.7.3 | 应用+MTA 一体 | Postfix 3.11.7 / PHP 8.3 | 官方多架构镜像,Docker Hub 有 73 个标签,固定版本号优于 latest |
mariadb:12 | 数据库 | 12.x | 官方 compose 示例同款,utf8mb4 |
redis:8-alpine | 缓存/队列 | 8.x | 官方示例同款 |
镜像内置行为(实测日志确认):首次启动自动执行数据库迁移、生成/写入 .env、拉起 nginx/php-fpm/postfix/cron 四个服务;Postfix 管道 anonaddy 与 policy 服务已在镜像 master.cf 中预置,无需手工配置——这是与裸机安装最大的差别。
三、前置条件
docker version --format '{{.Server.Version}}'
docker compose version
实测回显:
29.9.2
准备目录(数据持久化到宿主):
mkdir -p /opt/anonaddy/db /opt/anonaddy/data
生成两个必填随机值:
php -r "echo 'base64:'.base64_encode(random_bytes(32)).PHP_EOL;" # APP_KEY
php -r "echo bin2hex(random_bytes(32)).PHP_EOL;" # ANONADDY_SECRET
无 PHP 时可用 openssl rand -base64 32 / openssl rand -hex 32 替代。
四、部署步骤
4.1 编写 compose 文件
/opt/anonaddy/compose.yml(基于官方 examples/compose 调整,完整实测通过):
name: anonaddy-1.7.3-stack
services:
db:
image: mariadb:12
container_name: anonaddy-1.7.3-db
command:
- "mariadbd"
- "--character-set-server=utf8mb4"
- "--collation-server=utf8mb4_unicode_ci"
volumes:
- "/opt/anonaddy/db:/var/lib/mysql"
environment:
- "MARIADB_RANDOM_ROOT_PASSWORD=yes"
- "MYSQL_DATABASE=addy"
- "MYSQL_USER=addy"
- "MYSQL_PASSWORD=q1w2e3r4"
restart: always
redis:
image: redis:8-alpine
container_name: anonaddy-1.7.3-redis
restart: always
app:
image: anonaddy/anonaddy:1.7.3
container_name: anonaddy-1.7.3-app
depends_on:
- db
- redis
ports:
- "25:25"
- "8000:8000"
volumes:
- "/opt/anonaddy/data:/data"
environment:
- "TZ=Asia/Shanghai"
- "MEMORY_LIMIT=256M"
- "UPLOAD_MAX_SIZE=16M"
- "APP_KEY=base64:DSzQlrItKPRFcKRqaTEHAEaU+kZPyvCN+6e2QWgOKnE="
- "APP_DEBUG=false"
- "APP_URL=http://app.example.com:8000"
- "ANONADDY_RETURN_PATH=bounces@example.com"
- "ANONADDY_ADMIN_USERNAME=admin"
- "ANONADDY_ENABLE_REGISTRATION=true"
- "ANONADDY_DOMAIN=example.com"
- "ANONADDY_ALL_DOMAINS=example.com"
- "ANONADDY_HOSTNAME=mail.example.com"
- "ANONADDY_DNS_RESOLVER=127.0.0.11"
- "ANONADDY_SECRET=322cad02194d3de6144dbdffa35aab2aec46b74595e104cc7d53ebff38ede121"
- "ANONADDY_LIMIT=200"
- "ANONADDY_BANDWIDTH_LIMIT=104857600"
- "ANONADDY_NEW_ALIAS_LIMIT=10"
- "ANONADDY_ADDITIONAL_USERNAME_LIMIT=3"
- "MAIL_FROM_NAME=AnonAddy"
- "MAIL_FROM_ADDRESS=mailer@example.com"
- "POSTFIX_DEBUG=false"
- "POSTFIX_SMTPD_TLS=false"
- "POSTFIX_SMTP_TLS=false"
- "DB_HOST=db"
- "DB_DATABASE=addy"
- "DB_USERNAME=addy"
- "DB_PASSWORD=q1w2e3r4"
- "REDIS_HOST=redis"
restart: always
⚠️ 注意:
APP_KEY、ANONADDY_SECRET务必换成 4.1 节自己生成的值,上面的值是本文实验实例的实测值。实验环境关闭了 Postfix TLS 与对端校验;公网生产部署应申请证书后开启POSTFIX_SMTPD_TLS=true等(见《AnonAddy 配置参数详解》)。
4.2 启动并确认
cd /opt/anonaddy
docker compose up -d
docker compose ps
实测回显:
NAME IMAGE COMMAND SERVICE STATUS PORTS
anonaddy-1.7.3-app anonaddy/anonaddy:1.7.3 "/init" app Up 30 seconds 0.0.0.0:25->25/tcp, [::]:25->25/tcp, 0.0.0.0:8000->8000/tcp, [::]:8000->8000/tcp, 11334/tcp
anonaddy-1.7.3-db mariadb:12 "docker-entrypoint.s…" db Up 30 seconds 3306/tcp
anonaddy-1.7.3-redis redis:8-alpine "docker-entrypoint.s…" redis Up 30 seconds 6379/tcp
观察初始化日志(自动迁移 + 拉起 Postfix):
docker logs anonaddy-1.7.3-app 2>&1 | tail -8
实测回显:
[services.d] done.
[25-Oct-2026 10:29:04] NOTICE: fpm is running, pid 749
[25-Oct-2026 10:29:04] NOTICE: ready to handle connections
postfix/postlog: starting the Postfix mail system
Oct 25 10:29:04 mail postfix/master[1122]: daemon started -- version 3.11.7, configuration /etc/postfix
Web 入口验证:
curl -s -o /dev/null -w "%{http_code}\n" -H "Host: app.example.com:8000" http://127.0.0.1:8000/login
实测回显:200
4.3 创建管理员与别名
docker exec anonaddy-1.7.3-app php /var/www/anonaddy/artisan anonaddy:create-user admin admin@qq.com
实测回显:
Created user: "admin" with user_id: "18e53330-d441-434d-a8c1-7031840b28b1"
This user can now reset their password (the default password is their user_id)
把初始密码(user_id)改为演示口令并认证默认收件人:
docker exec -it anonaddy-1.7.3-app php /var/www/anonaddy/artisan tinker
$u = App\Models\Username::where("username","admin")->first()->user;
$u->password = bcrypt("q1w2e3r4"); $u->save();
$r = $u->defaultRecipient; $r->email_verified_at = now(); $r->save();
$a = App\Models\Alias::create([
"id" => (string) Ramsey\Uuid\Uuid::uuid4(),
"user_id" => $u->id, "local_part" => "test1", "extension" => null,
"domain" => "example.com", "email" => "test1@example.com", "active" => true,
"emails_forwarded" => 0, "emails_blocked" => 0, "emails_replied" => 0, "emails_sent" => 0
]);
$a->recipients()->attach($u->defaultRecipient->id);
实测回显:alias created: test1@example.com
4.4 邮件流端到端实测
向栈内 Postfix 投一封外部来信:
docker exec anonaddy-1.7.3-app sh -c 'printf "From: sender@gmail.com\r\nTo: test1@example.com\r\nSubject: compose stack test\r\nMessage-ID: <c001@gmail.com>\r\n\r\nhello compose\r\n" > /tmp/t.eml && sendmail -t < /tmp/t.eml'
sleep 5
docker exec anonaddy-1.7.3-app tail -12 /data/postfix/mail.log
实测回显(核心链路):
Oct 25 10:31:12 mail postfix/qmgr[1124]: 896225A0873: from=<b_on4w2zzzgbuhu5lggf3q_mntdiyzsme3ti@example.com>, size=15431, nrcpt=1 (queue active)
Oct 25 10:31:12 mail postfix/pipe[1157]: 39E965A0DED: to=<b_m5wdq6dina4xc23ynbvq_gyztimbvgrste@example.com>, relay=anonaddy, delay=0.39, ..., status=sent (delivered via anonaddy service)
Oct 25 10:31:12 mail postfix/smtp[1145]: 896225A0873: to=<admin@qq.com>, relay=mx3.qq.com[157.255.4.243]:25, delay=0.34, ..., dsn=5.0.0, status=bounced (host mx3.qq.com[157.255.4.243] said: 550 Mailbox not found. ...)
Oct 25 10:31:13 mail postfix/pipe[1153]: E9B905A0DEF: to=<b_on4w2zzzgbuhu5lggf3q_mntdiyzsme3ti@example.com>, relay=anonaddy, ..., status=sent (delivered via anonaddy service)
链路解读:来信经 anonaddy 管道进应用 → 匹配别名 → 经内置 Postfix 转发到真实 MX(演示邮箱 admin@qq.com 不存在被 550 退信,属预期)→ 退信经 VERP 地址回到管道并入库。生产换成真实收件邮箱即为正常送达。
五、数据持久化说明
| 宿主路径 | 容器路径 | 内容 |
|---|---|---|
/opt/anonaddy/db | /var/lib/mysql | MariaDB 全部数据(用户/别名/失败投递) |
/opt/anonaddy/data | /data | 应用持久层:.env 快照、Postfix 队列与 mail.log、GPG keyring 等 |
升级只需 docker compose pull && docker compose up -d,迁移由镜像启动脚本自动执行;备份直接打包上述两个目录。
六、环境变量表
app 服务关键变量(官方镜像 README + 实测):
| 变量 | 默认值 | 说明 |
|---|---|---|
APP_KEY | 空(必填) | Laravel 加密密钥,base64: 前缀 32 字节 |
APP_URL | — | Web 访问地址,含端口,不带尾斜杠 |
ANONADDY_DOMAIN | 必填 | 主收信域 |
ANONADDY_ALL_DOMAINS | $ANONADDY_DOMAIN | 逗号分隔的附加域 |
ANONADDY_HOSTNAME | 必填 | 本机 FQDN,用于自定义域校验 |
ANONADDY_SECRET | 必填 | 匿名回复哈希用的 64 位随机串 |
ANONADDY_ADMIN_USERNAME | — | 管理员用户名(可在根域收信) |
ANONADDY_ENABLE_REGISTRATION | true | 关闭开放注册设 false |
ANONADDY_LIMIT | 200 | 每用户每小时转发/回复上限 |
ANONADDY_BANDWIDTH_LIMIT | 104857600 | 每用户每月带宽(字节,默认 100MB) |
ANONADDY_NEW_ALIAS_LIMIT | 10 | 每小时新建别名额 |
ANONADDY_DNS_RESOLVER | 127.0.0.1 | 域名校验所用 DNS;容器内建议 127.0.0.11 |
MEMORY_LIMIT | 256M | PHP memory_limit |
UPLOAD_MAX_SIZE | 16M | 上传上限 |
DB_HOST/DB_DATABASE/DB_USERNAME/DB_PASSWORD | — | 对接 db 服务 |
REDIS_HOST | — | 对接 redis 服务 |
POSTFIX_SMTPD_TLS / POSTFIX_SMTP_TLS | false | 收信/发信 TLS 级别(true/may/encrypt…) |
POSTFIX_MESSAGE_SIZE_LIMIT | 26214400 | 单封邮件大小上限(25MB) |
POSTFIX_REJECT_UNKNOWN_REVERSE_CLIENT_HOSTNAME | true | 无 PTR 记录客户端拒收 |
七、配置参数说明
镜像启动时把环境变量渲染为 /var/www/anonaddy/.env 与 Postfix main.cf。注意两点实测结论:
- 队列默认同步:镜像默认
QUEUE_CONNECTION="sync"、CACHE_DRIVER="file",转发在管道进程内同步完成,无需独立 worker;若改用 Redis 队列需自行加 worker 服务。 - TLS 证书:
POSTFIX_SMTPD_TLS=true时需把证书挂进容器并配POSTFIX_SMTPD_TLS_CERT_FILE/POSTFIX_SMTPD_TLS_KEY_FILE。
应用层 .env 全量逐项说明见本专栏《AnonAddy 配置参数详解》。
八、配置文件挂载
需要深度定制时,可在 app 服务追加挂载:
volumes:
- "/opt/anonaddy/data:/data"
- "/opt/anonaddy/main.cf.override:/etc/postfix/main.cf:ro" # 谨慎,覆盖镜像内置配置
日常运维不建议覆盖 Postfix 主配置——镜像的 13-config 脚本已按环境变量生成;定制优先用 POSTFIX_* 变量。
九、等价 docker run
不使用 Compose 时的等价命令(db/redis 略,同 compose 中参数):
docker network create anonaddy-net
docker run -d --name anonaddy-1.7.3-db --network anonaddy-net \
-e MARIADB_RANDOM_ROOT_PASSWORD=yes -e MYSQL_DATABASE=addy \
-e MYSQL_USER=addy -e MYSQL_PASSWORD=q1w2e3r4 \
-v /opt/anonaddy/db:/var/lib/mysql mariadb:12 \
mariadbd --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
docker run -d --name anonaddy-1.7.3-redis --network anonaddy-net redis:8-alpine
docker run -d --name anonaddy-1.7.3-app --network anonaddy-net \
-p 25:25 -p 8000:8000 -v /opt/anonaddy/data:/data \
-e APP_KEY=base64:DSzQlrItKPRFcKRqaTEHAEaU+kZPyvCN+6e2QWgOKnE= \
-e APP_URL=http://app.example.com:8000 \
-e ANONADDY_DOMAIN=example.com -e ANONADDY_HOSTNAME=mail.example.com \
-e ANONADDY_SECRET=322cad02194d3de6144dbdffa35aab2aec46b74595e104cc7d53ebff38ede121 \
-e ANONADDY_ADMIN_USERNAME=admin \
-e DB_HOST=anonaddy-1.7.3-db -e DB_DATABASE=addy -e DB_USERNAME=addy -e DB_PASSWORD=q1w2e3r4 \
-e REDIS_HOST=anonaddy-1.7.3-redis \
anonaddy/anonaddy:1.7.3
十、常用运维命令
docker compose logs -f app # 跟踪应用+postfix 日志
docker compose restart app # 重启应用
docker exec anonaddy-1.7.3-app php /var/www/anonaddy/artisan anonaddy:list-users # 用户列表
docker exec anonaddy-1.7.3-app php /var/www/anonaddy/artisan queue:work --once # 手动排空队列
docker exec anonaddy-1.7.3-app postqueue -p # 查看 Postfix 队列
docker compose pull && docker compose up -d # 升级到最新镜像
十一、常见问题
Q1:app 启动后 8000 拒绝连接?
看 docker logs anonaddy-1.7.3-app:多为 APP_KEY 为空或 db 未就绪。镜像依赖 depends_on 仅保证启动顺序,偶发首启迁移失败时 docker compose restart app 即可。
Q2:创建用户报 The email must be a valid email address.?
收件域需能通过 DNS 查到 MX/A 记录;容器内 ANONADDY_DNS_RESOLVER 建议设为 127.0.0.11(Docker 内嵌 DNS),不要沿用默认 127.0.0.1(镜像内无本地解析器)。
Q3:退信/转发的日志在哪看?
容器内 /data/postfix/mail.log(同时被 tail 到 stdout,即 docker logs 可见);应用失败投递记录在 Web 控制台 Failed Deliveries。
Q4:25 端口被宿主占用?
宿主已有 MTA 时把映射改为 "2525:25" 并同步调整 DNS/防火墙;公网收发务必恢复标准 25。
十二、参考链接
- 官方镜像仓库:https://github.com/anonaddy/docker(compose 示例见 examples/compose)
- 镜像标签:https://hub.docker.com/r/anonaddy/anonaddy/tags
- 应用仓库:https://github.com/anonaddy/anonaddy/releases/tag/v1.7.3