SSD Nodes Learn
指南 Matt Connor作者: Matt Connor · 已更新 2026-07-24

Mailcow VPS 架設教學:如何確保郵件能成功送達 Gmail

在 VPS 上架設 mailcow-dockerized 時,務必先測試 outbound port 25 是否被封鎖,否則郵件會卡在 queue 中。本文詳細說明如何透過設定 PTR record 避免被 Gmail 以 550 5.7.25 錯誤代碼拒收。

您的建置目標

在您擁有的主機上建置完整的郵件伺服器:包含用於收發郵件的 SMTP、確保手機與筆電同步的 IMAP、Webmail 用戶端,以及會對雙向郵件進行評分的垃圾郵件過濾器。mailcow-dockerized 將 Postfix、Dovecot、Rspamd、SOGo webmail、MariaDB、Redis 與 ACME client 整合於單一 Docker Compose 堆疊中,因此軟體安裝並非難點。您將在半小時內完成運行。

真正的挑戰在於周邊設定。電子郵件是少數會被網路其他服務主動排斥新伺服器的服務;「功能正常」與「郵件被 Gmail 靜默丟棄」之間的差距,取決於四項 DNS 紀錄與一項您可能無法完全控制的 IP 信譽設定。在租用任何服務前,請先閱讀下方的先決條件。若閱讀後您認為維護信譽的成本過高,這也是合理的決定 —— 我們對 2026 年值得自行架設服務的總結 在「僅限您下定決心時」章節中,正是基於這些原因來討論電子郵件。

前提條件即是專案核心

若遺漏任何一項,郵件將無法送達。以下依據常見錯誤程度排序:

必須開啟 Outbound port 25。 伺服器透過 TCP port 25 向 Gmail 與 Microsoft 傳送郵件。許多 VPS 與雲端供應商為了防範垃圾郵件,預設會封鎖 outbound 25。此封鎖不會顯示錯誤,系統啟動與運行皆正常,但郵件會永遠卡在 queue 中。安裝前請務必測試。若被封鎖,唯一的解決方法是向供應商提交 support ticket 要求開啟;部分供應商會為長期用戶開啟,部分則永遠不會。

具備良好信譽的乾淨 IP。 使用過的 VPS IP 常因前一個租戶的垃圾郵件行為而被列入 blocklists。在開始作業前,請使用 Spamhaus lookup 或 mxtoolbox 等服務檢查您的 IP。若 IP 已在名單中,無論如何調整程式碼都無法解決被拒收的問題。

具備 DNS 控制權與正確的 PTR record。 您必須在網域的 zone 中新增紀錄,且必須設定 reverse DNS (PTR),將伺服器 IP 指向您的 mail hostname。PTR 通常不會出現在 DNS 控制面板中,而是由 IP 的持有者管理,因此必須透過 VPS 供應商的控制面板或透過 ticket 設定。

6 GiB RAM 與 2 vCPU 是建議的最低配置。 mailcow 私有安裝的最低配置為 6 GiB RAM 加上 1 GiB swap;當使用者數量增加時,建議配置為 8 GiB。若記憶體低於 2.5 GiB,generate_config.sh 會建議停用 ClamAV 病毒掃描器,以避免 kernel 觸發 OOM killer 殺掉 containers。初始配置建議提供 20 GB SSD。

使用 DNS name 而非單純的 IP。 請選擇一個如 mail.example.com 的 hostname。這個名稱將成為您的 MAILCOW_HOSTNAME、TLS 憑證的 subject、PTR 目標以及 SMTP banner。請確保在所有地方保持一致。

Step 1 — 驗證 outbound port 25 是否已開啟

請先執行此步驟。若此步驟失敗,後續操作皆為徒勞。請從新的 VPS 嘗試與真實的 mail server 建立 SMTP 連線:

sudo apt update && sudo apt install -y netcat-openbsd
nc -vz -w 5 gmail-smtp-in.l.google.com 25

若連線成功,會立即顯示結果:

Connection to gmail-smtp-in.l.google.com (142.250.x.x) 25 port [tcp/smtp] succeeded!

若 port 被封鎖,則會等待 5 秒後失敗:

nc: connect to gmail-smtp-in.l.google.com port 25 (tcp) timed out: Operation now in progress

該 timeout 即代表連線被封鎖。這是由供應商端的 network filter 造成,而非您的 firewall,因此無法透過本地設定解決。請提交工單並說明:「Please enable outbound TCP port 25 for my VPS at <IP>; I am running a legitimate mail server.」在結果顯示為 "succeeded" 之前,請勿安裝 mailcow。請注意,inbound 25(其他伺服器連向您)是不同的路徑且通常是開啟的;供應商限制的是 outbound 端。

Step 2 — 現在設定 DNS 紀錄

DNS 變更需要傳播時間,因此在安裝前請盡可能完成所有設定。假設您的網域為 example.com,郵件主機為 mail.example.com,且 IP 為 10.0.0.10。請在您的 Zone 中建立:

mail.example.com.        A      10.0.0.10
mail.example.com.        AAAA   2001:db8::10          ; only if you have IPv6
example.com.             MX  10 mail.example.com.
example.com.             TXT    "v=spf1 mx -all"
_dmarc.example.com.      TXT    "v=DMARC1; p=none; rua=mailto:postmaster@example.com"

SPF 紀錄的意義是「僅允許我的 MX 紀錄代表此網域發信,拒絕其他來源」。請先將 DMARC 設定為 p=none,以便在不影響自身郵件傳送的情況下觀察報告;待對齊(alignment)確認無誤後,再將其強化為 p=quarantine,接著是 p=reject。目前刻意保留兩項尚未設定:DKIM(mailcow 會在 Step 6 為您自動產生)以及 PTR(您現在需在供應商的控制台進行設定)。

請將 10.0.0.10 的 PTR (Reverse DNS) 設定為 mail.example.com —— 即 MAILCOW_HOSTNAME 的完整值。這是大多數人最容易遺漏的單一紀錄,大型供應商會因此紀錄錯誤而拒絕您的郵件。若您的控制台沒有 rDNS 欄位,請提交技術支援單(raise a ticket)。

Step 3 — 安裝 Docker

mailcow 需要安裝包含 Compose v2 插件的 Docker Engine。請使用 Docker 官方提供的便利腳本,不要使用 Ubuntu 的 docker.io 套件,因為該套件完全不包含 Compose 插件:

curl -fsSL https://get.docker.com | sudo sh
sudo docker compose version

你應該會看到 Docker Compose version v2.x 行。如果 docker compose version 顯示 docker: 'compose' is not a docker command,代表 Docker Engine 已安裝,但尚未安裝 Compose 插件。請從 Docker 儲存庫安裝該插件:重新執行上述腳本,或參考 我們的 Docker Compose 基礎指南,該指南會從 Docker 官方的 apt 儲存庫同時安裝這兩者。

Step 4 — Clone mailcow and generate the config

cd /opt
sudo git clone https://github.com/mailcow/mailcow-dockerized
cd mailcow-dockerized
umask
sudo ./generate_config.sh

Check umask prints 0022 first — mailcow refuses to build with an odd file mask, and a fresh Ubuntu 24.04 root shell already gives you 0022. The script then asks the one thing that matters: the fully qualified hostname. Enter mail.example.com — the value must match your A record and PTR exactly. It writes mailcow.conf, the single environment file the whole stack reads. Open it if you need to change the web ports (HTTP_PORT, HTTPS_PORT) or disable ClamAV on a small box:

MAILCOW_HOSTNAME=mail.example.com
HTTP_PORT=80
HTTPS_PORT=443
SKIP_CLAMD=n          # set to y to drop the virus scanner on a <2.5 GiB box

SKIP_FTS=y is the other lever on a low-RAM box: full-text search is the second memory hog mailcow's docs name, and skipping it only costs you body-text search in webmail.

Leave HTTP_PORT=80 and HTTPS_PORT=443 unless something else on the host already owns them — mailcow's built-in ACME client needs port 80 reachable from the internet to obtain the certificate. This is why you do not run a separate nginx-plus-Certbot setup on the same box; mailcow issues and renews its own TLS internally, and a second service squatting on 80/443 breaks that.

Step 5 — 啟動 stack 並登入

sudo docker compose pull
sudo docker compose up -d
sudo docker compose ps

pull 過程會下載約 24 個 images;請稍候幾分鐘。當 docker compose ps 顯示所有 container 皆為 running (或 healthy) 時,請在瀏覽器中開啟 https://mail.example.com。預設的 admin 登入資訊為 username admin,password moohoo。請立即在 admin UI 的 Access → Administrators 中更改該 password。若瀏覽器顯示 NET::ERR_CERT_AUTHORITY_INVALID 警告,代表 ACME certificate 尚未核發 —— 在判定系統故障前,請先參閱下方的 ACME failure 說明;在啟動後的 1 到 2 分鐘內,顯示 self-signed placeholder 是正常現象。

Step 6 — 新增網域、信箱並發布 DKIM

在管理介面中,開啟 Mail Setup 頁面 (Configuration → Mail Setup),在 Domains 標籤下點擊 Add domain 並輸入 example.com。接著,在 Mailboxes 標籤下點擊 Add mailbox 以建立帶有密碼的 you@example.com。該信箱已可透過 IMAP 正常運作。

接下來是 DKIM 金鑰。前往 Configuration → ARC/DKIM keys;當您新增網域時,mailcow 可能已自動產生金鑰;若尚未產生,請在此處產生 — 選擇該網域,保留 selector dkim,選擇 2048-bit,然後點擊 Add。複製顯示的長字串 TXT 值,並將其發布為:

dkim._domainkey.example.com.  TXT  "v=DKIM1;k=rsa;t=s;s=email;p=MIIBIjANBgkqh...long-key...QAB"

mailcow 的 Domains 頁面設有 DNS 按鈕,會列出所有預期紀錄,並針對實際發布的紀錄顯示綠色勾選或紅色叉號。請將其作為檢查清單 — 在測試送達率之前,確保每一列都顯示綠色。發布後若 DKIM 顯示紅色,通常代表金鑰被錯誤地拆分到不同的 TXT 區塊中;由於 2048-bit 金鑰長度超過單一 TXT 字串 255 個字元的限制,請將其作為單一邏輯值貼上,並由您的 DNS 主機進行拆分。

Step 7 — 測試送達率並取得 10/10 分

前往 mail-tester.com,複製顯示的隨機地址,並從您的新信箱發送郵件 —— 請登入 https://mail.example.com/SOGo 的 SOGo webmail 並從該處發送。接著點擊 "Then check your score"。

目標是取得 10/10 分。常見的扣分原因如下:

  • SPF not aligned —— 您的 MX/SPF 紀錄缺失,或發送的 IP 未包含在內。請重新檢查 SPF TXT 紀錄。
  • DKIM signature does not verify —— dkim._domainkey TXT 紀錄缺失、仍在生效中(propagating)或格式錯誤。這是最常見的錯誤。
  • No PTR / PTR mismatch —— 反向 DNS 無法解析至 mail.example.com。請聯繫供應商進行修正。
  • Listed on a blocklist —— 您的 IP 過往信譽不佳。請申請解除黑名單或要求更乾淨的 IP。

在分數達到 10/10 之前,請勿向 Gmail 或 Outlook 發送真實郵件。低分加上新 IP 會導致您的網域在第一天就被標記。

Step 8 — 連接真實郵件用戶端

請在 Thunderbird、Apple Mail 或手機上使用以下設定連接至伺服器。所有連線的伺服器主機均為 mail.example.com

  • IMAP: port 993, SSL/TLS (或使用 STARTTLS 的 port 143)
  • SMTP submission: port 465, SSL/TLS (或使用 STARTTLS 的 port 587)
  • Username: 完整電子郵件地址,you@example.com
  • Password: 您設定的信箱密碼

切勿透過 port 25 發送用戶端郵件。該 port 僅供伺服器間通訊使用,mailcow 不提供該 port 的驗證提交功能,且連線請求會被拒絕。若用戶端回報 Relay access denied,代表其正嘗試透過 port 25 發送或未進行驗證;請將設定改為使用您的信箱憑證並連接 port 465 或 587。

Step 9 — 備份關鍵資料

mailcow 提供一個備份指令碼,可針對所有具備狀態的 volume 進行快照。請將其執行至外部磁碟或已掛載的遠端儲存裝置:

sudo MAILCOW_BACKUP_LOCATION=/opt/mailcow-backups \
  ./helper-scripts/backup_and_restore.sh backup all

all 會擷取六項內容,遺失其中任何一項都會導致資料遺失:vmail(實際的信箱資料)、crypt(用於解密 vmail 的金鑰,缺少此項將無法解密)、mysql(存放網域、使用者、別名與設定的 MariaDB)、redis(佇列與快取狀態)、rspamd(已學習的垃圾郵件/正常郵件資料),以及 postfix(郵件佇列)。該指令碼於 helper container 內執行並寫入壓縮後的封存檔,因此即使在 stack 運行中,備份仍能保持一致性。建議使用 nightly cron job 進行自動化,並加入 --delete-days 14 以清理舊的備份集。還原流程使用相同的指令碼並加上 restore,該參數會列出所有快照並讓你選擇要還原的內容。未經測試還原的備份僅是「希望」而非真正的備份 — 請務必在新的 VPS 上進行一次測試還原。

Step 10 — 定期更新

mailcow 透過專用腳本進行更新。該腳本會依序執行:拉取新程式碼、遷移 mailcow.conf、預取 images,並重啟 containers:

cd /opt/mailcow-dockerized
sudo ./update.sh --check   # reports whether an update exists, changes nothing
sudo ./update.sh           # applies it

請先進行備份(Step 9),因為 schema 遷移難以復原。更新頻率很高,且包含針對網路服務 daemon 的安全性修復,請勿讓 mail server 數月未更新。若更新導致 container 狀態不正常,sudo docker compose logs --tail=50 <service>-mailcow 會標示出無法正常啟動的 daemon 名稱。

強化安全性說明

mailcow 運行專屬的 netfilter 服務 (netfilter-mailcow),會封鎖對郵件與 webmail 埠進行暴力破解的 IP,因此郵件端具備內建防護。然而,這並不包含主機本身的 SSH,該服務仍暴露於網路並面臨暴力破解攻擊。建議搭配 使用 Fail2ban 監控 SSH 認證日誌 並僅允許金鑰登入。請為 mailcow 管理介面設定強密碼,且理想情況下,應將其移出公網或置於 VPN 後方。

Failure modes, with the exact strings

郵件佇列且無法送達。 執行 sudo docker compose exec postfix-mailcow postqueue -p,或查看管理介面 (admin UI) 的郵件佇列;若出現以下延遲狀態:

status=deferred (connect to gmail-smtp-in.l.google.com[142.250.x.x]:25: Connection timed out)

這代表您的供應商封鎖了 outbound port 25 (步驟 1)。任何設定都無法修復此問題,請提交技術支援單 (open a ticket)。這與 DNS 或 TLS 無關;判斷依據是針對遠端 MX 在 port 25 顯示 timed out

Gmail 將所有郵件標記為垃圾郵件,或直接退件。 在 Gmail 中開啟郵件,點選「顯示原始郵件 (Show original)」,並查看驗證結果 (auth results)。dkim=faildkim=none 代表您的 dkim._domainkey TXT 紀錄缺失、格式錯誤或尚未生效——請依照 ARC/DKIM 頁面顯示的內容重新發布,並等待 TTL 生效。spf=fail 代表 SPF/MX 紀錄未包含您的 IP。驗證一致性 (Alignment) 至關重要;只要有一個檢查失敗,郵件就會進入垃圾郵件匣。

連線時被大型供應商拒絕。 退件通知或 Postfix 日誌會顯示 Gmail 的 PTR 拒絕訊息:

550-5.7.25 [10.0.0.10] The IP address sending this message does not have a PTR
550-5.7.25 record setup, or the corresponding forward DNS entry does not match
550 5.7.25 the sending IP. As a policy, Gmail does not accept messages from IPs
550 5.7.25 with missing PTR records.

550 5.7.25 錯誤碼代表缺少或不匹配的反向 DNS (reverse DNS)。請在供應商端將您的 IP PTR 設定為 mail.example.com (步驟 2)。正向 (A) 與反向 (PTR) 紀錄必須一致,且兩者必須指向 mailcow 與其他伺服器溝通時所使用的相同主機名稱。

瀏覽器顯示無法消除的憑證警告。 acme-mailcow 容器無法取得正式憑證。請檢查其日誌:

sudo docker compose logs acme-mailcow | tail -n 40

若出現 Cannot validate any hostnames, skipping Let's Encrypt for 1 hour. 或驗證失敗 (challenge failure),代表從網際網路無法連線至 port 80,或者 A 紀錄未指向此伺服器。請確認 mail.example.com 解析至本機,並透過主機防火牆開啟 80 與 443 port,同時確保沒有其他服務佔用這些 port。修復問題後,請使用 sudo docker compose restart acme-mailcow 重啟用戶端,而非等待一小時的退避機制 (back-off)。

FAQ

自架郵件真的值得嗎?

如果您追求數據所有權、無限別名以及完全控制權,答案是肯定的 —— mailcow 提供專業的技術棧,成本僅相當於一台 VPS。但送達率是一項持續性的任務:IP 信譽、DNS 對齊以及黑名單監控工作永無止盡。若是針對關鍵業務地址,一旦郵件進入垃圾郵件匣,損失將無法估量,此時選擇代管服務商較為務實。只有在您比起便利性更重視控制權,且願意投入維護精力時,才建議自行架設。

如何確認 outbound port 25 是否被封鎖?

請從伺服器執行 nc -vz -w 5 gmail-smtp-in.l.google.com 25。「succeeded!」表示連接開啟;若停頓後出現 timed out,則表示您的供應商封鎖了該連接埠。這是自架伺服器「能收信但無法寄信」最常見的原因。唯一的解決方案是要求供應商開啟該連接埠,任何本地設定都無法解決此問題。

為什麼我的郵件仍會進入 Gmail 的垃圾郵件匣?

通常是因為驗證鏈(authentication chain)失效。請在 Gmail 中使用「Show original」並檢查 spf=passdkim=passdmarc=pass。若出現 dkim=fail,表示 dkim._domainkey TXT 紀錄缺失或錯誤;此外,PTR 紀錄不匹配或新 IP 缺乏寄信歷史也會導致此問題。請先確保 mail-tester.com 達到 10/10 分,接著緩慢進行 IP 預熱(warm up)——從每天幾封郵件開始逐漸增加,而非在第一天就大量寄送。

我到底需要備份哪些內容?

請執行 backup_and_restore.sh backup all 並將完整備份存放在伺服器之外。它會擷取 vmail(信箱內容)、crypt(解密金鑰)、MariaDB 資料庫(網域、使用者、別名、設定)、Redis、Rspamd 的學習數據以及 Postfix 佇列。其中 crypt 磁碟區最容易被忽略 —— 若缺少它,vmail 備份將只是無法讀取的加密字串。請務必至少進行一次在測試機上的還原測試。

我可以在 2 GB 的 VPS 上執行 mailcow 嗎?

效能會非常吃力。當記憶體低於約 2.5 GiB 時,generate_config.sh 會建議停用 ClamAV;即便如此,Rspamd、ClamAV、Dovecot 與 MariaDB 仍會競爭記憶體,在實際負載下會觸發 swap 或 OOM kills。對於單人使用的穩定安裝,建議最低配置為 6 GiB 記憶體搭配 1 GiB swap;一旦有超過兩人使用,請立即升級至 8 GiB。

#mailcow#email#self-hosting#docker#dns