综合 用 BillionMail 自建邮局:两种装法、七个容器,以及上线前必须改掉的默认值

2026-10-19 21:31:21

用 BillionMail 自建邮局:两种装法、七个容器,以及上线前必须改掉的默认值

BillionMail 是自托管的邮件服务器 + 邮件营销 / NewsLetter 平台,用 Go 写,AGPLv3。它把 Postfix、Dovecot、Rspamd、RoundCube 打包在一起,外面套一层发信域名管理、模板和统计界面,可以理解为「自己的 Mailchimp」,但底层就是一台标准 SMTP/IMAP 服务器。

  • 仓库:
  • 官网:
  • 在线 demo:(账号 billionmail / 密码 billionmail)

自建邮局的关键步骤不在于安装,而在于「25 端口能不能出站」「IP 有没有 PTR」「域名记录对不对」。如果这些外部条件不满足,装完之后依然发不出去。因此首要任务是确认外部条件。

装之前先确认的三个外部条件

1. 25 端口出站。 多数云厂商默认封禁 25 端口出站,需要提交工单解封;如果不解封,就改用 587 submission 加中继。检查方式:

nc -vz gmail-smtp-in.l.google.com 25

或者 telnet 到收件方 MX 记录的 25 端口。请求超时就是被封。

2. 发信 IP 的 PTR / rDNS。 反向解析必须指向 mail.example.com 这类主机名,与 Postfix 的 myhostname 一致。这个一般也在云厂商控制台提交工单修改,自己改不了。

3. 域名解析。 除了 A 记录和 MX 记录,还需要 SPF、DKIM、DMARC 三条记录。装好之后用 bm show-record 可以把需要的记录直接打印出来,照抄到 DNS 服务商。

另外,新 IP 没有发信信誉,刚装好就群发基本会进垃圾箱,先小流量养一段时间。

两种安装路径与差异

一键脚本

要求 root,只支持 x86_64 / aarch64,不支持 32 位。

cd /opt && git clone https://github.com/aaPanel/BillionMail && cd BillionMail && bash install.sh

脚本做的事:

  • 检查 25/465/587/110/143/993/995 端口占用;
  • 用 /dev/urandom 生成随机的 ADMIN_USERNAME、ADMIN_PASSWORD(8 位)、SafePath(8 位)、REDISPASS(32 位);DBPASS 生成后写入 DBPASS_file.pl 并 chmod 600;
  • 自动安装 Docker CE;
  • 执行 setenforce 0,并把 /etc/selinux/config 改成 SELINUX=disabled;
  • 在 LXC 容器里会提示可能装不好(对嵌套/非特权环境有要求);
  • 支持 --domain、--TZ 参数。域名只传一级域名时,会自动补成 mail.example.com 作为 Postfix 的 myhostname。

Docker Compose

cd /opt && git clone https://github.com/aaPanel/BillionMail && cd BillionMail && cp env_init .env && docker compose up -d

两条路线的核心差异在口令:一键脚本会随机生成密码,并在安装完成后告诉你登录信息;Compose 路线直接把 env_init 复制成 .env,里面全是写死的默认值,不会自动改。

env_init 的默认值:

ADMIN_USERNAME=billion
ADMIN_PASSWORD=billion
SafePath=billion
DBPASS=NauF7ysRYyt9HTOiOn4JjIAL3QcRZnzj
REDISPASS=zKLnZQr3riFpcS2lEy3MOtfncztaCGKp
BILLIONMAIL_HOSTNAME=mail.example.com
SMTP_PORT=25
SMTPS_PORT=465
SUBMISSION_PORT=587
IMAP_PORT=143
IMAPS_PORT=993
POP_PORT=110
POPS_PORT=995
REDIS_PORT=127.0.0.1:26379
SQL_PORT=127.0.0.1:25432
HTTP_PORT=80
HTTPS_PORT=443
TZ=Etc/UTC
IPV4_NETWORK=172.66.1
FAIL2BAN_INIT=y
IP_WHITELIST_ENABLE=false
RETENTION_DAYS=7

用 Compose 装,up -d 之前先把 ADMIN_PASSWORD、SafePath、DBPASS、REDISPASS、BILLIONMAIL_HOSTNAME 改掉。装完再改就要动数据库和配置了。

容器拓扑

所有服务在 bridge 网络 billionmail-network 上,子网 172.66.1.0/24。

服务镜像端口挂载 / 备注
pgsql-billionmailpostgres:17.4-alpine默认 127.0.0.1:25432 → 5432数据 ./postgresql-data,socket ./postgresql-socket
redis-billionmailredis:7.4.2-alpine127.0.0.1:26379 → 6379entrypoint 走 ./conf/redis/redis-conf.sh,sysctl net.core.somaxconn=4096
rspamd-billionmailbillionmail/rspamd:1.2—依赖 redis,日志 ./logs/rspamd,RETENTION_DAYS 默认 7
dovecot-billionmailbillionmail/dovecot:1.6143 / 993 / 110 / 995挂 vmail-data、ssl,ulimit nofile 20000/40000
postfix-billionmailbillionmail/postfix:1.625 / 465 / 587挂 postfix-data、rspamd-data、ssl
webmail-billionmailroundcube/roundcubemail:1.6.11-fpm-alpine—ROUNDCUBEMAIL_REQUEST_PATH=/roundcube
core-billionmailbillionmail/core:4.9.380 / 443挂 /var/run/docker.sock:ro、.env、conf、logs、vmail-data,cap_add NET_BIND_SERVICE / NET_ADMIN / NET_RAW,FAIL2BAN_INIT=y

日常管理命令:

bm help          # 命令列表
bm default       # 查看登录信息
bm show-record   # 打印域名的 DNS 记录
bm update        # 升级

WebMail 在 /roundcube/ 路径下。

上线后的检查与坑

默认口令。 Compose 路线下 ADMIN_USERNAME=billion / ADMIN_PASSWORD=billion / SafePath=billion,等于管理后台门户大开。SafePath 是后台的隐藏入口路径,默认值意味着别人都知道走哪进去。装完立刻改,用 bm default 确认当前生效的登录信息。

DB 密码写法。 一键脚本把 DBPASS 写进 DBPASS_file.pl 并设成 600 权限,密码不在 .env 明文里;Compose 路线密码就在 .env 里,DBPASS=NauF7ysRYyt9HTOiOn4JjIAL3QcRZnzj 这个值是公开的,不改等于数据库密码全世界都知道——虽然它只监听 127.0.0.1。Redis 的 REDISPASS 同理。

fail2ban。 FAIL2BAN_INIT=y 表示容器启动时会初始化 fail2ban,配合 IP_WHITELIST_ENABLE=false(默认不启用白名单)。自己调试期间如果被反复封 IP,先看这里。

SELinux 被关。 一键脚本会 setenforce 0 并把配置改成 SELINUX=disabled,这是永久性的。宿主机上还跑着别的服务的话,需要自己权衡,脚本不提供保留 SELinux 的选项。

docker.sock。 core-billionmail 挂了 /var/run/docker.sock:ro,虽然是只读,但能读到宿主机 Docker 的控制面信息,能列举容器、镜像、网络。80/443 也是由这个 core 容器直接终结。对外暴露之前想清楚这一点。

数据库与 Redis。 只绑 127.0.0.1,是这套默认配置里比较合理的一处,别为了远程连库改成 0.0.0.0。

许可证。 AGPLv3,改了代码并对外提供服务,需要开源衍生的部分。

什么时候别用

需要企业级投递能力(专用 IP 池、投递信誉托管、退信处理流水线)的场景不适合自己部署这套方案——BillionMail 解决的是「有一个自己的发信平台」,不解决「从零建立发信信誉」。

云厂商不解封 25 端口出站、又不打算配 587 中继的,装完发不出信,只是得到一个能收信的 IMAP 服务器。

宿主机上跑着不能关 SELinux 的业务、或者对 Docker socket 暴露敏感的环境,一键脚本这条路直接排除;Compose 路线也要自己评估 core 容器挂 socket 的代价。

导出订阅者名单、跑大批量营销邮件、又不想承担 IP 被拉黑后的运维成本,这类需求交给第三方 ESP 更省事。

复制全文 生成海报 邮件服务器 自托管 Docker 运维

推荐文章

程序员茄子在线接单