Mail Server 征服指南(一) 前言:寫給業餘愛好者

精選內容

相信很多跟我一樣熱愛 Linux 的業餘玩家,都有過類似的經歷:我們興致勃勃地從零開始,成功架設了自己的 Web Server(無論是 Apache 還是 Nginx),搞定了 HTTPS 憑證,甚至進階到自己架設 DNS 服務。看著這些服務在網路上跑起來,那種成就感是無可比擬的。

然而,在這條「自託管 (Self-hosting)」的路上,總有一座公認難以跨越的高山,那就是—— Mail Server

比起 Web Server,架設 Mail Server 的難度幾乎是指數級上升的。它不僅僅是安裝軟體那麼簡單,你還得面對繁瑣的設定檔、複雜的 DNS 驗證(SPF, DKIM, DMARC)、以及如何避免自己的信件被 Gmail 或 Outlook 歸類為垃圾郵件。我曾經無數次在設定檔的迷宮中打轉,或者看著 Log 檔裡的錯誤訊息感到挫折。

這正是我寫這系列文章的初衷。

我不希望這只是一篇充滿「複製貼上」指令的教學。這系列文章的目標,是幫助像我這樣非科班出身、但充滿熱情的 Linux 愛好者,不僅是「照著做」,更能真正理解 Mail Server 的運作原理與架構。

為了讓這套系統更具備實用性與靈活性,我們不會使用傳統的 Linux 系統帳號來收發信,而是挑戰業界標準的**「虛擬使用者 (Virtual Users)」**架構——利用 MariaDB (MySQL) 資料庫來管理我們的網域、使用者與別名。這意味著未來你要新增信箱、修改密碼、甚至是多網域託管,都只需要修改資料庫,而無需更動系統核心設定。

最後,做個小小的「行前提醒」:

這系列文章是特別寫給已經對 Linux 伺服器運作有一定概念的朋友。如果你已經親手架設過 Web Server、熟悉 DNS 解析原理,並且對 SSH 指令列操作感到自在,那麼你就是這篇文章的最佳讀者。為了讓教學更流暢,我們將跳過基礎的 Linux 操作說明(例如如何使用 vim/nano 編輯檔案、基本的檔案權限管理等),直接切入 Mail Server 的核心配置,讓你把寶貴的精力集中在攻克這個最艱難的挑戰上。

如果你準備好了,請跟著我一起開始這趟旅程。

第一章:架構規劃與環境準備

第二章:基礎建設篇——DNS、SSL 與資料庫

第三章:郵差的武裝——安裝 Postfix 並連接資料庫

第四章:安裝與設定 Dovecot (最後一塊拼圖)。

第五章:驗收時刻——全流程測試

第六章:設定 AWS SES Relay (讓信件使命必達)

Mail Server 征服指南 (二) 第一章:架構規劃與環境準備

在我們登入伺服器輸入任何指令之前,必須先建立一張清晰的「地圖」。

很多初學者在架設 Mail Server 時感到挫折,是因為不知道資料現在流向哪裡:是卡在防火牆?是 DNS 設定錯了?還是資料庫連線失敗?透過理解下面第二點的的三個核心流程,你在除錯時就能精準判斷問題出在哪個環節。

1. 為什麼我們應該選擇 AWS EC2作為初學上手的平台?

雖然你可以在家裡的舊電腦或 Raspberry Pi 上練習,但我強烈建議初學者使用 AWS EC2(或其他雲端 VPS),這能大幅降低「卡關」的機率:

  • 擁有乾淨的網路環境:家用網路通常是浮動 IP,且 ISP 經常封鎖郵件所需的 Port 25,這會讓你一開始就無法收信。EC2 提供了標準的網路環境與公網 IP (Public IP)。
  • 容錯率與「時光機」:這是最重要的理由。在進行危險設定(例如修改資料庫結構或防火牆)之前,我們可以對 EC2 建立「快照 (Snapshot)」。萬一設定檔改壞了、服務起不來了,不需要重灌系統,一鍵就能還原到壞掉前的狀態。這給了我們大膽嘗試的勇氣。

2. 郵件運作的三大流程

我們將採用業界標準的 Postfix + Dovecot + MariaDB (MySQL) 組合。為了方便管理,我們使用「虛擬使用者」架構,將所有帳號、網域儲存在資料庫中,而非 Linux 系統帳號。

流程一:別人寄信給你 (Incoming Mail)

當網路上有人(postmaster@mydomain.com)寄信給你(username@mydomain.net)時,流程如下:

  1. 查詢 MX 記錄:發件方伺服器 (mydomain.com) 向 DNS 查詢目標域名 (mydomain.net) 的 MX 記錄,以確認郵件該發送到哪裡。
  2. 指向伺服器:DNS 解析出目標 Postfix 伺服器的 IP 地址,指引發件方進行連接。
  3. 發送郵件:發件方透過 SMTP 協議,將郵件內容發送給 Postfix 伺服器。
  4. 查詢域名:Postfix 接收到郵件後,暫停處理並向 MySQL 資料庫查詢:該信件的目標域名是否屬於本機需要負責的範圍?
  5. 確認接收:MySQL 確認域名有效且為本地託管,返回確認信息給 Postfix。
  6. 投遞郵件:Postfix 使用 LMTP 協議,將郵件轉交給後端的 Dovecot 服務進行最終投遞。
  7. 保存內容:Dovecot 根據設定(還是要再向MySQL查詢或是根據快取的紀錄決定存檔路徑),將郵件寫入接收者 (username) 在磁碟上對應的郵箱目錄,完成收信。

流程二:你收信看信 (User Retrieval)

當你打開手機或電腦的 郵件客戶端 (Outlook/Thunderbird) 想看信時:

  1. 建立連接:郵件客戶端 (Client) 向伺服器的 Dovecot (IMAP/POP3 服務) 發起連接請求。
  2. 伺服器響應:Dovecot 回應握手信息 (Greeting),確認服務正常並準備進行會話。
  3. 發送帳密:客戶端發送帳號與密碼,請求登入並獲取郵件列表。
  4. 查詢路徑:Dovecot 連接 MySQL 資料庫,查詢該用戶的郵箱存放路徑與存取權限。
  5. 返回資訊:MySQL 確認用戶身分無誤,並回傳對應的磁碟路徑資訊。
  6. 讀取郵件:Dovecot 根據獲取的路徑,前往磁碟存儲 (Storage) 讀取實際的郵件檔案。
  7. 獲取內容:存儲系統將郵件的標頭與內文數據流回傳給 Dovecot。
  8. 傳送數據:Dovecot 將完整的郵件內容傳送給客戶端,用戶即可在軟體介面中閱讀郵件。

流程三:你寄信給別人 (Outgoing Mail)

這是最容易混淆的部分。當你要寄信時,雖然是透過 Postfix 寄出,但驗證工作卻是外包給 Dovecot 的(這稱為 SASL 認證):

  1. 連接伺服器:郵件客戶端 (Client) 向 Postfix 發起 SMTP 連接請求。
  2. 伺服器響應:Postfix 回應握手信息 (Greeting),準備建立會話。
  3. 傳送帳密:客戶端發送經過編碼的帳號與密碼以進行身分驗證。
  4. 請求驗證:Postfix 本身不儲存密碼,將認證請求轉交給後端的 Dovecot (SASL 服務)。
  5. 查詢帳號:Dovecot 連接 MySQL 資料庫,查詢該用戶的帳號是否存在與密碼是否正確。
  6. 返回結果:MySQL 將查詢與比對的結果回傳給 Dovecot。
  7. 認證通過:Dovecot 確認身分無誤後,通知 Postfix 驗證通過。
  8. 認證成功:Postfix 向客戶端回報登入成功 (Authentication successful),允許開始發信。
  9. 發送郵件:客戶端正式上傳編寫好的郵件內容(標頭與內文)。
  10. 轉發郵件:Postfix 接收郵件後,透過 SMTP 協議將其投遞至外部網絡 (Internet) 的對方郵箱伺服器。

小結:軟體職責分工表

看完上面三個流程,你可能會覺得有點眼花撩亂。沒關係,我們只要記住這三個軟體在團隊中的「職位」與「核心任務」即可:

Postfix, Dovecot, 與Mysql的功能

軟體名稱 角色代號 核心職責 詳細工作內容
Postfix 郵差 (MTA) 負責「傳送」與「接收」 它是對外的窗口。負責把信從網路收進來,或是把你的信送到對方的伺服器。它只管「運送」,不管「存儲」。
Dovecot 管家 (MDA) 負責「存庫」、「取信」與「驗身」 它是對內的管家。負責把 Postfix 收到的信寫入硬碟 (LMTP),也負責讓使用者用手機/電腦把信讀出來 (IMAP)。同時,它還負責幫 Postfix 檢查使用者的帳號密碼是否正確 (SASL)。
MySQL 名冊 (DB) 負責「記憶」資料 它是大腦記憶區。系統裡有哪些網域?有哪些使用者?密碼是什麼?別名要轉寄給誰?全部都記在這裡。Postfix 和 Dovecot 做決定前,都要先問過它。

3. 防火牆策略 (Security Group)

理解了上述三個流程後,我們就很清楚為什麼需要開啟以下 Port 了。請登入 AWS Console,在你的 EC2 Security Group 中設定以下「Inbound Rules (入站規則)」:

服務名稱 Port 協定 用途說明 對應流程
SSH 22 TCP 讓我們能遠端登入管理伺服器。 系統管理
SMTP 25 TCP (最重要) 讓網際網路上的其他伺服器能寄信給你。 流程一 (收信)
HTTP 80 TCP 用於申請 Let's Encrypt SSL 憑證驗證。 安全性設定
HTTPS 443 TCP 用於 SSL 憑證驗證。 安全性設定
IMAP 143 TCP 接收郵件標準協定 (無加密或 STARTTLS)。 流程二 (讀信)
IMAPS 993 TCP 接收郵件加密協定 (SSL/TLS)。 流程二 (讀信)
SMTP 587 TCP (Submission) 使用者寄信專用端口,強制加密。 流程三 (寄信)

第一章:架構規劃與環境準備

第二章:基礎建設篇——DNS、SSL 與資料庫

第三章:郵差的武裝——安裝 Postfix 並連接資料庫

第四章:安裝與設定 Dovecot (最後一塊拼圖)。

第五章:驗收時刻——全流程測試

第六章:設定 AWS SES Relay (讓信件使命必達)

Mail Server 征服指南 (三) 第二章:基礎建設篇——DNS、SSL 與資料庫

因為我們在同一台 EC2 上同時運行 Web 與 Mail 服務,這章的重點在於讓兩者和平共處。

1. DNS 設定 (A 與 MX)

請確保您的 DNS 紀錄包含以下兩者,並指向同一個 EC2 IP

類型名稱用途
A@ (mydomain.com)YourIP給網站用 (Web)
AmailYour IP給郵件主機用 (Hostname)
MX@mail.mydomain.com指定郵件由 mail 子網域負責

2. 設定系統 Hostname

我們將系統名稱設為 mail,以利 Postfix 識別。

sudo hostnamectl set-hostname mail.mydomain.com

編輯 /etc/hosts,在 127.0.0.1 localhost 下一行加入:


127.0.0.1 mail.mydomain.com mail

系統的hostname對於Mail server很重要,這會在後面設定Postfix的時候解釋,現在請直接照著設定。這個設定並不會影響任何其他正在運作的服務(如Nginx/Apache、DNS 等等),請安心修改。

3. 透過免費的Let’s Encrypt申請 SSL 憑證 (Webroot 模式)

因為您的 Nginx/Apache 正在佔用 Port 80,我們使用 Webroot 模式。這會請求 Web Server 幫忙驗證,而不需要暫停網站服務。

假設您的 Web Server 根目錄在 /var/www/html (請根據實際情況調整):

# 安裝 certbot
sudo apt update
sudo apt install certbot -y

# 申請憑證 (注意:這裡是申請 mail 子網域的證書)

sudo certbot certonly --webroot -w /var/www/html -d mail.mydomain.com

注意:如果您的網站已經有 SSL 了(例如 www.mydomain.com),這次申請是為了給 Mail Server 用的,所以我們特地申請 mail.mydomain.com。這兩個證書是分開的,互不影響。

如果申請成功,你會看到 Congratulations! 的訊息,並且憑證會存放在:

  • 公鑰 (Certificate): /etc/letsencrypt/live/mail.mydomain.com/fullchain.pem
  • 私鑰 (Private Key): /etc/letsencrypt/live/mail.mydomain.com/privkey.pem

記下這兩個路徑,我們在設定 Postfix 和 Dovecot 時會頻繁用到它們。

4. 安裝與初始化 MariaDB

最後,我們來建立儲存帳號密碼的資料庫。

安裝 MariaDB:

sudo apt install mariadb-server -y
sudo systemctl start mariadb
sudo systemctl enable mariadb

執行安全設定(設定 root 密碼):


sudo mysql_secure_installation

5. 建立郵件資料庫結構

我們不使用 Linux 系統帳號,而是用資料庫來管理「虛擬使用者」。 登入 SQL:

sudo mysql -u root -p

請依序輸入以下 SQL 指令(記得將 password 換成你自訂的強密碼):

-- 1. 建立資料庫
CREATE DATABASE mailserver;

-- 2. 建立郵件系統專用使用者 (mailuser)
CREATE USER 'mailserver'@'127.0.0.1' IDENTIFIED BY 'passwordyouchoose';

-- 3. 賦予查詢權限 (只給 SELECT,安全性更高)
GRANT SELECT ON mailserver.* TO 'mailserver'@'localhost';
FLUSH PRIVILEGES;

-- 4. 進入資料庫
USE servermail;

-- 5. 建立網域表 (Virtual Domains)
CREATE TABLE `virtual_domains` (
  `id` int(11) NOT NULL auto_increment,
  `name` varchar(50) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- 6. 建立使用者表 (Virtual Users)
CREATE TABLE `virtual_users` (
  `id` int(11) NOT NULL auto_increment,
  `domain_id` int(11) NOT NULL,
  `password` varchar(150) NOT NULL,
  `email` varchar(100) NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `email` (`email`),
  FOREIGN KEY (domain_id) REFERENCES virtual_domains(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- 7. 建立別名表 (Virtual Aliases)
CREATE TABLE `virtual_aliases` (
  `id` int(11) NOT NULL auto_increment,
  `domain_id` int(11) NOT NULL,
  `source` varchar(100) NOT NULL,
  `destination` varchar(100) NOT NULL,
  PRIMARY KEY (`id`),
  FOREIGN KEY (domain_id) REFERENCES virtual_domains(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

為了方便之後測試,我們先寫入一筆假資料(請換成你的網域):

-- 假設你的網域是 mydomain.com,密碼暫時用明碼 '123456'
INSERT INTO virtual_domains (id, name) VALUES (1, 'mydomain.com');
INSERT INTO virtual_users (id, domain_id, password, email) VALUES (1, 1,'123456','user@example.com');

輸入 exit 離開。


這樣一來,我們的基礎建設 (Infrastructure) 就全部完成了! 我們現在有了:

  • 正確的地址 (DNS & Hostname)
  • 安全的加密憑證 (SSL)
  • 儲存使用者的倉庫 (MariaDB)

第一章:架構規劃與環境準備

第二章:基礎建設篇——DNS、SSL 與資料庫

第三章:郵差的武裝——安裝 Postfix 並連接資料庫

第四章:安裝與設定 Dovecot (最後一塊拼圖)。

第五章:驗收時刻——全流程測試

第六章:設定 AWS SES Relay (讓信件使命必達)

Mail Server 征服指南 (四) 第三章:郵差的武裝——安裝 Postfix 並連接資料庫

我們已經準備好了身分證 (DNS/Hostname)、通行證 (SSL) 和大腦 (MariaDB)。現在,我們要請出負責收發信件的郵差——Postfix,並給它三張「藏寶圖」,讓它知道去資料庫的哪裡找人。

1. 安裝 Postfix 與 MySQL 驅動

首先,安裝 Postfix 主程式以及讓它能跟資料庫溝通的套件。

sudo apt update
sudo apt install postfix postfix-mysql -y

在安裝過程中,您會看到一個藍底灰字的設定畫面,請依序輸入:

  1. General type of mail configuration: 選擇 Internet Site
  2. System mail name: 輸入您的主網域 mydomain.com (注意:這裡填您信箱 @ 後面的名字,不要填 mail.mydomain.com)。

2. 製作三張「藏寶圖」 (SQL 連接設定)

Postfix 本身看不懂資料庫(SQL)結構,我們需要建立三個設定檔,告訴它 SQL 語句該怎麼寫。

先建立一個專用資料夾來存放這些機密檔案:

sudo mkdir -p /etc/postfix/mysql

接下來建立三個檔案(請記得將下方的 password 換成您在第二章設定的 mailserver 資料庫密碼):

地圖 A:查詢「我們負責哪些網域?」

sudo nano /etc/postfix/mysql/mysql-virtual-mailbox-domains.cf

貼上內容:

user = mailserver
password = password
hosts = 127.0.0.1
dbname = mailserver
query = SELECT 1 FROM virtual_domains WHERE name='%s'

地圖 B:查詢「這個使用者存在嗎?」

sudo nano /etc/postfix/mysql/mysql-virtual-mailbox-maps.cf

貼上內容:

user = mailserver
password = password
hosts = 127.0.0.1
dbname = mailserver
query = SELECT 1 FROM virtual_users WHERE email='%s'

地圖 C:查詢「這封信要轉寄嗎?」

sudo nano /etc/postfix/mysql/mysql-virtual-alias-maps.cf


貼上內容:

user = mailuser
password = password
hosts = 127.0.0.1
dbname = servermail
query = SELECT destination FROM virtual_aliases WHERE source='%s'

3. 保護檔案並測試連接 (關鍵步驟!)

因為檔案裡有密碼,我們必須鎖定權限。

sudo chmod 640 /etc/postfix/mysql/*
sudo chgrp postfix /etc/postfix/mysql/*

立即測試! 不要等到全部設完才測。我們用 postmap 指令測試 Postfix 能不能連上資料庫(假設您在第二章有寫入 example.com 的測試資料):

# 在這請用你剛剛在第二章測試資料庫時設定的網域和使用者
# 測試網域,example.com 
# (應回傳 1,如果什麼都沒回傳就是在資料庫沒查到example.com這筆資料,下面同理)
sudo postmap -q example.com mysql:/etc/postfix/mysql/mysql-virtual-mailbox-domains.cf

# 測試使用者 (應回傳 1)
sudo postmap -q user@example.com mysql:/etc/postfix/mysql/mysql-virtual-mailbox-maps.cf

如果這裡報錯(例如 Login failed),則是在連線到資料庫時出錯了,請回頭檢查在第二步中創建的 .cf檔案裡的帳號密碼是否正確。

4. 編輯主設定檔 main.cf

請跟著我一步步修改。為了避免混亂,我會將設定檔拆解成幾個模組來解釋。

備份舊設定:

sudo cp /etc/postfix/main.cf /etc/postfix/main.cf.bak

請打開設定檔:

sudo nano /etc/postfix/main.cf

這個檔案裡應該已經有一些預設內容。建議您註解掉(在前面加 #)或是直接刪除舊的內容,然後依照下面的區塊,將設定一塊一塊貼上或修改。

A. 身分識別 (Identity) —— 最容易錯的地方

# ==============================
# Postfix Main Configuration
# ==============================

# --- A. Identity (身分識別:郵差 vs. 收件人) ---

# 1. [郵差的名牌]:這台伺服器自己的名字
# 當它跟別的伺服器打招呼時,會說:「你好,我是郵差,我的名字是 mail.mydomain.com」
myhostname = mail.mydomain.com

# 2. [寄件來源]:從這台機器發出的信,信封上要蓋什麼章?
# 例如:系統排程通知信,會顯示來自 root@mydomain.com 
# (看起來像公司發的),而不是 root@mail...
myorigin = mydomain.com

# 3. 哪些信是「寄給郵差自己」的?(本機帳號的系統信件,如cron排程執行結果等等)
# 這是最關鍵的設定!
# 我們只留 localhost 與 mail.mydomain.com ($myhostname),
# 讓 Postfix 知道其他的都要去查 MySQL。
# 千萬「不能」把 mydomain.com 寫在這裡!
# 因為客戶的信 (user@mydomain.com) 不該留在郵差口袋,而是要放入「客戶信箱 (MySQL)」(下面的 Virtual 設定)。
mydestination = $myhostname, localhost.mydomain.com, localhost

!!教學的第二章中Hostname 設定正確的重要性

如果把 Mail Server 比喻成一位「國際外交官」,那 Hostname 就是他的「護照名字」

為什麼它這麼重要?主要有以下三個致命原因:

1. 為了不被當成騙子 (HELO/EHLO 與 rDNS 檢查)

這是最直接影響「信寄不寄得出去」的原因。

當您的伺服器 (Postfix) 連線到對方的伺服器 (例如 Gmail) 時,第一句話會進行自我介紹:

Postfix: “HELO/EHLO,我是 mail.mydomain.com

這時候,Gmail 不會輕易相信你,它會做一個 「雙重查核 (FCrDNS)」

  1. 查 IP:Gmail 會去查這個連線 IP 的 Reverse DNS (PTR 紀錄),看看這個 IP 註冊的名字是不是真的叫 mail.mydomain.com。(自家的網路要設定反查要找ISP 幫你設定,但是ISP通常不會幫你弄,所以這時AWS的優勢又體現出來了,你可以請AWS幫你設定IP反查)
  2. 比對:如果你的 Hostname 設成 localhost 或是 ubuntu-server,但 PTR 紀錄卻是 mail.mydomain.com
    • 結果:名字對不上!Gmail 會判定你在說謊(可能是殭屍電腦),直接拒收或丟垃圾桶。

結論: Hostname 必須跟你在 DNS (PTR) 上登記的名字一模一樣,才能取信於人。

2. 為了避免「精神分裂」 (Loop Prevention)

Postfix 需要清楚區分 「我」「我的客戶」

  • Hostname (我):例如 mail.mydomain.com。這是伺服器本身的名字(第二章設定的hostname以及/etc/hosts這個檔案),用來收系統通知(如 root@mail…)。
  • Virtual Domain (客戶):例如 mydomain.com。這是我們要服務的郵件網域。

如果 Hostname 設錯(設成跟網域一樣 mydestination = mydomain.com): 當有人寄信給 user@mydomain.com 時,Postfix 會看著自己的 Hostname 說:「咦?這不是寄給我自己的嗎?」 於是它不去查 MySQL(客戶名單),而是去查 Linux 本機帳號 (/etc/passwd)。 結果當然查不到 user 這個帳號,最後導致 “User unknown in local recipient table” 的錯誤。

結論: Hostname 必須是 Sub-domain (子網域),絕對不能跟 Email 主網域重疊,以確保路由邏輯清晰。

3. 為了產生合法的 Message-ID

每一封寄出去的信,都會有一個全球獨一無二的身分證號碼,叫做 Message-ID。這個號碼通常長這樣: 20251020.A1B2C3D4@mail.mydomain.com

注意到了嗎? @ 後面的部分就是由 Hostname 產生的。

  • 如果你 Hostname 沒設好(例如叫 localhost.localdomain),Message-ID 就會變成 @localhost
  • 這在嚴格的垃圾郵件過濾器(如 SpamAssassin)眼中,是一個非常大的扣分項目(Malformated Message-ID)。

總結

Hostname 對於 Mail Server 來說,不僅僅是一個代號,它是:

  1. 對外的誠信憑證(跟 IP 反解必須一致)。
  2. 對內的導航座標(區分本機與虛擬網域)。
  3. 信件的合格標章(產生正確的 Message-ID)。

所以,永遠記得把主機名稱設為 FQDN (完整網域名稱,如 mail.example.com),而不要只用 mailserver1 這種簡稱。Hostname的重要性介紹到這,接下來我們繼續postfix的設定教學。

B. 網路與連線 (Network)

這裡設定誰可以連線,以及我們監聽的介面。

# --- Network Settings ---
# 監聽所有介面 (包含外部連線)
inet_interfaces = all
# 只使用 IPv4 (為了避免 IPv6 設定不全導致的怪問題,建議新手先鎖定 IPv4)
inet_protocols = ipv4
# 信任的網路 (通常維持預設,只允許本機)
mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128

C. 虛擬使用者設定 (Virtual Settings) —— 連接 MySQL

這是讓 Postfix 去讀取我們上一節建立的那三個檔案。

# --- Virtual User Settings (MySQL) ---
# 1. 告訴 Postfix,這些網域是歸我們管的 (查 virtual_domains 表)
virtual_mailbox_domains = mysql:/etc/postfix/mysql/mysql-virtual-mailbox-domains.cf

# 2. 告訴 Postfix,這些使用者是存在的 (查 virtual_users 表)
virtual_mailbox_maps = mysql:/etc/postfix/mysql/mysql-virtual-mailbox-maps.cf

# 3. 告訴 Postfix,這些別名要轉寄 (查 virtual_aliases 表)
virtual_alias_maps = mysql:/etc/postfix/mysql/mysql-virtual-alias-maps.cf

# 4. 告訴 Postfix,信件收下來後,透過 LMTP 協定丟給 Dovecot 處理
# (注意:這一步需要等下一章安裝 Dovecot 後才會真正通,現在先設好)
virtual_transport = lmtp:unix:private/dovecot-lmtp

D. 安全性與加密 (TLS/SSL) —— 使用 Let’s Encrypt

請將路徑換成您在第二章申請到的實際路徑。

# --- TLS/SSL Settings ---
# 啟用 TLS
smtpd_tls_security_level = may
smtp_tls_security_level = may

# 指定憑證路徑 (請將 mail.mydomain.com 換成您的真實路徑)
smtpd_tls_cert_file = /etc/letsencrypt/live/mail.mydomain.com/fullchain.pem
smtpd_tls_key_file = /etc/letsencrypt/live/mail.mydomain.com/privkey.pem
smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache
smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache

# 強化安全性 (禁止匿名加密協定)
smtpd_tls_auth_only = yes

E. SASL 認證 (整合 Dovecot) —— 寄信驗證

這就是你收信/看信流程圖中,Postfix 轉身問 Dovecot「密碼對不對」的設定。

# --- SASL Authentication (Dovecot) ---
smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth
smtpd_sasl_auth_enable = yes

F. 基礎防護規則 (Restrictions) —— 第一層擋信

這裡設定誰可以透過我們寄信,以及我們要擋掉誰。

# --- Restrictions ---
smtpd_recipient_restrictions =
    permit_mynetworks,           # 允許本機 (127.0.0.1)
    permit_sasl_authenticated,   # 允許通過密碼驗證的使用者 (你)
    reject_unauth_destination    # 拒絕未經授權的轉寄 (防止變成 Open Relay)

存檔離開

5. 編輯 master.cf 開啟 Submission Port (587)

預設 Postfix 只開 Port 25。但現代的 Email Client (Outlook, iPhone Mail) 寄信時,標準是走 Port 587 (Submission)。我們需要把它打開。

sudo nano /etc/postfix/master


找到開頭是 submission 的那幾行(通常是被註解掉的),將前面的 # 拿掉,改成如下(注意縮排):

submission inet n       -       y       -       -       smtpd
  -o syslog_name=postfix/submission
  -o smtpd_tls_security_level=encrypt
  -o smtpd_sasl_auth_enable=yes
  -o smtpd_relay_restrictions=permit_sasl_authenticated,reject

(重點是開啟它,並強制 TLS 加密與 SASL 認證)

存檔離開。

6. 檢查與重啟

在重啟之前,我們先檢查設定檔語法有沒有寫錯:

sudo postfix check

如果不回傳任何訊息,代表語法正確。

接著重啟 Postfix 讓設定生效:

sudo systemctl restart postfix

4. 驗證成果:我們現在完成了什麼?

現在,您的 Postfix 已經具備了以下能力:

  1. 知道自己是誰 (mail.mydomain.com)。
  2. 知道要去哪裡查資料 (連接 MySQL)。
  3. 打開了收發信的大門 (Port 25 和 587)。

但是!現在還不能寄信,也不能收信。 為什麼?

  • 因為 Dovecot 還沒裝!
  • Postfix 設定檔裡的 private/auth (驗證密碼) 和 private/dovecot-lmtp (存信) 都是要連線給 Dovecot 的。現在這兩條線是斷的。

查看 Log 確認: 如果您現在去查看 Log:

Bash

tail -f /var/log/mail.log

您可能會看到類似 warning: connect to private/dovecot-lmtp: No such file or directory 的警告,這是完全正常的,因為我們還沒安裝 Dovecot。


這就是第三章的內容。我們已經把「郵差 (Postfix)」武裝好了,但他現在還缺一個「管家 (Dovecot)」來幫他管倉庫和查戶口。

第一章:架構規劃與環境準備

第二章:基礎建設篇——DNS、SSL 與資料庫

第三章:郵差的武裝——安裝 Postfix 並連接資料庫

第四章:安裝與設定 Dovecot (最後一塊拼圖)。

第五章:驗收時刻——全流程測試

第六章:設定 AWS SES Relay (讓信件使命必達)

Mail Server 征服指南 (五) 第四章:安裝與設定 Dovecot (最後一塊拼圖)。

這就是我們的最後一塊拼圖:Dovecot

如果說 Postfix 是在大門口負責收發信件的「郵差」,那 Dovecot 就是在屋內負責管理的「全能管家」。它有兩個核心任務:

  1. 驗收與倉儲 (LMTP/Mail Location):把郵差收進來的信,依照收件人分門別類,整齊地存進硬碟的資料夾裡。
  2. 身分驗證與取信 (Auth/IMAP):幫郵差查驗寄信人的密碼 (SASL),並讓主人(你)能透過手機或電腦把信取出來看。

讓我們開始安裝並設定這位管家吧!

1. 建立系統專用帳號 (vmail)

在安裝軟體前,我們需要先解決一個 Linux 的權限問題。 雖然我們的使用者是「虛擬」的(在資料庫裡),但信件最終還是要存成硬碟上的「檔案」。Linux 的檔案系統需要有一個真實的擁有者來管理這些檔案。

我們建立一個名為 vmail 的系統帳號,專門用來持有所有人的信件檔案:

# 建立群組 vmail (GID 5000)
sudo groupadd -g 5000 vmail

# 建立使用者 vmail (UID 5000),並指定它的家目錄在 /var/mail/vmail
sudo useradd -g vmail -u 5000 vmail -d /var/mail/vmail -m

2. 安裝 Dovecot 套件

我們需要安裝核心服務、IMAP 服務、LMTP 服務(接收 Postfix 轉交的信),以及 MySQL 驅動。

sudo apt update
sudo apt install dovecot-core dovecot-imapd dovecot-lmtpd dovecot-mysql -y

3. 設定資料庫連線 (dovecot-sql.conf.ext)

這一步是讓 Dovecot 能夠讀取我們在第二章建立的資料庫。

備份並建立設定檔:

sudo cp /etc/dovecot/dovecot-sql.conf.ext /etc/dovecot/dovecot-sql.conf.ext.bak
sudo nano /etc/dovecot/dovecot-sql.conf.ext

請清空內容,貼上以下設定(請記得修改 password):

driver = mysql
connect = host=127.0.0.1 dbname=mailserver user=mailserver password=password

# [密碼加密方式]
# 目前我們先用 PLAIN (明碼) 方便測試。
# 未來若要加密,這裡改成 SHA512-CRYPT (那資料庫裡的密碼也要換成加密字串)
default_pass_scheme = PLAIN

# [驗證查詢]:Dovecot 用這行來檢查帳號密碼是否正確
password_query = SELECT email as user, password FROM virtual_users WHERE email='%u';

# [使用者查詢]:驗證通過後,Dovecot 用這行知道信箱檔案要放在哪裡
# 這裡我們回傳了固定的 uid/gid (5000),以及動態的路徑 (domain/user)
user_query = SELECT 5000 as uid, 5000 as gid, 'maildir:/var/mail/vmail/%d/%n' as mail FROM virtual_users WHERE email='%u';

注意%d 代表網域 (mydomain.com),%n 代表使用者名稱 (user)。所以信件會存在 /var/mail/vmail/mydomain.com/user/ 裡面,結構非常清晰。

修改權限(保護密碼):

sudo chgrp dovecot /etc/dovecot/dovecot-sql.conf.ext
sudo chmod 640 /etc/dovecot/dovecot-sql.conf.ext

4. 設定 Dovecot 核心模組

Dovecot 的設定檔分散在 /etc/dovecot/conf.d/ 裡。我們需要修改其中的四個檔案。

A. 修改 10-auth.conf (啟用 SQL 認證)

sudo nano /etc/dovecot/conf.d/10-auth.conf


  • 找到 disable_plaintext_auth,確認它是 no (或是註解掉),因為我們之後會強制用 SSL,所以這裡設 no 沒關係,方便除錯。
  • 找到 auth_mechanisms,修改為:auth_mechanisms = plain login
  • 註解掉 (加上 #):!include auth-system.conf.ext (我們不用 Linux 系統帳號)
  • 取消註解 (拿掉 #):!include auth-sql.conf.ext (我們要用 SQL)

B. 修改 10-mail.conf (設定信箱位置)

sudo nano /etc/dovecot/conf.d/10-mail.conf


  • 找到 mail_location,修改為:
mail_location = maildir:/var/mail/vmail/%d/%n

  • 找到 mail_uidmail_gid,修改為我們剛建的 vmail 帳號 ID:
mail_uid = 5000 mail_gid = 5000


C. 修改 10-master.conf (打開與 Postfix 的溝通大門) 這是最重要的一步!

這裡定義了 Postfix 第三章設定檔裡寫的 private/authprivate/dovecot-lmtp 是什麼。

sudo nano /etc/dovecot/conf.d/10-master.conf

請找到 service lmtpservice auth 區塊,修改成下面這樣(小心大括號的位置):

# 1. 讓 Postfix 把信塞進來的接口 (LMTP)
service lmtp {
  unix_listener /var/spool/postfix/private/dovecot-lmtp {
    mode = 0600
    user = postfix
    group = postfix
  }
}

# 2. 讓 Postfix 來問密碼的接口 (Auth)
service auth {
  # 給 Postfix 用的 (SMTP Auth)
  unix_listener /var/spool/postfix/private/auth {
    mode = 0666
    user = postfix
    group = postfix
  }
  
  # 給 Dovecot 自己用的
  unix_listener auth-userdb {
    mode = 0600
    user = vmail
  }
  user = dovecot
}

D. 修改 10-ssl.conf (掛載 Let’s Encrypt)

sudo nano /etc/dovecot/conf.d/10-ssl.conf
  • 找到 ssl,確認是 yesrequired
  • 修改憑證路徑(換成你的真實路徑):
ssl_cert = </etc/letsencrypt/live/mail.mydomain.com/fullchain.pem 
ssl_key = </etc/letsencrypt/live/mail.mydomain.com/privkey.pem

5. 權限修正與啟動

我們需要告訴 Dovecot 它的 SQL 設定檔在哪裡(因為我們剛剛是在 conf.d/10-auth.conf 裡 include 了 auth-sql.conf.ext,我們要去編輯那個檔案指向我們的 dovecot-sql.conf.ext)。

更簡單的做法,直接編輯 /etc/dovecot/conf.d/auth-sql.conf.ext

sudo nano /etc/dovecot/conf.d/auth-sql.conf.ext

確保內容如下:

passdb {
  driver = sql
  args = /etc/dovecot/dovecot-sql.conf.ext
}
userdb {
  driver = sql
  args = /etc/dovecot/dovecot-sql.conf.ext
}

最後,重啟 Dovecot 並檢查狀態:

sudo systemctl restart dovecot
sudo systemctl status dovecot

如果看到綠色的 active (running),恭喜你!所有安裝步驟已全部完成!

最後我們將要進入驗收環節!

第一章:架構規劃與環境準備

第二章:基礎建設篇——DNS、SSL 與資料庫

第三章:郵差的武裝——安裝 Postfix 並連接資料庫

第四章:安裝與設定 Dovecot (最後一塊拼圖)。

第五章:驗收時刻——全流程測試

第六章:設定 AWS SES Relay (讓信件使命必達)

Mail Server 征服指南 (六) 第五章:驗收時刻——全流程測試

我們辛苦搭建的郵件伺服器即將迎來第一次實戰測試。

在這個章節,我們不只要看「結果」,更要學會看「過程」。我會教您如何用「駭客視角」(直接下指令)來測試伺服器,這能讓您清楚看到每一個環節是否正常運作。

第一階段:功能連通性測試 (使用明碼)

在這個階段,您的資料庫密碼應該是明碼的 123456,且 Dovecot 設定為 default_pass_scheme = PLAIN

1. 測試收信 (Telnet 模擬) 我們假裝自己是外部郵件主機,直接投遞信件。 在 視窗 B 輸入:

telnet localhost 25


依序輸入(注意:若打錯字請按 Enter 重來,不能按 Backspace):

EHLO gmail.com
MAIL FROM:<test@gmail.com>
RCPT TO:<user@mydomain.com>
DATA
Subject: Test 1 (Plaintext)

Hello, this is a test.
.
QUIT

驗收:看視窗 A,出現 saved mail to maildir:... 代表寫入成功。

2. 測試讀信 (IMAP) 打開您的手機或電腦郵件軟體 (Thunderbird/Outlook):

  • Protocol: IMAP
  • Email: user@mydomain.com
  • Hostname (Incoming): mail.mydomain.com
  • Port: 993 (SSL/TLS)
  • Username: user@mydomain.com (務必填完整 Email)
  • Password: 123456 (您在資料庫設定的密碼)

驗收:應該能成功登入,並看到剛剛那封 “Test 1″。

3. 測試寄信 (SMTP) 使用剛剛設定好的軟體寄一封信給您自己的 Gmail。

  • Protocol: SMTP
  • Hostname (Outgoing): mail.mydomain.com
  • Port: 587 (STARTTLS) —— 這裡很重要,不要選 25 或 465
  • Authentication: Normal Password (或 Plain)
  • Username: user@mydomain.com

驗收:視窗 A 出現 sasl_method=PLAIN, sasl_username=...status=sent (或是 AWS 逾時),只要沒出現 Access denied 就算成功。


第二階段:安全性升級 (啟用密碼加密)

確認系統能跑後,我們要來修補最大的安全漏洞:資料庫裡的明碼密碼

1. 產生加密密碼 我們使用 Dovecot 內建工具,產生強大的 SHA512-CRYPT 雜湊值。 在終端機輸入:

doveadm pw -s SHA512-CRYPT


  • 輸入兩次您的密碼 (例如 123456)。
  • 複製回傳的那串亂碼,例如:{SHA512-CRYPT}$6$xyz...

2. 更新資料庫 登入 MySQL,把這串亂碼存進去。

sudo mysql -u root -p servermail


— 請把下面那一長串換成你剛剛生成的亂碼


UPDATE virtual_users 
SET password = '{SHA512-CRYPT}$6$xyz...' 
WHERE email = 'user@mydomain.com';

離開資料庫 (exit)。

3. 修改 Dovecot 設定 告訴 Dovecot:「從現在開始,資料庫給你的不再是明碼,而是 SHA512 加密過的字串。」

編輯檔案:

sudo nano /etc/dovecot/dovecot-sql.conf.ext



將原本的 PLAIN 改掉:

# default_pass_scheme = PLAIN  <-- 註解或刪掉這行
default_pass_scheme = SHA512-CRYPT

4. 重啟 Dovecot

sudo systemctl restart dovecot


第三階段:最終驗收 (加密後測試)

現在,雖然您的密碼還是 123456,但在伺服器內部,它已經不再以明碼形式儲存了。我們必須確認 Dovecot 能正確解讀這串亂碼。

1. 再次測試收信 (IMAP)

  • 動作:在您的郵件軟體中,按一下「接收/傳送」或是重新登入。
  • 觀察
    • 如果成功:代表 Dovecot 成功將您輸入的 123456 加密後,跟資料庫裡的 $6$... 比對吻合。
    • 如果失敗 (Authentication failed):代表加密演算法沒對上 (例如您產生了 BLF-CRYPT 但設定檔寫 SHA512-CRYPT),或是複製時少複製了字元。

2. 再次測試寄信 (SMTP)

  • 動作:再寄一封信給 Gmail,主旨寫 “Test 2 (Encrypted DB)”。
  • 觀察:確認信件能順利寄出。

恭喜!您已完成正式部署

如果第三階段測試通過,您的 Mail Server 就已經達到 Production (生產環境) 的安全標準了:

  1. 傳輸加密:全程使用 TLS/SSL。
  2. 儲存加密:資料庫密碼使用 SHA512 雜湊保護。
  3. 身分驗證:收發信皆需帳號密碼。

現在這台機器已經固若金湯。下一步,我們要解決的是**「信寄出去會被當垃圾信」**的問題,這就需要 設定 AWS SES Relay (寄信中繼) 來幫忙了。

第一章:架構規劃與環境準備

第二章:基礎建設篇——DNS、SSL 與資料庫

第三章:郵差的武裝——安裝 Postfix 並連接資料庫

第四章:安裝與設定 Dovecot (最後一塊拼圖)。

第五章:驗收時刻——全流程測試

第六章:設定 AWS SES Relay (讓信件使命必達)

Mail Server 征服指南 (七) 第六章:設定 AWS SES Relay (讓信件使命必達)

你可以把 Email 寄送的過程想像成**「古代送信」,而 SMTP(寄信協定)本身設計得非常老舊且沒有安全感,就像一個毫無防備的郵差**。

為什麼 Gmail、Outlook 會把你的信當垃圾信?核心原因只有一個:「身分不明,缺乏信任」。

以下是用最白話的方式解釋這「三大護法」加上「黑名單」的運作邏輯:


1. 根本原因:SMTP 的天生缺陷

SMTP 協定在幾十年前發明時,並沒有設計「驗證身分」的功能。

這意味著,任何人都可以躲在暗巷裡,寫一封信,然後在信封寄件人(From)填上 president@whitehouse.gov。郵差(SMTP)根本看不出來這是假的,照樣幫你送。

為了防止這種「冒名頂替」,現代郵件系統發展出了三道檢查關卡:

2. 第一關:SPF (Sender Policy Framework) —— 「警衛與訪客名單」

  • 概念:這是一份白名單
  • 運作:Gmail 收到你的信時,會去查你的 DNS(警衛室)問:「請問 IP 1.2.3.4 (這位郵差) 有資格代表 mydomain.com 送信嗎?」
    • 如果沒有 SPF:Gmail 覺得這個郵差是隨便路過的,可疑 –> 垃圾信
    • 如果有 SPF:確認這是在名單上的合法郵差 –> 通過

3. 第二關:DKIM (DomainKeys Identified Mail) —— 「完整的蠟封」

  • 概念:這是一個數位簽名(防偽標籤)
  • 運作:就算郵差是對的,信件內容有沒有在半路被駭客竄改過?或者這是不是別人偽造了你的信頭?DKIM 就像是在信封口蓋了一個**「獨一無二的火漆蠟封」**(私鑰加密)。
    • 沒有 DKIM:Gmail 收到信,發現信封沒封口,誰都能塞廣告進去 –> 垃圾信
    • 有 DKIM:Gmail 用你的公鑰檢查蠟封,發現完好無損 –> 確認是原廠出品,內容未被竄改

4. 第三關:DMARC —— 「老闆的指令」

  • 概念:這是一本指導手冊
  • 運作:如果有駭客偽造了你的信,導致 SPF 或 DKIM 檢查失敗了,Gmail 該怎麼辦?是直接丟掉?還是放進垃圾桶?還是通知你?DMARC 就是你(網域擁有者)告訴 Gmail:「如果有人冒充我(驗證失敗),請直接把它拒絕(Reject)!」
    • 沒有 DMARC:Gmail 雖然抓到了假信,但不知道怎麼處理,可能會為了怕誤判而勉強收下,但也降低了你網域的權威性。

5. 隱藏大魔王:IP 信譽 (IP Reputation) —— 「前科紀錄」

就算你上述三種證件都齊全了,為什麼還會進垃圾桶?

  • 原因:因為送信的那個 IP 位址(例如 AWS EC2 的 IP)可能有**「前科」**。
  • 情境:如果上一位租用這個 IP 的人是用來發送百萬封詐騙信的,這個 IP 就會在國際反垃圾組織(如 Spamhaus)的黑名單上。
  • 結果:Gmail 一看:「喔,這個 IP 是個慣犯!」不管你的證件多齊全,直接拒收。

總結

這就是為什麼我們要用 AWS SES

  1. 解決 IP 前科:Amazon 會維護 IP 的清潔度,確保它們不在黑名單上。
  2. 解決 SPF/DKIM:讓 Gmail 相信**「這封信真的是你寄的,而且你授權了 Amazon 幫你跑腿」。

下面讓我們詳細講述設定的流程

1. AWS SES 前置作業 (在 AWS Console 操作)

這部分需要在 AWS 網頁介面上完成,請確保您選對了 Region (區域)(選有支援 SES 的區域)。

A1. 驗證網域 (Verify Domain)

  1. 進入 SES Console -> Configuration -> Identities
  2. 點擊 Create identity -> 選擇 Domain
  3. 輸入您的網域 mydomain.com
  4. Publish DNS records to Route53: 請「不要」勾選此選項(保持未勾選狀態,除非您用Route53 管理您的網域)。
  5. Advanced DKIM settings: 選擇 Easy DKIM (預設值)。
  6. DKIM signing key length: 選擇 RSA_2048_BIT (比較通用) 或 1024 都可以。
  7. 點擊 Create identity

A2. 獲取 CNAME 紀錄 (DKIM)

建立完成後,畫面會跳轉到該網域的詳細資訊頁面。往下滑,您會看到一個 「DKIM DNS records」 的區塊。

這裡會有 3 組 CNAME 紀錄。AWS 會給您兩個欄位:

  • Name (主機名稱 / Host)
  • Value (內容 / Target)

A3. 到您的 DNS 託管商新增紀錄

現在,請開另一個分頁,登入您的 DNS 管理後台。

您需要將那 3 組 CNAME 逐一新增進去。

⚠️ 超級重要的陷阱 (請務必注意)

大多數 DNS 託管商(如 Cloudflare, GoDaddy)在輸入「Name (Host)」時,會自動幫您補上網域後綴

  • AWS 顯示的 Nameabcde12345._domainkey.mydomain.com
  • 您在 DNS 後台只需輸入abcde12345._domainkey

如果您把整串貼上去,就會變成 ...mydomain.com.mydomain.com,導致驗證失敗!


A4. 除了 CNAME,別忘了 SPF (重要!)

因為您要透過 AWS SES 寄信,您必須在 DNS 告訴全世界:「AWS SES 是我授權的寄件人」。

請在您的 DNS 後台檢查 TXT 紀錄 (SPF)

  • 如果本來沒有 SPF 紀錄: 新增一條 TXT 紀錄:
    • Host/Name: @
    • Value: v=spf1 include:amazonses.com ~all
  • 如果原本已經有 SPF 紀錄 (例如原本是設給 EC2 本機寄信): 請修改原本那條紀錄,把 AWS SES 加進去。
    • 舊的可能長這樣:v=spf1 mx ip4:1.2.3.4 ~all
    • 修改後v=spf1 mx ip4:1.2.3.4 include:amazonses.com ~all

(重點就是一定要出現 include:amazonses.com 這段文字)

設定完後,通常等待 5 分鐘到 1 小時,回到 AWS SES Console 重新整理頁面,當 Status 變成綠色的 Verified,就代表成功了!如果沒成功,請檢查你輸入的DNS資訊是否正確,任何微小的錯誤都會導致驗證失敗

B. 申請移出沙盒 (Production Access) 剛開通的 SES 處於「沙盒模式 (Sandbox)」,只能寄信給「已經驗證過」的 Email。您必須申請移出沙盒才能寄給外面的陌生人。

  1. 在 SES Console 首頁上方會看到一個藍色警告條。
  2. 點擊 Request production access
  3. 填寫用途(用英文寫:My mail server is for personal business communication, not for marketing spam…)。
  4. 通常需要等待數小時到一天審核。

C. 取得 SMTP 帳號密碼 (關鍵!) 注意:這不是您登入 AWS 的 IAM 帳號,這是 SES 專用的。

  1. 進入 SES Console -> SMTP Settings
  2. 記下 SMTP Endpoint (例如:email-smtp.us-east-1.amazonaws.com)。
  3. 點擊 Create SMTP credentials
  4. AWS 會產生一組 IAM User NameSmtp UsernameSmtp Password
  5. 請務必下載 CSV 或複製下來! 這個長得很像亂碼的密碼只會顯示這一次。

2. 安裝 SASL 相依套件

Postfix 需要這個套件才能拿著帳號密碼去向 AWS SES 登入。

sudo apt update
sudo apt install libsasl2-modules postfix-pcre -y

3. 設定 Postfix 指定 Relay Host

我們要修改 main.cf,告訴 Postfix:「以後寄給外部的信,不要自己送,全部轉交給 AWS SES。」

開啟設定檔:

sudo nano /etc/postfix/main.cf


請找到 relayhost 這一行(預設可能是空的),並在檔案的最下方加入/修改以下設定區塊:

# ==============================
# AWS SES Relay Configuration
# ==============================

# 1. 指定 AWS SES 的伺服器 (請換成您在步驟 1-C 看到的 Endpoint)
# 注意:要把網址用中括號 [] 包起來,並指定 :587
# 中括號的意思是「不要查 MX 紀錄,直接連線」,這能加速連線
relayhost = [email-smtp.us-east-1.amazonaws.com]:587

# 2. 啟用 SASL 認證 (Postfix 作為客戶端向 SES 登入)
smtp_sasl_auth_enable = yes
smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd
smtp_sasl_security_options = noanonymous
smtp_sasl_mechanism_filter = login

# 3. 強制使用 TLS 加密 (AWS 要求一定要加密)
smtp_use_tls = yes
smtp_tls_security_level = encrypt
smtp_tls_note_starttls_offer = yes

# 4. 指定 CA 憑證位置 (確保能驗證 AWS 的 SSL 憑證)
smtp_tls_CAfile = /etc/ssl/certs/ca-certificates.crt

存檔離開。


4. 建立密碼檔 (sasl_passwd)

我們要把剛剛從 AWS 拿到的 SMTP 帳號密碼寫入檔案。

建立新檔案:

sudo nano /etc/postfix/sasl_passwd


貼上以下內容(請替換成您自己的資料): 格式:[Endpoint]:587 Username:Password

[email-smtp.us-east-1.amazonaws.com]:587 AKIAIOSFODNN7EXAMPLE:AgGbq...VERY...LONG...PASSWORD...

(注意:前面的 Endpoint 也要加上中括號 [],必須跟 main.cf 裡寫的一模一樣)

存檔離開。


5. 雜湊密碼並保護檔案

這個檔案裡有明碼密碼,非常危險,我們要把權限鎖死,並轉換成 Postfix 讀得懂的 hash 檔。

# 1. 轉換成資料庫格式 (會產生 sasl_passwd.db)
sudo postmap hash:/etc/postfix/sasl_passwd

# 2. 將檔案的所屬群組改為 postfix (這樣 postfix 才有資格讀)
sudo chgrp postfix /etc/postfix/sasl_passwd /etc/postfix/sasl_passwd.db

# 4. 移除明碼檔案 (或是移到安全的地方備份)
# 這裡我們先改權限讓 root能讀寫 postfix能讀,確保安全
sudo chmod 0640 /etc/postfix/sasl_passwd /etc/postfix/sasl_passwd.db

# 3. 重啟 Postfix
sudo systemctl restart postfix

6. 最終驗收:寄信到 Gmail

現在,請再次打開您的郵件軟體(手機或電腦),透過您的 Mail Server 寄一封信給您的 Gmail。

觀察重點:

  1. 檢查 Log (/var/log/mail.log): 您應該會看到類似這樣的訊息: status=sent (250 Ok ...) 且會顯示連線到 email-smtp.us-east-1.amazonaws.com
  2. 檢查 Gmail 收件匣: 打開收到的信,點擊「顯示原始郵件 (Show Original)」。
    • SPF: PASS
    • DKIM: PASS (如果您在 AWS 有開啟 DKIM)
    • DMARC: PASS (如果您 DNS 有設對)
    • Encryption: Standard encryption (TLS)

如果 Log 顯示 Authentication failed

  • 檢查 sasl_passwd 裡的帳號密碼是否填錯(是 SMTP 帳號,不是 IAM 帳號)。
  • 檢查 relayhostsasl_passwd 裡的中括號 [] 是否一致。
  • 記得每次改完 sasl_passwd 都要執行 sudo postmap hash:/etc/postfix/sasl_passwd

全系列總結

恭喜您!經過這長途跋涉,您已經完成了一項許多工程師都覺得頭痛的任務。

您現在擁有一台:

  • 獨立自主 的郵件伺服器 (Linux + Postfix + Dovecot)。
  • 資料庫管理 的虛擬帳號系統 (MariaDB + SHA512)。
  • 企業級 的傳輸安全性 (TLS + Let’s Encrypt)。
  • 高信譽 的寄信通道 (AWS SES)。

現在,您可以自由地開設無限個 Email 帳號,掌控自己的數據,並享受自架服務的樂趣了!另外特別推薦使用Roundcube webmail作為你的Webmail解決方案,這個老牌的Webmail解決方案不但更新頻繁,還有強大的社群以及外掛程式(例如兩步驟驗證2FA等等),絕對值得您一試!

第一章:架構規劃與環境準備

第二章:基礎建設篇——DNS、SSL 與資料庫

第三章:郵差的武裝——安裝 Postfix 並連接資料庫

第四章:安裝與設定 Dovecot (最後一塊拼圖)。

第五章:驗收時刻——全流程測試

第六章:設定 AWS SES Relay (讓信件使命必達)

比立法院杯葛更可怕的核彈:如果總統決定「不補人」?

最近憲法法庭做出的**【114年憲判字第1號】**判決,宣告在野黨試圖提高判決門檻的修法違憲。大法官的理由很明確:不能讓司法權因為人數不足而「被迫停擺」。目前大法官僅剩 8 人,若任由立法院調高門檻,憲法法庭將實質關門。

然而,大眾目前的焦點都鎖定在「藍白立委惡意杯葛」與「執政黨名單不佳」的互踢皮球上。大家似乎忽略了另一個更深層、更恐怖的憲政災難劇本——如果總統決定「不再提名」呢?

現任8位大法官並非同時卸任,其中4位將於 2027年 離開,剩下4位則要撐到 2031年。這意味著,如果朝野持續互不相讓,甚至總統為了政治算計刻意「不再提名」,台灣的憲法法庭將經歷長達六年的「慢性死亡」。先是2027年剩下4人的苟延殘喘,到了2031年將正式進入**「大法官歸零」**的憲政真空。

這不僅是司法癱瘓,更是一場獨裁者的豪賭。一旦2031年大法官人數歸零,最荒謬的後果將降臨:總統獲得「免死金牌」。依憲法規定,總統彈劾案需由憲法法庭審理,沒有大法官,彈劾程序就無法完成。

屆時,總統即便違憲亂政,立法院也無力讓他下台。立法院現在的杯葛只是讓司法貧血,但若逼得(或誘使)總統採取「歸零戰術」,那將是親手埋葬制衡機制,迎來實質獨裁。

Solution for Low Memory on Small Servers: Configuring Swap Space on AWS EC2

As a self-hosting enthusiast, I enjoy deploying various web services for personal use. On a single AWS EC2 instance, I’ve hosted multiple services including Nextcloud, WordPress, Postfix, Dovecot, MariaDB, and Nginx.

However, with only 1GB of RAM, I frequently encountered MariaDB database crashes due to “Out of Memory” (OOM) errors. To address this, setting up Swap Space is an effective solution to significantly reduce service interruptions. While using a hard drive for Swap may slightly decrease caching performance, the trade-off is well worth it for personal use—exchanging a bit of speed for continuous service availability.


Step 1: Prepare the Disk Volume in AWS Console

Before configuring the OS, you need to provide the physical storage:

  1. Go to the AWS EC2 Console.
  2. Create a new EBS Volume. I recommend setting the size to twice your RAM (e.g., 2GB for a 1GB instance).
  3. Attach this volume to your instance.

Step 2: Identify the New Partition

Connect to your server via SSH and use the following command to identify your new block device:

lsblk

In my case, nvme0n1 is the new partition designated for SWAP. You should see your newly added storage partition listed in the output.

Step 3: Format and Enable Swap

Once you have identified the device name, execute the following commands to format it as swap space and activate it:

# Format the partition as swap
sudo mkswap /dev/nvme0n1

# Enable the swap space
sudo swapon /dev/nvme0n1

Verification

To confirm it is working, run lsblk again. If you see [SWAP] under the MOUNTPOINTS column, it means the partition is successfully attached.

You can also use the top command to monitor the swap usage in real-time:

top

Step 4: Configure Persistent Mount (Auto-mount on Boot)

To ensure the swap remains active after a reboot, you must add it to the file system table (/etc/fstab). It is best practice to use the UUID for stability.

  1. Find the UUID of your swap partition:
    sudo blkid
    Locate your partition (e.g., /dev/nvme0n1) and copy the UUID string.

  2. Edit the fstab file:
    sudo nano /etc/fstab
  3. Add the following line at the end of the file:
    UUID="YOUR-UUID-HERE" none swap sw 0 0

    Note: Replace YOUR-UUID-HERE with your actual UUID. Be careful with this step, as errors in this file can cause boot issues.

  4. Press Ctrl + X, then Y, and Enter to save and exit.

Conclusion

By adding a simple 2GB swap partition, your small AWS instance can handle memory spikes much more gracefully. No more worrying about MariaDB crashing in the middle of the night!

拆毀隔斷的牆:從羅馬書二、三章看合一與救恩

要讀懂羅馬書,不能忽略它獨特的寫作背景。當時的羅馬教會正面臨分裂的危機:猶太基督徒在被皇帝驅逐又回歸後,與留守的外邦信徒在文化和律法觀點上產生了劇烈衝突,雙方互相看不慣、彼此論斷。保羅寫這封信,正是為了要在真理中消除這種隔閡,將分裂的群體重新帶回基督裡的合一。

帶著這個視角進入第二、三章,我發現保羅對「論斷」的嚴厲責備,不單是道德教導,更是對教會衝突的當頭棒喝。他指出神不偏待人,無論是自認擁有律法優越感的猶太人,或是被視為不潔的外邦人,在神公義的審判台前,誰都沒有特權。

第三章宣告「世人都犯了罪,虧缺了神的榮耀」,這句話徹底粉碎了人與人之間比較的基礎。既然在神面前大家都是無法自救的罪人,誰又有資格輕看誰呢?這讓我深刻體會到,「因信稱義」不僅是個人得救的途徑,更是群體和好的關鍵。既然我們都是單單仰賴耶穌的寶血才得以稱義,這份白白的恩典,就應當成為我們彼此接納、而非互相排斥的理由。