AnonAddy 1.7.3 配置参数详解
逐项详解 AnonAddy 1.7.3 全部 .env 配置参数(含 config/anonaddy.php 实测映射),并给出 SPF/DKIM/DMARC 邮件加固完整方案
AnonAddy 1.7.3 配置参数详解
目标:逐项讲清 AnonAddy(addy.io)v1.7.3 全部配置参数的含义、取值与生效方式,并给出一套可直接照做的 SPF/DKIM/DMARC 邮件加固方案。参数定义以应用内
config/anonaddy.php(v1.7.3 实取)与官方.env.example为准,所有命令回显均在 Ubuntu 22.04 + AnonAddy 1.7.3 真实环境实测。安装过程见《Ubuntu 22.04 安装 AnonAddy 1.7.3 指南》。
一、配置体系总览
AnonAddy 是标准 Laravel 应用,配置分三层:
.env(项目根目录):环境变量源头,部署时唯一需要手工维护的文件。config/*.php:应用代码通过env('KEY', 默认值)读取.env,AnonAddy 自有参数集中在config/anonaddy.php,Laravel 框架参数分布在config/app.php、config/mail.php等。- 配置缓存:生产环境用
php artisan config:cache把全部配置编译进bootstrap/cache/config.php,此后.env改动必须重建缓存才生效。
实测验证:用 Laravel 自带的 config:show 查看 AnonAddy 全部生效配置(截取前 26 行):
$ cd /var/www/anonaddy && php artisan config:show anonaddy
anonaddy ...................................................................
version ............................................................... null
return_path ............................................. mailer@example.com
admin_username ....................................................... admin
non_admin_username_subdomains ..............................................
non_admin_shared_domains ..................................................
enable_registration ................................................... true
domain ......................................................... example.com
hostname .................................................. mail.example.com
dns_resolver ..................................................... 127.0.0.1
blocklist ⇁ allowed_ips ⇁ 0 ...................................... 127.0.0.1
blocklist ⇁ secret .......................... uStu5BoDvDoxGi1AHCfEW3ougDcgty
postfix_log_path ......................................... /var/log/mail.log
all_domains ⇁ 0 ................................................ example.com
secret .... 6671089a52ee47fbe79afb42d72be70f2ace421800d4d08a3e9400027b82ba32
limit .................................................................. 200
bandwidth_limit_enabled ............................................... true
bandwidth_limit .................................................. 104857600
new_alias_hourly_limit ................................................. 100
additional_username_limit ............................................... 10
signing_key_fingerprint ....................................................
gnupg_home .......................................................... .gnupg
dkim_signing_key ...................................................... null
dkim_selector ...................................................... default
auto_verify_new_recipients ........................................... false
use_proxy_authentication ............................................. false
这份输出就是后文逐项详解的对照基准。
二、应用基础参数(APP_*)
| 参数 | 示例值 | 说明 |
|---|---|---|
APP_NAME | addy.io | 应用名称,显示在页面标题与通知邮件中,可改为自己的品牌名 |
APP_ENV | production | 运行环境,生产必须 production(影响错误页与调试行为) |
APP_KEY | base64:DSzQlrIt... | Laravel 加密密钥,用于 Cookie、会话、数据库加密字段。安装时用 php artisan key:generate --force 生成,丢失后所有加密数据不可恢复,务必备份 |
APP_DEBUG | false | 生产必须 false;为 true 时错误页会泄露路径、SQL 与配置 |
APP_LOG_LEVEL | debug | 日志最低级别,生产建议 info 或 warning 减少噪音 |
APP_URL | https://app.example.com | 实例对外 URL,邮件中的链接、Vite 前端构建都依赖它。非标准端口必须带端口号(如 https://example.test:8000),结尾不要带 / |
LOG_CHANNEL | stack | 日志通道,默认写 storage/logs/laravel.log |
注意:APP_URL 不只是展示用——前端资源构建(npm run production)时 Vite 会读取它,改域名后若页面资源 404,需检查 .env 的 APP_URL 并重新构建。
三、数据库与缓存会话参数
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=addy_database
DB_USERNAME=addy
DB_PASSWORD=secret
BROADCAST_DRIVER=log
CACHE_DRIVER=redis
QUEUE_CONNECTION=redis
SESSION_DRIVER=redis
SESSION_LIFETIME=10080
SESSION_SECURE_COOKIE=true
SAME_SITE_COOKIES=lax
REDIS_CLIENT=phpredis
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379
| 参数 | 说明 |
|---|---|
DB_* | MySQL/MariaDB 连接。库、账号在安装篇已建好,密码务必替换为强随机值 |
QUEUE_CONNECTION | 队列驱动。必须 redis:别名转发、退信处理都走队列;若设为 sync 则收信管道内同步处理,高并发下会拖慢 Postfix |
CACHE_DRIVER / SESSION_DRIVER | 缓存与会话存 Redis,多实例部署时必需 |
SESSION_LIFETIME | 会话有效期(分钟),默认 10080 = 7 天 |
SESSION_SECURE_COOKIE | 仅 HTTPS 下回传 Cookie。HTTP 访问时必须改 false,否则登录报 419 Page Expired(实测踩坑,见安装篇排障) |
REDIS_CLIENT | PHP 的 Redis 客户端,推荐 phpredis(C 扩展,性能优于 predis) |
REDIS_PASSWORD | 无密码时保留字面量 null,不要留空 |
四、外发邮件参数(MAIL_*)
MAIL_FROM_NAME=Example
MAIL_FROM_ADDRESS=mailer@example.com
MAIL_DRIVER=smtp
MAIL_HOST=mail.example.com
MAIL_PORT=25
MAIL_ENCRYPTION=tls
MAIL_EHLO_DOMAIN=mail.example.com
MAIL_VERIFY_PEER=true
| 参数 | 说明 |
|---|---|
MAIL_FROM_NAME | 系统通知邮件(注册验证、别名失效提醒等)的发件人显示名 |
MAIL_FROM_ADDRESS | 系统通知邮件的发件地址,建议与 GPG 签名密钥的邮箱一致(见第六章) |
MAIL_HOST / MAIL_PORT | 本机 Postfix,即 127.0.0.1:25 或服务器 FQDN;通知邮件经 Postfix 投递可享受 DKIM 签名与队列重试 |
MAIL_ENCRYPTION | 本机投递用 tls;Postfix 未配 TLS 时改为 null |
MAIL_EHLO_DOMAIN | SMTP EHLO 主机名,必须与服务器 FQDN(ANONADDY_HOSTNAME)一致,否则严格的对端会拒收 |
MAIL_VERIFY_PEER | 校验对端 TLS 证书,本机 Postfix 用自签证书时设 false |
五、AnonAddy 核心参数(ANONADDY_*)
这是别名服务的业务核心,全部映射到 config/anonaddy.php。
5.1 域名与身份
| 参数 | 示例值 | 说明 |
|---|---|---|
ANONADDY_DOMAIN | example.com | 主域名。设置后可在根域收发(@example.com),同时作为别名默认域 |
ANONADDY_ALL_DOMAINS | example.com,example2.com | 全部可用域名的逗号分隔列表,必须包含主域。多域时 Postfix 的 virtual 查询也要覆盖这些域 |
ANONADDY_HOSTNAME | mail.example.com | 服务器 FQDN,用于校验用户自定义域名的 MX 记录是否指向本服务 |
ANONADDY_ADMIN_USERNAME | admin | 管理员用户名。设置后该用户可在根域接收邮件(*@example.com catch-all),普通用户只能用 *@用户名.example.com 子域 |
ANONADDY_DNS_RESOLVER | 127.0.0.1 | 校验自定义域名 DNS 记录时使用的解析器。本机有缓存 DNS(如 bind9)用 127.0.0.1,否则填 1.1.1.1 等公共解析器 |
5.2 安全密钥
| 参数 | 说明 |
|---|---|
ANONADDY_SECRET | 64 位以上随机串,用于匿名回复/发送的哈希计算与 VERP 退信地址校验。泄露意味着任何人可伪造退信回调,生成:openssl rand -hex 32 |
5.3 限额
| 参数 | 默认值 | 说明 |
|---|---|---|
ANONADDY_LIMIT | 200 | 单用户每小时可转发+回复的邮件数上限,防滥用 |
ANONADDY_BANDWIDTH_LIMIT_ENABLED | true | 是否启用月度带宽限额,设 false 关闭执行 |
ANONADDY_BANDWIDTH_LIMIT | 104857600 | 单用户月度带宽上限(字节),默认 100MB。超限后该用户别名暂停转发 |
ANONADDY_NEW_ALIAS_LIMIT | 100 | 单用户每小时可新建别名数 |
ANONADDY_ADDITIONAL_USERNAME_LIMIT | 10 | 单用户可添加的附加用户名(子域)数量上限 |
5.4 行为开关
| 参数 | 默认值 | 说明 |
|---|---|---|
ANONADDY_ENABLE_REGISTRATION | true | 是否开放注册。私有实例设 false,此后只能用 php artisan anonaddy:create-user 建号 |
ANONADDY_NON_ADMIN_USERNAME_SUBDOMAINS | true | 设 false 则禁止非管理员创建用户名子域别名(*@username.example.com) |
ANONADDY_NON_ADMIN_SHARED_DOMAINS | true | 设 false 则禁止非管理员在共享域(根域)创建别名 |
ANONADDY_AUTO_VERIFY_NEW_RECIPIENTS | false | 设 true 则新收件人邮箱免验证(官方 .env.example 未列出,见 config/anonaddy.php),自托管信任内部收件人时可开启 |
ANONADDY_RETURN_PATH | mailer@example.com | 外发邮件的 Return-Path 兜底地址。当别名地址不能作为发件人时(如自定义域未验证发信权限)使用该地址接收退信 |
实测验证——改限额并重建缓存后立刻生效:
$ sed -i 's/^ANONADDY_LIMIT=.*/ANONADDY_LIMIT=500/' .env
$ php artisan config:cache
INFO Configuration cached successfully.
$ echo "var_dump(config(\"anonaddy.limit\"));" | php artisan tinker
int(500)
验证完毕把值改回 200 再跑一次 config:cache 即可。
六、加密与签名参数(GPG / DKIM)
| 参数 | 说明 |
|---|---|
ANONADDY_SIGNING_KEY_FINGERPRINT | 用于给加密转发邮件签名的 GPG 私钥指纹(40 位十六进制)。留空则不签名 |
ANONADDY_GNUPGHOME | GPG 密钥环目录,必须是运行 PHP/队列进程用户(www-data)可读的绝对路径。生产队列 worker 环境里 HOME 常未设置,不要依赖 ~/.gnupg |
ANONADDY_DKIM_SIGNING_KEY | DKIM 私钥文件路径。仅在需要给用户自定义域名代签 DKIM 时才填,主域签名由 Rspamd 完成(见第九章),此处留空即可 |
ANONADDY_DKIM_SELECTOR | 上面私钥对应的 selector,默认 default |
实测验证——以 www-data 身份生成无密码签名密钥(php-gnupg 无法使用带密码的密钥):
$ mkdir -p /var/www/.gnupg && chown www-data:www-data /var/www/.gnupg && chmod 700 /var/www/.gnupg
$ sudo -u www-data GNUPGHOME=/var/www/.gnupg gpg --batch --gen-key <<EOF
%no-protection
Key-Type:1
Key-Length:4096
Subkey-Type:1
Subkey-Length:4096
Name-Real: addy.io mailer
Name-Email: mailer@example.com
Expire-Date:0
EOF
gpg: keybox '/var/www/.gnupg/pubring.kbx' created
gpg: /var/www/.gnupg/trustdb.gpg: trustdb created
gpg: key 217B220E8B0FDF55 marked as ultimately trusted
gpg: directory '/var/www/.gnupg/openpgp-revocs.d' created
gpg: revocation certificate stored as '/var/www/.gnupg/openpgp-revocs.d/C6D5589A4F30EF1762F34BCD217B220E8B0FDF55.rev'
查看指纹:
$ sudo -u www-data GNUPGHOME=/var/www/.gnupg gpg -k
/var/www/.gnupg/pubring.kbx
---------------------------
pub rsa4096 2026-10-25 [SCEA]
C6D5589A4F30EF1762F34BCD217B220E8B0FDF55
uid [ultimate] addy.io mailer <mailer@example.com>
sub rsa4096 2026-10-25 [SEA]
把 C6D5589A4F30EF1762F34BCD217B220E8B0FDF55 填入 ANONADDY_SIGNING_KEY_FINGERPRINT,ANONADDY_GNUPGHOME=/var/www/.gnupg,然后 php artisan config:cache 生效。注意 Name-Email 建议与 MAIL_FROM_ADDRESS 一致,签名身份才与发件人吻合。
七、反代认证与 Blocklist API
7.1 反向代理自动登录(慎用)
ANONADDY_USE_PROXY_AUTHENTICATION=false
ANONADDY_PROXY_AUTHENTICATION_USER_ID_HEADER=X-User
ANONADDY_PROXY_AUTHENTICATION_NAME_HEADER=X-Name
ANONADDY_PROXY_AUTHENTICATION_EMAIL_HEADER=X-Email
开启后,应用信任反向代理(OAuth2-Proxy、Authentik 等)注入的请求头并自动登录/注册。只有在流量必然经过可信代理时才能开启,否则任何人伪造 X-User 头即可登录任意账号。
7.2 Blocklist API(配合 Rspamd 用户黑名单)
BLOCKLIST_API_ALLOWED_IPS=127.0.0.1
BLOCKLIST_API_SECRET=uStu5BoDvDoxGi1AHCfEW3ougDcgty
| 参数 | 说明 |
|---|---|
BLOCKLIST_API_ALLOWED_IPS | 允许调用 /api/blocklist-check 的 IP 逗号列表,填 Rspamd 所在邮件服务器的实际 IP |
BLOCKLIST_API_SECRET | 可选共享密钥;设置后必须与 Rspamd Lua 脚本(/etc/rspamd/lua.local.d/addy_blocklist.lua)中的 blocklist_secret 一致 |
7.3 Postfix 日志路径
POSTFIX_LOG_PATH 默认 /var/log/mail.log,用于解析入站拒信记录。日志路径非默认时才需设置。
八、词表与黑名单参数
随机生成的别名(如 red.panda123@...)来自内置词表,保留用户名来自黑名单。config/anonaddy.php 通过统一的 $resolveList 机制加载:值为空则用默认词表文件;值为逗号分隔字符串则直接作为列表;值为路径(绝对或相对项目根目录的 .php 文件)则加载该文件返回的数组。
| 参数 | 默认文件 | 用途 |
|---|---|---|
ANONADDY_BLACKLIST | config/lists/blacklist.php | 禁止注册的用户名(含 HTTP 状态码、保留名等) |
ANONADDY_WORDLIST | config/lists/wordlist.php | 随机别名单词表 |
ANONADDY_ADJECTIVES / ANONADDY_NOUNS | 同名默认文件 | 别名生成的形容词/名词表 |
ANONADDY_MALE_FIRST_NAMES / ANONADDY_FEMALE_FIRST_NAMES / ANONADDY_SURNAMES | 同名默认文件 | 人名风格别名生成 |
例如 .env 中写 ANONADDY_BLACKLIST=reserved,admin,root 即追加自定义保留名。
九、SPF/DKIM/DMARC 邮件加固
别名转发服务的投递信誉完全取决于这三套记录。未配置时,转发的邮件在 Gmail/QQ 邮箱大概率进垃圾箱甚至被拒收。先看一个生产级参照——官方托管服务 addy.io 的真实记录(2026-10-25 实测):
$ dig +short TXT addy.io
"v=spf1 ip4:213.108.105.57 ip4:185.70.196.149 ip4:94.237.47.233 ip6:2a00:c6c0:0:108:3::10 ip6:2a04:3544:8000:1000:e8b5:6ff:fe29:56c ip6:2a04:3544:1000:1510:e8b5:6ff:fe29:1d32 -all"
$ dig +short TXT _dmarc.addy.io
"v=DMARC1; p=reject; pct=100; rua=mailto:dmarc@notifications.uriports.com; ruf=mailto:dmarc@notifications.uriports.com; sp=reject; aspf=r; fo=1:d:s"
$ dig +short TXT default._domainkey.addy.io
"v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3zaLO8stjapEtX5FcAwYi69Hlt53DOF89+KjCjsoutvB/+KcoWdr1X1PEFECkO01UaCSH/O3ReXn7CKSLmUCuNWN1vJWeut/EbTq+M6j9W7HS/CLv4SxF+y0PtWBSgLxZiIHDwVxhd9y9ahWT/AUTlg9C7wxx0ZLsf7UmFT5pEUOVpsUMXbebIA3P9S9RbBNk" "9t4y26QoFAn6kOwqwAaBKfum0MzF/WRdb4HamIRjbBlKmy58skxAQYePpLSl75Nq5WmDArE03zFkknIgdGXnfR0RrgCRpEbTXrHeRMpa5O49FcABUWF9ALEQzSalVOaMaSddLLe4qX0gEt5Iix99wIDAQAB"
注意官方用的是最严格的 -all 与 p=reject,DKIM 为 2048 位 RSA。下面按官方 SELF-HOSTING 指南的路径自建同等配置。
9.1 SPF 记录
在域名 DNS 添加 TXT 记录,授权 MX 主机发信:
TXT @ "v=spf1 mx ~all"
TXT * "v=spf1 mx ~all"
第二条通配记录覆盖所有用户名子域(username.example.com),别名地址在这些子域下,不可省略。运行稳定后建议把 ~all(软拒绝)收紧为 -all(硬拒绝),与官方一致。
9.2 DKIM:Rspamd 签名
安装 Rspamd 后生成 2048 位密钥对。实测验证:
$ mkdir /var/lib/rspamd/dkim
$ rspamadm dkim_keygen -s 'default' -b 2048 -d example.com -k /var/lib/rspamd/dkim/example.com.default.key | tee -a /var/lib/rspamd/dkim/example.com.default.pub
default._domainkey IN TXT ( "v=DKIM1; k=rsa; "
"p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw5ZTN7f2lE+ghPcVZzml34RVPvJBJ1xZ330qYgc2QiJIKixJAtVTDaBoWkch7KMX7/zJDqhOxkVP84iIJ3Da8eZEU6331u6/OXb1ojx0/RkFmGatmFEZhD3ckh4PYkaZuCDbowLHSpIJdT3KHvaMKCsNIZQ9lOFj2ANvPl/trjNga+7Iqj+J31ScNDXR/Q/YouLdrx2945+3xVOrr"
"3yXXUlB6Q5q6FGjMIwpEkjEP/o+g1pJQVoxea+0FtsNbd5/slfP9CHMHybAQcC8JU9b51+/LD4qpz4AsSwfRoHHn5hMbAeQNfox6whw4LSwCaqu7vpFRZHqNxG7AMETWHqK2QIDAQAB"
) ;
$ chown -R _rspamd: /var/lib/rspamd/dkim
$ chmod 750 /var/lib/rspamd/dkim
$ chmod 440 /var/lib/rspamd/dkim/example.com.default.key /var/lib/rspamd/dkim/example.com.default.pub
把公钥内容(括号内拼接、去掉多余引号与空白)发布为 DNS TXT 记录:主机名 default._domainkey,值形如 "v=DKIM1; k=rsa; p=MIIBIjANBgkq..."。
配置 Rspamd 签名表 /etc/rspamd/local.d/dkim_signing.conf(覆盖根域与全部子域):
signing_table = [
"*@example.com example.com",
"*@*.example.com example.com",
];
key_table = [
"example.com example.com:default:/var/lib/rspamd/dkim/example.com.default.key",
];
use_domain = "envelope";
allow_hdrfrom_mismatch = true;
allow_hdrfrom_mismatch_sign_networks = true;
allow_username_mismatch = true;
use_esld = true;
sign_authenticated = false;
ARC(Authenticated Received Chain)签名复用同配置,转发场景下可让下游服务器信任原始认证结果:
$ cp /etc/rspamd/local.d/dkim_signing.conf /etc/rspamd/local.d/arc.conf
若还要给用户自定义域名代签 DKIM,才需要在
.env填ANONADDY_DKIM_SIGNING_KEY=/var/lib/rspamd/dkim/example.com.default.key,并把运行 PHP 的用户加入_rspamd组、给私钥加组读权限(usermod -a -G _rspamd www-data && chmod g+r .../example.com.default.key)。主域签名由 Rspamd 完成,无需该参数。
9.3 DMARC 记录与入站处置
发布 DMARC 记录(初期 p=none 只监控,确认 SPF/DKIM 全部正常后再收紧到 quarantine/reject):
TXT _dmarc "v=DMARC1; p=none; sp=none; adkim=r; aspf=r; pct=100;"
入站方向,让 Rspamd 按对方域的 DMARC 策略处置来信,创建 /etc/rspamd/local.d/dmarc.conf:
actions = {
quarantine = "add_header";
reject = "reject";
}
含义:来信 DMARC 校验失败且对方策略为 p=quarantine 时加标记头,策略为 p=reject 时直接拒收。配合 /etc/rspamd/local.d/milter_headers.conf 可给通过校验的邮件添加 Authentication-Results 头,应用侧据此允许别名回复/发送,防止伪造收件人地址(完整配置见官方 SELF-HOSTING 指南)。
改完重启 Rspamd:systemctl restart rspamd。
验证清单(发布 DNS 后逐条执行):
dig +short TXT example.com # 应返回 v=spf1 ...
dig +short TXT default._domainkey.example.com # 应返回 v=DKIM1 ...
dig +short TXT _dmarc.example.com # 应返回 v=DMARC1 ...
再向别名发一封外部邮件,在真实收件箱查看原文,确认 Authentication-Results 中 spf=pass、dkim=pass、dmarc=pass 三项齐全。
十、配置修改与生效
标准变更流程:
$ nano /var/www/anonaddy/.env # 1. 修改参数
$ cd /var/www/anonaddy
$ php artisan config:cache # 2. 重建配置缓存(queue worker 会读取新配置)
$ systemctl restart anonaddy-worker # 3. 重启队列 worker(Supervisor 管理的单元名以实际为准)
$ systemctl reload php8.3-fpm nginx # 4. 重载 Web 层
常见问题:
- 改了
.env不生效:九成是忘了config:cache。生产环境配置走缓存,.env只在构建缓存时读取。 config:cache后页面报错:检查.env是否有未加引号的特殊字符值(含空格、#、$的值要用双引号包起来)。- 排查当前生效值:
php artisan config:show anonaddy或echo "var_dump(config('anonaddy.limit'));" | php artisan tinker,看到的才是应用真正使用的值。 - 回滚:直接改回
.env再config:cache即可,缓存文件bootstrap/cache/config.php也可直接删除后重建。
十一、参考链接
- 官方 .env.example(v1.7.3):https://github.com/anonaddy/anonaddy/blob/v1.7.3/.env.example
- 官方自托管指南(Rspamd/DKIM/DMARC 章节):https://github.com/anonaddy/anonaddy/blob/master/SELF-HOSTING.md
- Rspamd DKIM 签名模块文档:https://rspamd.com/doc/modules/dkim_signing.html
- Laravel 13 配置文档:https://laravel.com/docs/13.x/configuration