【Mail Server 系列文:第 4 篇】
在本系列的前幾篇中,我們完成了:
- Mail Server 架構介紹(第 1 篇)
- 基礎網路 / DNS 與 SSL 憑證(第 2 篇)
- MariaDB + PostfixAdmin 虛擬網域帳號管理(第 3 篇)
本篇開始正式介紹整個郵件系統的「引擎」:
🚀 1. 為什麼 Postfix 需要自行編譯?
官方沒有提供 Postfix Docker image,而 apt 安裝的版本通常:
- 過舊(Ubuntu 24.04 只有 3.7.x)
- 缺功能(例如缺 MySQL、缺 LMDB、多網域 SNI 不完整)
- 缺 libpcre2(Regex 最新功能無法使用)
- 不易在 Docker 中客製 tuning
👉 因此本篇採用 Postfix 官方原始碼自行編譯出 Postfix 3.10.4,並包成 Docker image。
功能包括:
✔ MySQL maps
✔ LMDB(tls_sni)
✔ PCRE2
✔ SASL (Cyrus)
✔ TLS / SNI
✔ 支援 PostfixAdmin 架構
✔ 支援 Amavis(Virus + Spam 入口)
✔ 支援 Piler Milter(X-Envelope-To)
🧱 2. 建立 Postfix Docker Image(Builder + Runtime 兩階段建置)
Postfix 採用 multi-stage build:
- builder:編譯 Postfix(含 MySQL/LMDB/PCRE2)
- runtime:僅保留執行所需檔案,image 更乾淨
建議目錄:
/opt/docker/mail/postfix/
建立 Dockerfile(此為精華版,完整配置請見實作):
FROM ubuntu:24.04 AS builder
RUN apt-get update && apt-get install -y \
build-essential libssl-dev libsasl2-dev libmariadb-dev \
liblmdb-dev libpcre2-dev ...
# 下載並解壓縮 Postfix 3.10 原始碼
WORKDIR /usr/src
RUN curl -LO https://archive.postfix.org/official/postfix-3.10.4.tar.gz
RUN tar xzf postfix-3.10.4.tar.gz
WORKDIR /usr/src/postfix-3.10.4
RUN make -f Makefile.init makefiles \
CCARGS="-DUSE_TLS -DUSE_SASL_AUTH -DHAS_MYSQL -DHAS_LMDB -DHAS_PCRE2 ..." \
AUXLIBS="-lssl -lcrypto -lsasl2 -lpcre2-8" \
AUXLIBS_MYSQL="$(pkg-config --libs libmariadb)"
RUN sh postfix-install -non-interactive -package ...
Runtime stage:
FROM ubuntu:24.04
RUN apt-get update && apt-get install -y \
libssl3 libsasl2-2 libmariadb3 liblmdb0 libpcre2-8-0 ...
COPY --from=builder /tmp/postfix-stage/ /
ENTRYPOINT ["/usr/local/sbin/docker-entrypoint.sh"]
🧩 Docker image 內建 LMDB 支援 → 可使用 postmap -F lmdb:xxx
🧩 支援 SNI + MySQL 全功能
這讓你的郵件系統具備完整可擴展性。
🐳 3. 啟動 Postfix 容器(SMTP 25 + Submission 587)
啟動腳本:
docker run -dit --name postfix \
--restart=always \
--network intranet-net \
-p 25:25 -p 587:587 \
-e TZ=Asia/Taipei \
-v $PWD/config:/etc/postfix \
-v $PWD/log:/var/log/postfix \
-v /opt/docker/wwwapp/data/etc-letsencrypt:/etc/letsencrypt \
nuface/postfix-3.10.4:1.0
你會注意到:
✔ 沒有 465(SMTPS)→ 可選
✔ 25:收外部 email
✔ 587:供內部使用者(Outlook / Thunderbird)提交郵件
🗃 4. main.cf:完整設定解析
完整檔案很長,這裡整理其功能邏輯:
4.1 基本設定
myhostname = it.demo.tw
myorigin = $myhostname
mydestination = $myhostname, localhost
inet_interfaces = all
mydestination 千萬不能加上虛擬網域
❌ it.demo.tw
❌ nuface.tw
否則所有信件會變成本機投遞 → 直接壞掉。
4.2 TLS / SNI 設定
使用 Let’s Encrypt:
smtpd_tls_chain_files =
/etc/letsencrypt/live/it.demo.tw/privkey.pem,
/etc/letsencrypt/live/it.demo.tw/fullchain.pem
SNI 需要 LMDB:
smtpd_tls_server_sni_maps = lmdb:/etc/postfix/tls_sni
多網域例子:
it.demo.tw /etc/letsencrypt/live/it.demo.tw/privkey.pem /fullchain.pem
nuface.tw /etc/letsencrypt/live/nuface.tw/privkey.pem /fullchain.pem
4.3 SASL(使用 Dovecot)
smtpd_sasl_type = dovecot
smtpd_sasl_path = inet:dovecot:12345
smtpd_sasl_auth_enable = yes
允許使用 Roundcube / Thunderbird 認證。
4.4 使用 MariaDB map 讀取虛擬帳號
virtual_mailbox_domains = mysql:/etc/postfix/sql/virtual_domains.cf
virtual_mailbox_maps = mysql:/etc/postfix/sql/virtual_mailboxes.cf
virtual_alias_maps = mysql:/etc/postfix/sql/virtual_aliases.cf ...
這些 SQL 查詢與 PostfixAdmin 所寫入的資料表完全相容。
4.5 信件投遞交給 Dovecot LMTP
virtual_transport = lmtp:inet:dovecot:24
比 IMAP/POP 傳統投遞更安全且支援 quota → 非常建議。
4.6 Milter(給 piler-milter 使用)
milter_default_action = accept
milter_protocol = 6
smtpd_milters = inet:pilermilter:33333
non_smtpd_milters = inet:pilermilter:33333
作用:
→ 將 Envelope RCPT 轉成標頭
→ Piler 可以依使用者權限瀏覽信件
🛠 5. master.cf:收發信處理流程
本篇最重要部分之一。
5.1 入站流程(25 port)
25 port:
smtp → content_filter = smtp-amavis:[amavis]:10024
送進 Amavis(反垃圾 + 防毒)。
5.2 Amavis 回投 Postfix(10025)
設為簡化模式:
- 不驗證 sender、recipient
- 不執行 anti-spam policy
- 不重複過濾
- 不重新 DKIM
- 只進行投遞
5.3 外送郵件(10027)
Outbound flow:
- Postfix Submission(587)
- Amavis(簽 DKIM)
- 回投 Postfix → 10027 → Internet
5.4 Submission(587)
smtpd_tls_security_level=encrypt
smtpd_sasl_auth_enable=yes
milter_macro_daemon_name=ORIGINATING
→ 需登入
→ 強制 TLS
→ 正確記錄 SASL identity
🔄 6. transport_maps:放行到 Piler
archive.local smtp:[172.18.0.1]:2525
將所有副本(always_bcc)送入 Piler 存檔。
搭配:
always_bcc = piler@archive.local
📦 7. SQL maps:與 PostfixAdmin 對接
你建立了:
- virtual_domains.cf
- virtual_mailboxes.cf
- virtual_aliases.cf
- relay_domains.cf
- sender_login_maps.cf
所有查詢指向:
maildb → postfix 資料庫
PostfixAdmin 寫入 → Postfix 讀出 → Dovecot 投遞
形成一個完整一致的架構。
🧪 8. 測試建議
以下為完整測試清單:
✔ 8.1 確認 Postfix 啟動
docker logs postfix
postconf mail_version
✔ 8.2 測試 SNI
openssl s_client -connect mail.it.demo.tw:25 -starttls smtp -servername it.demo.tw
✔ 8.3 測試 MySQL maps
postmap -q [email protected] mysql:/etc/postfix/sql/virtual_mailboxes.cf
✔ 8.4 測試投遞到 Dovecot
sendmail [email protected]
✔ 8.5 測試 Submission(587)
使用 Thunderbird / Outlook
或:
openssl s_client -connect it.demo.tw:587 -starttls smtp
✔ 8.6 測試 Milter(Piler)
收信後 headers 應該有:
X-Envelope-From:
X-Envelope-To:
🏁 9. 結語:SMTP Pipeline 進入整合階段
本系列第 4 篇介紹了:
- Postfix 為何需要自行編譯(Docker 最佳模式)
- MySQL、LMDB、PCRE2、SNI 的技術價值
- 與 Amavis、Dovecot、Piler 的整合
- Submission(587)正確設計方式
- Milter + 內容過濾完整流程
到這一步,你的 Mail Server 已經具備:
✔ 多網域
✔ 虛擬帳號
✔ TLS / SNI
✔ SPF / DKIM / DMARC-ready
✔ 垃圾郵件防護
✔ 病毒掃描
✔ 全信件歸檔(Piler)
整個 SMTP Pipeline 已完全成形。
▶ 下一篇預告(第 5 篇)
Dovecot:IMAP / POP3 / LMTP / Sieve / Spam Learning 全攻略(含 Docker 自建)
內容將包含:
- Dovecot SQL 認證
- 多網域 SNI
- Quota(含 quota-warning)
- LMTP 交互運作
- Sieve + SpamAssassin 線上學習(ham/spam)
- TLS / 設備認證
- Roundcube 整合