Skip to content

antony@notes:~/container$ cat "Docker-Mail-Server-完整部署指南.md"

Docker Mail Server 完整部署指南

2026-03-31· container

Docker Mail Server 完整部署指南

前置條件

開始部署前,請確認以下環境條件皆已滿足。

基礎架構

項目需求說明
DNS Server必須內網需有可控的 DNS Server(如 BIND),用於新增 MX / SPF / DKIM / DMARC 等 TXT Record。本文以 nsupdate 動態更新為例
DNS MX Record必須域名的 MX 記錄需指向 Mail Server(例如 kubeantony.com. MX 10 mx1.kubeantony.com.
DNS A Record必須Mail Server 主機名需有對應的 A 記錄(例如 mx1.kubeantony.com. A 192.168.11.3
固定 IP建議Mail Server 應使用固定 IP,避免 DNS 記錄失效

Mail Server 主機

項目需求說明
作業系統Linux(Debian/Ubuntu/RHEL/Rocky 等)需支援 Podman 4.4+
Podman4.4 以上需支援 Quadlet(.kube 單元檔)。確認版本:podman --version
Git必須用於下載 mkcert 憑證工具
OpenSSL必須用於產生自簽憑證及驗證 TLS。確認版本:openssl version
systemd必須Quadlet 依賴 systemd generator 產生 service

網路 Port

Mail Server 需開放以下 Port(使用 hostNetwork 模式會直接綁定主機 Port):

Port協定服務說明
25TCPSMTP接收外部郵件
465TCPSMTPSSMTP over TLS(隱式 TLS)
587TCPSubmissionSMTP 寄信(STARTTLS + 認證)
993TCPIMAPSIMAP over TLS(收信)
995TCPPOP3SPOP3 over TLS(收信)
11334TCPRspamd Web UIRspamd 管理介面(HTTP)

測試機器

項目需求說明
同網段的其他機器必須測試寄信步驟需在內網其他機器執行(不是 Mail Server 本機)
s-nail 或 msmtp建議用於 SMTP 寄信測試。步驟十一會說明安裝方式
dig建議用於驗證 DNS Record。安裝:apt install dnsutilsapk add bind-tools

快速檢查腳本

在 Mail Server 主機上執行,一次確認所有前置條件:

cat << 'SCRIPT' | sudo tee /usr/local/bin/check-mail-prereqs.sh
#!/bin/bash
# Mail Server 前置條件檢查腳本
# 用法:bash check-mail-prereqs.sh <DNS_IP>

DNS_IP="${1:?用法: bash $0 <DNS_IP>}"

R='\033[31m'
G='\033[32m'
N='\033[0m'
P=0
F=0

c(){
  local label="$1"
  local cmd="$2"
  if eval "$cmd" >/dev/null 2>&1; then
    echo -e "  [${G}PASS${N}] ${label}"
    ((P++))
  else
    echo -e "  [${R}FAIL${N}] ${label}"
    ((F++))
  fi
}

# 檢查 Port 是否被非 mail 服務佔用
# 排除 master (Postfix)、dovecot、rspamd — Container 內的 mail 服務屬正常
check_port(){
  local port="$1"
  ! ss -tlnp 2>/dev/null | grep -E ":${port}\b" | grep -Eqv 'master|dovecot|rspamd'
}

echo "===== Mail Server 前置條件檢查 ====="

PODMAN_MAJOR=$(podman --version 2>/dev/null | awk '{print $3}' | cut -d. -f1)
c "Podman >= 4.4"              "test ${PODMAN_MAJOR:-0} -ge 4"
c "Quadlet generator"          "test -f /usr/libexec/podman/quadlet"
c "OpenSSL"                    "openssl version"
c "Git"                        "git --version"
c "systemd"                    "systemctl is-system-running | grep -qE 'running|degraded'"
c "Port 25 未被其他服務佔用"    "check_port 25"
c "Port 465 未被其他服務佔用"   "check_port 465"
c "Port 587 未被其他服務佔用"   "check_port 587"
c "Port 993 未被其他服務佔用"   "check_port 993"
c "Port 995 未被其他服務佔用"   "check_port 995"
c "Port 11334 未被其他服務佔用" "check_port 11334"
c "DNS Server ${DNS_IP}"       "dig @${DNS_IP} google.com +short +time=3"

echo "===== ${P} 通過 / ${F} 失敗 ====="
SCRIPT

sudo chmod +x /usr/local/bin/check-mail-prereqs.sh

執行檢查(帶入 DNS Server IP):

sudo bash /usr/local/bin/check-mail-prereqs.sh 192.168.11.2  # ← 根據環境修改

注意: Port 檢查會排除 Postfix(master)、Dovecot、Rspamd,因為使用 hostNetwork 模式時 Container 內的服務會直接綁定主機 Port,這是正常的。檢查目的是確認沒有其他非 Mail Server 的服務佔用這些 Port。 如果 Mail Server 尚未啟動,所有 Port 檢查應顯示 PASS。

環境變數速查表

後續每個步驟的開頭都會列出該步驟所需的環境變數,請根據你的環境修改後再執行。

變數範例值說明
DNkubeantony.com郵件域名
MAIL_HOSTmx1郵件主機名稱前綴
MAIL_FQDNmx1.kubeantony.com郵件主機 FQDN
MAIL_IP192.168.11.3Mail Server IP
DNS_IP192.168.11.2內網 DNS Server IP
MY_NETWORKS127.0.0.0/8,192.168.11.0/24允許 relay 的網段
NET_IFens18Mail Server 網路介面名稱
POSTMASTERbigredPostmaster 帳號名稱
RSPAMD_PW$2$zmnrfh...Rspamd Web UI 密碼 hash

一、建立 Container Image

# ===== 根據環境修改 =====
export DN="kubeantony.com"                # 郵件域名

1.1 建立 Dockerfile

sudo mkdir -p /opt/zfs/images/dkmail-rspamd

cat << 'EOF' | sudo tee /opt/zfs/images/dkmail-rspamd/Dockerfile
FROM docker.io/mailserver/docker-mailserver
ARG DN=""
ENV OVERRIDE_HOSTNAME="mx1.${DN}" \
    DMS_DEBUG="1" \
    POSTMASTER_ADDRESS="bigred@${DN}" \
    ENABLE_RSPAMD="1" \
    ENABLE_OPENDKIM="0" \
    ENABLE_OPENDMARC="0" \
    ENABLE_POLICYD_SPF="0" \
    ENABLE_AMAVIS="0" \
    ENABLE_SPAMASSASSIN="0" \
    ENABLE_IMAP="1" \
    ENABLE_POP3="1"
RUN apt-get update && apt-get install -y net-tools curl wget nano && \
    setup email add bigred@${DN} bigred && \
    setup email add rbean@${DN} rbean && \
    setup email add gbean@${DN} gbean && \
    touch /tmp/docker-mailserver/postfix-main.cf
EOF

1.2 Build 映像檔

sudo podman build \
  --build-arg DN="${DN}" \
  --format docker \
  --no-cache \
  -t dkmail.rspamd \
  /opt/zfs/images/dkmail-rspamd/

1.3 標記映像檔(Kubernetes YAML 需要 localhost 前綴)

sudo podman tag dkmail.rspamd localhost/dkmail.rspamd:latest

二、產生自簽 TLS 憑證

# ===== 根據環境修改 =====
export DN="kubeantony.com"                # 郵件域名
export MAIL_HOST="mx1"                    # 郵件主機名稱前綴
export MAIL_FQDN="${MAIL_HOST}.${DN}"     # 郵件主機 FQDN(自動組合)

2.1 下載 mkcert 工具

cd /opt
sudo git clone https://github.com/braveantony/mkcert.git
sudo chmod +x /opt/mkcert/certctl

2.2 編輯設定檔

cat << EOF | sudo tee /opt/mkcert/config
# CA 相關設定
CA_KEY="ca.key"
CA_CRT="ca.crt"
CA_DAYS=3650
CA_SUBJ="/C=TW/ST=Taipei/L=Taipei/O=${DN}/OU=Mail/CN=${DN} Root CA"

# Server 相關設定
DOMAIN_NAME="${DN}"
SERVER_KEY="\${DOMAIN_NAME}.key"
SERVER_CSR="\${DOMAIN_NAME}.csr"
SERVER_CRT="\${DOMAIN_NAME}.crt"
SERVER_DAYS=3650
SERVER_SUBJ="/C=TW/ST=Taipei/L=Taipei/O=${DN}/OU=Mail/CN=${MAIL_FQDN}"
V3_EXT="v3.ext"

ALT_NAMES=(
  "DNS.1=*.\${DOMAIN_NAME}"
  "DNS.2=\${DOMAIN_NAME}"
  "DNS.3=${MAIL_FQDN}"
)
EOF

2.3 產生憑證

sudo /opt/mkcert/certctl

2.4 確認產生結果

ls -l /opt/mkcert/${DN}/

預期輸出:

ca.crt              # CA 根憑證
ca.key              # CA 私鑰
<DN>.crt            # 伺服器憑證
<DN>.key            # 伺服器私鑰

三、部署 TLS 憑證與設定檔

# ===== 根據環境修改 =====
export DN="kubeantony.com"                # 郵件域名
export MY_NETWORKS="127.0.0.0/8,192.168.11.0/24"  # 允許 relay 的網段
export RSPAMD_PW='$2$zmnrfhkhbr9sb411b8eykyxgs1do4jeg$3fjncbo78qfsymbzu7nhfi35inhwezqh313trc7if4ie3d6sj1fy'  # Rspamd Web UI 密碼 hash

3.1 建立目錄結構

sudo mkdir -p \
  /opt/zfs/dkmail/data \
  /opt/zfs/dkmail/conf/ssl \
  /opt/zfs/dkmail/conf/rspamd/override.d

3.2 複製憑證

sudo cp /opt/mkcert/${DN}/${DN}.key /opt/zfs/dkmail/conf/ssl/

sudo bash -c "cat \
  /opt/mkcert/${DN}/${DN}.crt \
  /opt/mkcert/${DN}/ca.crt \
  > /opt/zfs/dkmail/conf/ssl/fullchain.pem"

sudo chmod 644 /opt/zfs/dkmail/conf/ssl/fullchain.pem
sudo chmod 600 /opt/zfs/dkmail/conf/ssl/${DN}.key

3.3 Rspamd 設定

cat << 'EOF' | sudo tee /opt/zfs/dkmail/conf/rspamd/override.d/options.inc
local_networks = ["127.0.0.1/8"];
EOF

cat << EOF | sudo tee /opt/zfs/dkmail/conf/rspamd/override.d/worker-controller.inc
password = ${RSPAMD_PW}
EOF

cat << 'EOF' | sudo tee /opt/zfs/dkmail/conf/rspamd/override.d/hfilter.conf
enabled = false;
EOF

3.4 Postfix 額外設定

重要: docker-mailserver 透過 SSL_TYPE=manual 環境變數會自動設定 Postfix TLS(smtpd_tls_chain_files)、 Dovecot TLS、以及 SASL 認證 socket。postfix-main.cf 只需放 docker-mailserver 沒有自動處理的額外設定, 不可手動設定 smtpd_tls_cert_file / smtpd_tls_key_file,否則會與 smtpd_tls_chain_files 衝突。

cat << EOF | sudo tee /opt/zfs/dkmail/conf/postfix-main.cf
# Relay 設定(允許內網寄信)
mynetworks = ${MY_NETWORKS}

# 寄出郵件啟用 TLS
smtp_tls_security_level = may
smtp_tls_protocols = !SSLv2,!SSLv3,!TLSv1,!TLSv1.1
EOF

四、建立 Kubernetes YAML

# ===== 根據環境修改 =====
export DN="kubeantony.com"                # 郵件域名
export MAIL_HOST="mx1"                    # 郵件主機名稱前綴
export MAIL_FQDN="${MAIL_HOST}.${DN}"     # 郵件主機 FQDN(自動組合)
export DNS_IP="192.168.11.2"            # 內網 DNS Server IP
export NET_IF="ens18"                     # Mail Server 網路介面名稱
cat << EOF | sudo tee /etc/containers/systemd/dkmail.yaml
apiVersion: v1
kind: Pod
metadata:
  name: dkmail
  labels:
    app: dkmail
spec:
  hostname: ${MAIL_FQDN}
  hostNetwork: true
  dnsConfig:
    nameservers:
      - ${DNS_IP}
    searches:
      - ${DN}
  containers:
    - name: dkmail
      image: localhost/dkmail.rspamd:latest
      env:
        - name: NETWORK_INTERFACE
          value: "${NET_IF}"
        - name: SSL_TYPE
          value: "manual"
        - name: SSL_CERT_PATH
          value: "/etc/ssl/mail/fullchain.pem"
        - name: SSL_KEY_PATH
          value: "/etc/ssl/mail/${DN}.key"
      volumeMounts:
        - name: mail-data
          mountPath: /var/mail
        - name: postfix-main-cf
          mountPath: /tmp/docker-mailserver/postfix-main.cf
          readOnly: true
        - name: rspamd-config
          mountPath: /tmp/docker-mailserver/rspamd
        - name: ssl-certs
          mountPath: /etc/ssl/mail
          readOnly: true
  volumes:
    - name: mail-data
      hostPath:
        path: /opt/zfs/dkmail/data
        type: Directory
    - name: postfix-main-cf
      hostPath:
        path: /opt/zfs/dkmail/conf/postfix-main.cf
        type: File
    - name: rspamd-config
      hostPath:
        path: /opt/zfs/dkmail/conf/rspamd
        type: Directory
    - name: ssl-certs
      hostPath:
        path: /opt/zfs/dkmail/conf/ssl
        type: Directory
EOF

YAML 與原始 podman run 參數對照

原始 podman run 參數YAML 對應欄位
--name dkmailmetadata.name: dkmail
-h ${MAIL_FQDN}spec.hostname
--network=hostspec.hostNetwork: true
--dns ${DNS_IP}spec.dnsConfig.nameservers
--dns-search ${DN}spec.dnsConfig.searches
-e NETWORK_INTERFACE=${NET_IF}containers[].env
-e SSL_TYPE=manualcontainers[].env
-v ...:/var/mailvolumes + volumeMounts
-v ...:rovolumeMounts 加上 readOnly: true

說明: 不需要掛載 Dovecot SSL 設定檔。docker-mailserver 會根據 SSL_TYPE=manual + SSL_CERT_PATH + SSL_KEY_PATH 自動設定 Postfix TLS、Dovecot TLS 和 SASL 認證 socket。


五、建立 Quadlet .kube 檔案

cat << 'EOF' | sudo tee /etc/containers/systemd/dkmail.kube
[Unit]
Description=Docker Mail Server (dkmail) with TLS
After=network-online.target
Wants=network-online.target

[Kube]
Yaml=/etc/containers/systemd/dkmail.yaml
Network=host

[Service]
Restart=always
RestartSec=10
TimeoutStartSec=120

[Install]
WantedBy=multi-user.target default.target
EOF

.kube 各區塊說明

區塊設定說明
[Unit]After=network-online.target網路就緒後才啟動
[Kube]Yaml=...指向 Kubernetes YAML 路徑
[Kube]Network=host使用 host 網路(郵件服務需直接綁定 Port)
[Service]Restart=always異常退出自動重啟
[Service]TimeoutStartSec=120給 Container 足夠啟動時間
[Install]WantedBy=multi-user.target開機自動啟動

六、啟動服務

# 重新載入 systemd(讓 Quadlet generator 產生 service)
sudo systemctl daemon-reload

# 啟動服務
sudo systemctl start dkmail.service

# 設定開機自動啟動
sudo systemctl enable dkmail.service

# 確認狀態
sudo systemctl status dkmail.service

七、驗證 TLS

# ===== 根據環境修改 =====
export MAIL_FQDN="mx1.kubeantony.com"    # 郵件主機 FQDN

7.1 確認 Pod 與 Container

sudo podman pod ps
sudo podman ps --pod

7.2 確認 TLS

# SMTP STARTTLS(Port 587)
openssl s_client -connect ${MAIL_FQDN}:587 -starttls smtp

# SMTPS(Port 465)
openssl s_client -connect ${MAIL_FQDN}:465

# IMAPS(Port 993)
openssl s_client -connect ${MAIL_FQDN}:993

# POP3S(Port 995)
openssl s_client -connect ${MAIL_FQDN}:995

正常輸出應包含:

subject: CN = <MAIL_FQDN>
issuer: CN = <DN> Root CA
Verify return code: 21 (unable to verify the first certificate)  ← 自簽憑證正常現象

八、設定 SPF Record

# ===== 根據環境修改 =====
export DN="kubeantony.com"                # 郵件域名
export MAIL_IP="192.168.11.3"           # Mail Server IP
export DNS_IP="192.168.11.2"            # 內網 DNS Server IP

透過 nsupdate 將 SPF 記錄新增至內網 DNS(BIND):

nsupdate << EOF
server ${DNS_IP}
zone ${DN}
update del ${DN}. TXT
update add ${DN}. 300 IN TXT "v=spf1 ip4:${MAIL_IP} ~all"
send
EOF

驗證 SPF Record:

dig @${DNS_IP} ${DN}. TXT +short

預期輸出:

"v=spf1 ip4:<MAIL_IP> ~all"

九、設定 DKIM

# ===== 根據環境修改 =====
export DN="kubeantony.com"                # 郵件域名
export DNS_IP="192.168.11.2"            # 內網 DNS Server IP

9.1 產生 DKIM Key

sudo podman exec -it dkmail-dkmail setup config dkim domain ${DN}

預期輸出:

INFO  rspamd-dkim: Creating DKIM keys of type 'rsa' and length '2048' with selector 'mail' for domain '<DN>'
INFO  rspamd-dkim: Successfully created DKIM keys
INFO  rspamd-dkim: Here is the content of the TXT DNS record mail._domainkey.<DN> that you need to create:
v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQE...

9.2 啟用內網寄信的 DKIM 簽署

重要: docker-mailserver 預設產生的 dkim_signing.confsign_local = false, 這會導致從內網直接寄出的郵件不會被 DKIM 簽署。必須改為 true

sudo sed -i 's/sign_local = false/sign_local = true/' \
  /opt/zfs/dkmail/conf/rspamd/override.d/dkim_signing.conf

驗證修改結果:

grep 'sign_local' /opt/zfs/dkmail/conf/rspamd/override.d/dkim_signing.conf

預期輸出:

sign_local = true;

9.3 確認產生的檔案

tree /opt/zfs/dkmail/conf/rspamd/

預期結構:

/opt/zfs/dkmail/conf/rspamd/
├── dkim
│   ├── rsa-2048-mail-<DN>.private.txt
│   ├── rsa-2048-mail-<DN>.public.dns.txt
│   └── rsa-2048-mail-<DN>.public.txt
└── override.d
    ├── dkim_signing.conf
    ├── hfilter.conf
    ├── options.inc
    └── worker-controller.inc

9.4 擷取 DKIM Public Key

DKIM_K8S_TXT=$(sed -n 's|.*"\([^"]*\)".*|"\1"|p' \
  /opt/zfs/dkmail/conf/rspamd/dkim/rsa-2048-mail-${DN}.public.txt | tr '\n' ' ')

echo $DKIM_K8S_TXT

9.5 新增 DKIM TXT Record(以 BIND DNS 為例)

nsupdate << EOF
server ${DNS_IP}
zone ${DN}
update del mail._domainkey.${DN}
update add mail._domainkey.${DN} 3600 IN TXT $DKIM_K8S_TXT
send
EOF

9.6 驗證 DKIM Record

dig @${DNS_IP} mail._domainkey.${DN}. TXT +short

預期輸出:

"v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA..."

9.7 重啟 Container 套用 DKIM 設定

sudo systemctl restart dkmail.service

十、設定 DMARC Record

# ===== 根據環境修改 =====
export DN="kubeantony.com"                # 郵件域名
export DNS_IP="192.168.11.2"            # 內網 DNS Server IP
export POSTMASTER="bigred"                # Postmaster 帳號名稱

說明: DMARC 需在 SPF 和 DKIM 都設定完成後再新增。 p=none 表示僅監控模式,不影響郵件遞送,待確認運作正常後可改為 p=quarantinep=reject

nsupdate << EOF
server ${DNS_IP}
zone ${DN}
update del _dmarc.${DN}. TXT
update add _dmarc.${DN}. 300 IN TXT "v=DMARC1; p=none; rua=mailto:${POSTMASTER}@${DN}"
send
EOF

驗證 DMARC Record:

dig @${DNS_IP} _dmarc.${DN}. TXT +short

預期輸出:

"v=DMARC1; p=none; rua=mailto:<POSTMASTER>@<DN>"

十一、測試寄信

重要: 以下測試步驟必須在同一內網的其他機器上執行(不是 Mail Server 本機)。 從其他機器寄信才能正確模擬實際使用情境,驗證 mynetworks relay 設定、TLS 連線、SMTP 認證、 以及 DKIM 簽署(sign_local 是否對內網來源生效)等功能是否正常。

# ===== 根據環境修改(在測試機器上執行)=====
export DN="kubeantony.com"                # 郵件域名
export MAIL_HOST="mx1"                    # 郵件主機名稱前綴
export MAIL_FQDN="${MAIL_HOST}.${DN}"     # 郵件主機 FQDN(自動組合)
export MAIL_IP="192.168.11.3"           # Mail Server IP
export POSTMASTER="bigred"                # Postmaster 帳號名稱

11.1 安裝寄信工具(在內網其他機器上執行)

# Debian/Ubuntu
sudo apt install -y s-nail

# Alpine Linux
sudo apk add s-nail

11.2 從內網直接寄信測試(不經 SMTP 認證)

echo "Test Mail" | s-nail \
  -S mta=smtp://${MAIL_IP} \
  -s "Mail Server Test" \
  "sreantony@gmail.com"

11.3 透過 SMTP 認證寄信測試(msmtp)

在內網其他機器上安裝 msmtp 並建立設定檔(自簽憑證需關閉憑證檢查):

cat << EOF > ~/.msmtprc
account    test
host       ${MAIL_FQDN}
port       587
from       ${POSTMASTER}@${DN}
auth       plain
user       ${POSTMASTER}@${DN}
password   ${POSTMASTER}
tls        on
tls_starttls on
tls_certcheck off
logfile    /tmp/msmtp.log
EOF

chmod 600 ~/.msmtprc

注意: 帳號為 ${POSTMASTER}@${DN}(不是 ${POSTMASTER}@${MAIL_FQDN}), 對應 Dockerfile 中 setup email add bigred@${DN} 的設定。

寄信測試:

echo -e "To: sreantony@gmail.com\nSubject: Auth Test\n\n認證測試" | msmtp -a test sreantony@gmail.com

11.4 驗證 Rspamd 評分

開啟 Rspamd Web UI(http://${MAIL_FQDN}:11334)查看 History, SPF / DKIM / DMARC 設定正確後,以下 Symbol 應消失或轉為通過:

Symbol修正前修正後
R_SPF_NA+1.5(無 SPF)R_SPF_ALLOW(SPF 通過)
R_DKIM_NA+1.0(無 DKIM)R_DKIM_ALLOW(DKIM 通過)
DMARC_NA+0.5(無 DMARC)DMARC_POLICY_ALLOW(DMARC 通過)
AUTH_NA+2.5(未認證)消失(經 SMTP 認證寄信)

十二、日常管理

操作指令
啟動sudo systemctl start dkmail.service
停止sudo systemctl stop dkmail.service
重啟sudo systemctl restart dkmail.service
查看狀態sudo systemctl status dkmail.service
查看 logsudo journalctl -u dkmail.service -f
開機啟動sudo systemctl enable dkmail.service
取消開機啟動sudo systemctl disable dkmail.service
進入 Containersudo podman exec -it dkmail-dkmail bash
Container logsudo podman logs -f dkmail-dkmail
Postfix logsudo podman exec -it dkmail-dkmail tail -50 /var/log/mail/mail.log

注意: Container 名稱為 dkmail-dkmail(Pod 名稱 + Container 名稱)。


十三、客戶端匯入 CA 根憑證

# ===== 根據環境修改 =====
export DN="kubeantony.com"                # 郵件域名
export MAIL_IP="192.168.11.3"           # Mail Server IP

自簽憑證需在每台客戶端匯入 ca.crt

# 從伺服器下載 ca.crt
scp user@${MAIL_IP}:/opt/mkcert/${DN}/ca.crt ~/Desktop/
客戶端匯入方式
Thunderbird設定 → 隱私與安全 → 憑證 → 匯入 → 選 ca.crt → 勾選「信任此 CA 識別網站」
Windows雙擊 ca.crt → 安裝憑證 → 「受信任的根憑證授權單位」
macOS雙擊 ca.crt → 加入鑰匙圈 → 設定為「永遠信任」
Linuxsudo cp ca.crt /usr/local/share/ca-certificates/ && sudo update-ca-certificates

十四、故障排除

Quadlet 沒有產生 service

# 手動執行 generator 檢查錯誤
sudo /usr/libexec/podman/quadlet --dryrun

手動測試 YAML 是否正確

# 用 podman kube play 直接測試
sudo podman kube play /etc/containers/systemd/dkmail.yaml

# 測試完畢清除
sudo podman kube down /etc/containers/systemd/dkmail.yaml

映像檔找不到

sudo podman images | grep dkmail

# 如果缺少 localhost 前綴,重新標記
sudo podman tag dkmail.rspamd localhost/dkmail.rspamd:latest

SMTP 寄信出現 Relay access denied

確認 postfix-main.cfmynetworks 包含發信主機的網段:

sudo podman exec -it dkmail-dkmail postconf mynetworks

SMTP 認證失敗(SASL)

確認 Dovecot auth socket 存在:

sudo podman exec -it dkmail-dkmail ls -l /dev/shm/sasl-auth.sock

確認 Postfix 指向正確的 socket 路徑:

sudo podman exec -it dkmail-dkmail postconf smtpd_sasl_path

注意: docker-mailserver 的 Dovecot auth socket 位於 /dev/shm/sasl-auth.sock, 不是 Postfix 預設的 private/auth。不要在 postfix-main.cf 手動設定 smtpd_sasl_path / smtpd_sasl_type,讓 docker-mailserver 自動處理。

TLS 憑證與 docker-mailserver 衝突

重要: 不要在 postfix-main.cf 設定 smtpd_tls_cert_file / smtpd_tls_key_file。 docker-mailserver 的 SSL_TYPE=manual 會使用 smtpd_tls_chain_files, 兩者同時存在會產生衝突警告且舊的設定會被忽略。


完整目錄結構

/etc/containers/systemd/                # Quadlet 檔案
├── dkmail.kube                         # Quadlet 單元檔
└── dkmail.yaml                         # Kubernetes Pod YAML

/opt/zfs/dkmail/                        # 資料與設定
├── data/                               # 郵件資料(/var/mail)
└── conf/
    ├── postfix-main.cf                 # Postfix 額外設定(mynetworks + smtp_tls)
    ├── ssl/
    │   ├── fullchain.pem               # 伺服器憑證 + CA 憑證
    │   └── <DN>.key                    # 伺服器私鑰
    └── rspamd/
        ├── dkim/                       # DKIM Keys(步驟九產生)
        │   ├── rsa-2048-mail-<DN>.private.txt
        │   ├── rsa-2048-mail-<DN>.public.dns.txt
        │   └── rsa-2048-mail-<DN>.public.txt
        └── override.d/
            ├── dkim_signing.conf       # DKIM 簽署設定(步驟九產生)
            ├── options.inc
            ├── worker-controller.inc
            └── hfilter.conf

/opt/mkcert/                            # 憑證產生工具(備份保留)
├── certctl
├── config
└── <DN>/
    ├── ca.crt
    ├── ca.key
    ├── <DN>.crt
    └── <DN>.key

/opt/zfs/images/dkmail-rspamd/          # Container Image Dockerfile
└── Dockerfile