一直以來
筆者的收信都是透過 Cloudflare 的 Email 轉發功能
將送來的信件轉發到自己的 Gmail 信箱
然而這個服務只能轉發收信 而不能發信
於是筆者決定在自己的伺服器上架設一個 MailServer
來一勞永逸的解決這個問題
事情總是想得很簡單
在我開始架設之前 看著各種教學文
以及官方寫得看起來很清楚的文檔
我以為事情會非常順利的進行下去
但實際上等待我的卻是一個又一個大坑
# 前提
在開始之前 先確認一下自己手邊的環境
# 環境
- 系統: Ubuntu 22.04
- Webserver: Nginx/1.26.1
- UFW: ufw/0.36.1
- DNS: Cloudflare
- SSL: acme.sh
# 需求
使用 docker 架設一個 MailServer
# 前置準備
在開始前我們需要先搞好一些前置的設定
# Router Port Forwarding
首先 如果你是自己家的伺服器 或是你有網管權限
請先確認你的路由器有將以下的 port 打開
ports: | |
- "25:25" # SMTP (explicit TLS => STARTTLS, Authentication is DISABLED => use port 465/587 instead) | |
- "110:110" # POP3 (explicit TLS => STARTTLS) | |
- "143:143" # IMAP4 (explicit TLS => STARTTLS) | |
- "465:465" # ESMTP (implicit TLS) | |
- "587:587" # ESMTP (explicit TLS => STARTTLS) | |
- "993:993" # IMAP4 (implicit TLS) | |
- "995:995" # POP3 (implicit TLS) |
請務必要確定 port 是開的
筆者搞這個搞了兩天就是卡在 port 打不出去 ==
# DNS
接下來我們需要設定 DNS
由於我是使用 cloudflare 的 DNS
如果你沒有用 CF 家的服務而是使用網域商提供的 DNS 服務的話
那請自己變通一下
我們需要設定幾個紀錄
- A 紀錄:這個應該大家都會設定,不如你的網址根本連不到伺服器
- [mail.]example.com -> 你的伺服器 IP
- MX 紀錄:指定信件要導去哪裡
- example.com -> [mail.]example.com
- TXT 紀錄:
- example.com -> v=spf1 ip4: 你的伺服器 IP -all
- PTR 紀錄:做 rDNS 反向解析用的,可以從 IP 反向解析到 domain,這個是為了避免被標記為垃圾郵件
- 你的伺服器 IP -> [mail.]example.com
這邊的 example.com 請自行替換成你自己的網域,當然有引號的部分也可以選用 subdomain
例如 mail.example.com,只是筆者想要用主網域因此沒有選用
❯ dig +short TXT miyago9267.com | |
"google-site-verification=eWCbTPIIpTueaDXP5h1AjIB83xZTKmMAfgsSL9IgGs8" | |
"v=spf1 a mx ip4:我的IP -all" | |
❯ dig +short MX miyago9267.com | |
10 miyago9267.com. | |
❯ dig +short A miyago9267.com | |
我的IP |
IP 不給你看勒 ><(雖然你自己去戳就會寫了)
# 防火牆
確定你的防火牆有開放上面那些 port
如果你有加裝 ufw-docker
的話也要記得開
# Docker MailServer
確定好手邊的資源以及確定要做什麼了
接下來就是開始架設 MailServer 了
我們使用的是現成的 Docker 專案 Docker MailServer
# 部屬 docker container
我們不需要 clone 整個專案
需要用到的只有
compose.yaml
mailserver.env
setup.sh
(選擇性)
這三個檔案而已
DMS_GITHUB_URL="https://raw.githubusercontent.com/docker-mailserver/docker-mailserver/master" | |
curl -LO "${DMS_GITHUB_URL}/compose.yaml" && mv compose.yaml docker-compose.yaml | |
curl -LO "${DMS_GITHUB_URL}/mailserver.env" |
# 編輯 mailserver.env
正常來說我們需要修改的地方只有這幾個
OVERRIDE_HOSTNAME=mail.example.com
ENABLE_POP3=1 <- 這行預設好樣找不到要自己加
# 編輯 docker-compose.yaml
docker-compose.yaml
裡面要動的東西比較多
我們一個一個來確認
hostname: miyago9267.com # 修改成你的網域 | |
# 以下的 PORT 全部都要打出來 不然會有問題 | |
ports: | |
- "25:25" # SMTP (explicit TLS => STARTTLS, Authentication is DISABLED => use port 465/587 instead) | |
- "110:110" # POP3 (explicit TLS => STARTTLS) | |
- "143:143" # IMAP4 (explicit TLS => STARTTLS) | |
- "465:465" # ESMTP (implicit TLS) | |
- "587:587" # ESMTP (explicit TLS => STARTTLS) | |
- "993:993" # IMAP4 (implicit TLS) | |
- "995:995" # POP3 (implicit TLS) | |
# 在 volumes 裡面加上你的 SSL 證書映射的位置 我是放在 /etc/nginx/certs 裡面 | |
# 請一定要記得自己「映射在容器內」的位置 之後在容器內設定是用那個路徑 | |
volumes: | |
- /etc/nginx/certs/miyago9267.com/:/etc/nginx/certs/miyago9267.com:ro |
# 啟動
確認無誤後就可以啟動 stack 了
docker compose up -d # 我看有教學說測試階段不要用 - d,但我覺得沒差,看 log 就好 |
# 創建帳號
# 建立一個新的 admin 使用者 你可以有你自己的 但 admin 建議要有 | |
docker exec -it mailserver setup email add admin@example.com "password" | |
# 建立一個新的 postmaster 使用者 | |
# 這個 postmaster 是用來接收系統的通知信件 沒有的話可能會噴錯 | |
docker exec -it mailserver setup alias add postmaster@example.com admin@example.com |
# 安全性設定
# DKIM
DKIM 是一種防止郵件被偽造的驗證技術
可以將信件的標頭和內文都進行加密以及生成數位簽章
我們可以在 dns 設定裡面加入這個
而 docker mailserver 裡有預設提供 opendkim 來進行金鑰的生成
docker exec -it mailserver setup config dkim |
由於我們在啟動 docker-compose 之前已經映射過路徑了
我們只需要進到 ./docker-data/dms/config/opendkim/
內即可以看到生成的金鑰
底下會有 mail.private
和 mail.txt
兩個檔案
mail.private
是私鑰, mail.txt
是公鑰
將 mail.txt
的內容加入到 DNS 的 TXT 紀錄即可
上傳之後請記得重新啟動 docker
docker compose down | |
docker compose up -d |
# SPF
SPF 是一種驗證發信人身份的技術
一開始我們前置作業所設定的 TXT 就是這個
# DMARC
DMARC 也是一種郵件驗證技術
主要是 SPF 和 DKIM 的補充
並且可以指定如何處理未經驗證或驗證失敗的信件
這裡有一個現成的 DMARC 產生器可以用
rua 和 ruf 要調整好,不然出錯的時候很難 debug
# 容器文件設定
接下來就是筆者覺得最麻煩的地方了
docker 裡面實際運行了兩個程式
dovecot
:IMAP/POP3 伺服器postfix
:SMTP 伺服器
這兩個伺服器的設定檔案都在容器內
然後都超級零散
可是又互相依賴和驗證
我這裡直接提供筆者嘗試了三個晚上試出來的設定
注意: 這裡的片段只是部分的設定檔
代表這一個區塊需要調整和設定 沒提到的就別動
# postfix
nano /etc/postfix/main.cf
# 這裡有個大坑 如果你用預設的 $myhostname的話 他會和系統預設的vmail虛擬郵件位置衝突
mydestination = localhost.$mydomain, localhost
smtpd_sasl_type = dovecot
smtpd_sasl_path = /dev/shm/sasl-auth.sock
smtpd_sasl_auth_enable = yes
smtpd_tls_security_level = encrypt
smtpd_sasl_security_options = noanonymous
smtpd_recipient_restrictions = permit_sasl_authenticated,permit_mynetworks,reject_unauth_destination
virtual_alias_domains = miyago9267.com
virtual_alias_maps = hash:/etc/postfix/virtual
nano /etc/postfix/master.cf
submission inet n - n - - smtpd
-o syslog_name=postfix/submission
-o smtpd_tls_security_level=encrypt
-o smtpd_sasl_auth_enable=yes
-o smtpd_client_restrictions=permit_sasl_authenticated,reject
-o milter_macro_daemon_name=ORIGINATING
# dovecot
/etc/dovecot/conf.d/10-ssl.conf
# 這裡是你容器內的證書位置 要填上fullchain和key pem或crt等格式都可以
ssl_cert = </etc/nginx/certs/miyago9267.com/fullchain.crt
ssl_key = </etc/nginx/certs/miyago9267.com/key.crt
/etc/dovecot/conf.d/10-auth.conf
unix_listener /dev/shm/sasl-auth.sock {
mode = 0666
user = postfix
group = postfix
}
以上設定大致上告一段落
# 測試
最後就是測試我們的功能有沒有成功了
# Telnet
可以使用 telnet 來測試協定的連線
telnet mail.example.com 25 |
# openssl
可以使用 openssl 來測試加密的連線是否正常,他其實有一些指令可以操作,但我沒有特別去研究
openssl s_client -connect localhost:995 -crlf | |
openssl s_client -connect localhost:587 -crlf |
# Mailtest
有一個測試郵件健康的網站可以使用
Mail-tester
他有一些指標可以告訴你
你的 mailserver 以及發出去的信件有什麼需要調整的問題
蠻方便的 起碼有一個方向可以參考
# 連結外部平台
自架的 MailServer 最大的問題是讀取信件的時候很不方便
誰有那個美國時間和閒工夫去登入自己的 MailServer 看信
讀個信還得打指令
因此我們可以將我們的 MailServer 連結到外部平台
筆者選擇的是 Gmail
首先
- 打開你的 Gmail
- 接著點擊右上角的大齒輪
- 點擊「查看所有設定」
- 點擊「帳戶和匯入」
- 點擊「新增郵件帳戶」
- 輸入你的信箱地址和帳號
- 輸入你的信箱密碼
- 噹啷 搞定
這樣你就可以在 Gmail 裡面讀取你的 MailServer 的信件了
# 結語
由於這次架一個 mailserver 踩到太多坑了
因而才決定寫一篇半紀錄的心得來分享
我沒辦法保證完全按照教學走就一定會成功
然而應該可以做到幫忙指個路這樣
如果有遇到什麼需要幫忙看的問題再留言吧
我能夠幫忙就盡力幫忙