AnonAddy 1.7.3 Docker Compose 部署指南

用 Docker Compose 编排 AnonAddy 1.7.3 全家桶(app + MariaDB + Redis),跑通 Web 控制台与完整别名邮件流

AnonAddyAnonAddy邮件别名DockerDocker Compose2026/10/25

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/mysqlMariaDB 全部数据(用户/别名/失败投递)
/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_REGISTRATIONtrue关闭开放注册设 false
ANONADDY_LIMIT200每用户每小时转发/回复上限
ANONADDY_BANDWIDTH_LIMIT104857600每用户每月带宽(字节,默认 100MB)
ANONADDY_NEW_ALIAS_LIMIT10每小时新建别名额
ANONADDY_DNS_RESOLVER127.0.0.1域名校验所用 DNS;容器内建议 127.0.0.11
MEMORY_LIMIT256MPHP memory_limit
UPLOAD_MAX_SIZE16M上传上限
DB_HOST/DB_DATABASE/DB_USERNAME/DB_PASSWORD—对接 db 服务
REDIS_HOST—对接 redis 服务
POSTFIX_SMTPD_TLS / POSTFIX_SMTP_TLSfalse收信/发信 TLS 级别(true/may/encrypt…)
POSTFIX_MESSAGE_SIZE_LIMIT26214400单封邮件大小上限(25MB)
POSTFIX_REJECT_UNKNOWN_REVERSE_CLIENT_HOSTNAMEtrue无 PTR 记录客户端拒收

七、配置参数说明

镜像启动时把环境变量渲染为 /var/www/anonaddy/.env 与 Postfix main.cf。注意两点实测结论:

  1. 队列默认同步:镜像默认 QUEUE_CONNECTION="sync"、CACHE_DRIVER="file",转发在管道进程内同步完成,无需独立 worker;若改用 Redis 队列需自行加 worker 服务。
  2. 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。

十二、参考链接