一直以來
筆者的收信都是透過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紀錄:這個應該大家都會設定,不如你的網址根本連不到伺服器
  • MX紀錄:指定信件要導去哪裡
  • TXT紀錄:
  • PTR紀錄:做rDNS反向解析用的,可以從IP反向解析到domain,這個是為了避免被標記為垃圾郵件

這邊的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 bashig dkim

由於我們在啟動docker-compose之前已經映射過路徑了
我們只需要進到./docker-data/dms/bashig/opendkim/內即可以看到生成的金鑰
底下會有mail.privatemail.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/bash.d/10-ssl.bash

# 這裡是你容器內的證書位置 要填上fullchain和key pem或crt等格式都可以
ssl_cert = </etc/nginx/certs/miyago9267.com/fullchain.crt
ssl_key = </etc/nginx/certs/miyago9267.com/key.crt

/etc/dovecot/bash.d/10-auth.bash

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

首先

  1. 打開你的Gmail
  2. 接著點擊右上角的大齒輪
  3. 點擊「查看所有設定」
  4. 點擊「帳戶和匯入」
  5. 點擊「新增郵件帳戶」
  6. 輸入你的信箱地址和帳號
  7. 輸入你的信箱密碼
  8. 噹啷 搞定

設定怎麼進去

設定的進入

如何添加帳號

添加帳號

這樣你就可以在Gmail裡面讀取你的MailServer的信件了

# 結語

由於這次架一個mailserver踩到太多坑了
因而才決定寫一篇半紀錄的心得來分享
我沒辦法保證完全按照教學走就一定會成功
然而應該可以做到幫忙指個路這樣

如果有遇到什麼需要幫忙看的問題再留言吧
我能夠幫忙就盡力幫忙

總瀏覽次數:載入中...更新於

請我喝[茶]~( ̄▽ ̄)~*

Miyago9267 微信支付

微信支付

Miyago9267 支付寶

支付寶

Miyago9267 buymeacoffee

buymeacoffee