如何在 Ubuntu Server 用 mailcow 建置郵件伺服器

被端走的小菜
15 min readAug 15, 2023

--

前言

這篇是紀錄如何自行架設郵件伺服器 (Mail Server) 的過程,使用開源的 mailcow 建置

說明

當初在找開源的 Email 軟體時,主要是比較 mailcowRoundcube 這兩套,
需求為:

  1. 收發信
  2. 有 WebMail 介面
  3. 方便管理所有 Email 的介面
  4. 權限管理功能
  5. 有 API 可以打
  6. 容易建置
  7. 容易升級
  8. 開源專案有持續地維護

因此選擇以 mailcow 作為首選

若想要比較不同 Email 的服務差異,可以參考 SaaShubLibHunt ,可以比較任兩套的軟體

安裝步驟

以下建置過程是在 Ubuntu Server 22.04.2 LTS ,可參考這篇如何建置

1. 設定 DNS

建議先設定好 DNS ,生效會需要一些時間
假設我的固定 IP 是 123.45.67.89
假設我的 domain 是 riverye.com

2. 安裝 Docker

照著 Docker 官方文件,複製貼上,執行即可

$ sudo apt-get update
$ sudo apt-get install ca-certificates curl gnupg
$ sudo install -m 0755 -d /etc/apt/keyrings
$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg - dearmor -o /etc/apt/keyrings/docker.gpg
$ sudo chmod a+r /etc/apt/keyrings/docker.gpg
$ echo \
"deb [arch="$(dpkg - print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
"$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
$ sudo apt-get update
$ sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin -y

3. 下載 mailcow

$ sudo su -
$ cd /opt
$ git clone https://github.com/mailcow/mailcow-dockerized
$ cd mailcow-dockerized

4. 設定 mailcow 的 generate_config.shmailcow.conf

4–1. 設定 generate_config.sh

$ ./generate_config.sh

Found Docker Compose Plugin (native).
Setting the DOCKER_COMPOSE_VERSION Variable to native
Notice: You´ll have to update this Compose Version via your Package Manager manually!
Press enter to confirm the detected value '[value]' where applicable or enter a custom value.
Mail server hostname (FQDN) - this is not your mail domain, but your mail servers hostname: mail.riverye.com
Timezone [Asia/Taipei]:
Which branch of mailcow do you want to use?
Available Branches:
- master branch (stable updates) | default, recommended [1]
- nightly branch (unstable updates, testing) | not-production ready [2]
Choose the Branch with it´s number [1/2] 1
Fetching origin
Your branch is up to date with 'origin/master'.
Generating snake-oil certificate…
..+.+…+…..+…….+…………+………..+.+……+…..+……………+….+……..+.+…..+……….+……+…+…+……..+………………………+…+.+…..+….+..+…+….+..+.+…..+……………+…….+…..+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*………+..+…+.+……………..+…+….+……+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*….+.+…+………+…+………+…+..+…………………….+…..+….+…..+.+…..+……+…+….+…+..+…+…+….+..+…………….+…..+…………+.+………+…………+…..+………………+.+……+……+………+…..+….+..+…….+..+……….+…..+….+..+….+……+…+……+…..+.+..+……+…….+…..+….+…..+.+………+…+……..+……………+…….+………………+…..+…+.+…..+……….+……+…+………+…..+…….+…+……+………..+…+…+…….+………..+.+………+…………………………+………+…………+…+…………………..+………+…+……+………+.+..+………+.+..+……+……………+….+…+………………………..+.+……………..+.+………………..+……………+.+……+…..+…………+……………………….+…………+…..+……….+…..+…+…+………+…………+……….+…..+………+…….+…+…..+…………+………+…+……………+……+………+…………+……+…+.+……+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
…+…..+…+………….+…..+…….+…+..+….+…..+………+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*……………….+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*..+….+………..+……+…+.+…+………………………+……+………+…+……………..+….+…………………+…………..+…….+…..+….+…..+.+………………+..+…+……+…+……+……+………….+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- - -
Copying snake-oil certificate…
Detecting if your IP is listed on Spamhaus Bad ASN List…
Check completed! Your IP is clean

4–2. 設定 mailcow.conf

以下是我有調整的部分,可依照需求自行更改

$ vim mailcow.conf

DBNAME=mailcow_db
DBUSER=mailcow_user
SKIP_IP_CHECK=y
SKIP_HTTP_VERIFICATION=y
ALLOW_ADMIN_EMAIL_LOGIN=y

5. 啟動服務

上述設定完成後,接著要用 Docker 啟動服務

$ docker compose pull
$ docker compose up -d

5–1. 服務啟動失敗

啟動服務後,若開啟網頁看到以下錯誤,請不要慌,靜待數秒至幾分鐘後 (依電腦效能),再重新整理,就能看到登入畫面了

5–1. 服務啟動成功

看到以下畫面,代表服務有正常被啟動成功,若仍只看到上述畫面,可以照上面的錯誤訊息,印出 Log 看錯誤訊息

登入後,建議把預設密碼改掉

6. 新增域名

新增我的 domain
操作步驟:E-Mail -> Configuration -> 新增域名

以下是範例

7. DNS 設定

操作步驟:E-Mail -> Configuration -> 找到剛才新增的域名(domain) -> DNS
依照提示去設定 DNS 即可

附上從 Cloudflare 匯出的 DNS 設定

;; A Records
mail.riverye.com. 1 IN A 123.45.67.89

;; CNAME Records
autoconfig.riverye.com. 1 IN CNAME mail.riverye.com.
autodiscover.riverye.com. 1 IN CNAME mail.riverye.com.

;; MX Records
riverye.com. 1 IN MX 10 mail.riverye.com.

;; SRV Records
_autodiscover._tcp.riverye.com. 1 IN SRV 10 10 443 mail.riverye.com.

;; TLSA Records
_25._tcp.mail.riverye.com. 1 IN TLSA 3 1 1 af728af706fe3eb0c23ad4387d2d24ad81cfa5811e3821f8fa206452ea52ef32

;; TXT Records
dkim._domainkey.riverye.com. 1 IN TXT "v=DKIM1;k=rsa;t=s;s=email;p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1NRc1H0Ae7+vv//hwsXCKwGDDs6QnU8ZNZ/RbBCPATEMdNkfxrAhlY9Q9x4znQFdoXm6i6P2P39/EF/+PjaKMNR7YKwxe/LDfuZUMitR2/vccRxmRttoJ/FoEO2HimlTliGYE8ertDXHsmyS2Lf3ddxUbS4PZyHm18heWcoSA4IXmsL02JK0Jnt5aotqMAMyZk8m8WGkQkMfHyc3KdhcqfsCdfMBhRMp6HY72qrjRvjKWnQPeyZaB9mqeaasxjCTfZHOoEfi+2qJf04U3SYBOuhs1lv/BJXNJo5iyTHz9mBdPDqGFsn653BHcSpggEW6RXqctIOSMSlypW5/hcp8fQIDAQAB"
_dmarc.riverye.com. 1 IN TXT "v=DMARC1; p=none;"
riverye.com. 1 IN TXT "v=spf1 mx ~all"

設定完成後,等待 DNS 生效後 (快則數秒,慢則數小時),可透過 mailcow 的介面檢查設定是否正確,正確則會有綠色 v

若已經設定好 DNS ,但在 mailcow 介面看仍尚未正確,可以在終端機使用 dig 指令 double check 看是否有輸入錯誤

# 想看 SRV Type
$ dig SRV _autodiscover._tcp.riverye.com

# 用特定的 DNS 服務查詢,以 Cloudflare 為例
$ dig @1.1.1.1 SRV _autodiscover._tcp.riverye.com

8. 新增信箱及測試寄信

影片教學

已經新增專屬的信箱後,再來就是要寄到外部,確認能否寄信成功
推薦可以使用 Newsletters spam test by mail-tester.com 進行測試

以下是我的寄信評分

如何綁定 Outlook

以 IMAP 為例,設定如下

QA.

QA1. 使用「HiNet非固定制固定IP」,並非「固定制」也可以自行架設嗎?

可以的,只差別在 DNS 的 PTR 類型無法設定,常用的信箱 (ex: Gmail、Hotmail、Apple icloud 等) 還是能收到信,但如果是檢查比較嚴格的信箱,則可能會被拒收 (reject),可依照需求評估是否要改用「固定制」。

在建置時,有遇到同樣的設定,使用固定 IP A 可以寄到上述所說的信箱,但換成另一組固定 IP 時,則全都被拒收,好在退信的信件中,有提供申訴的管道,提出申訴後,約等 3–4 小時,就能正常寄給上面的那些外部信箱了。

QA2. 如何讓輸入的網址,連到對應的電腦

關鍵字是「Port Forwarding (通訊埠轉發)」,也有廠商是用「虛擬伺服器」、「虛擬 IP」…等稱呼,指的是同樣的東西。

在 ASUS 的教學文件,寫的很清楚什麼是 Port Forwarding ,以及要如何設定 ASUS 的路由器
[無線路由器]如何在華碩路由器設定虛擬伺服器(Port forwarding)?

ASUS 的設定範例

在 ASUS 中,是在「虛擬伺服器」中設定

Fortinet FortiGate 的設定範例

在 FortiGate 中,是在「虛擬 IP」中設定

防火牆也要記得設定,免得無法將資料正確傳到指定的電腦,其中 NAT 要停用!!!
不然 Server 都只會接收到 Gateway IP Address ,無法知道真實的 IP,進而無法用 Fail2ban

QA3. 路由器已經將 80 或 443 port (埠) 用做其他用途,該怎麼辦?

關鍵字是「Reverse Proxy (反向代理)」,可以使用 Nginx、Apache 來架設 Reverse Proxy
這邊推薦使用 Caddy,比前 2 個更好設定、語法更簡潔、不用處理憑證 (CA)

# /etc/caddy/Caddyfile

# 假設 Reverse Proxy Server 和 Mail Server 是不同電腦
mail.riverye.com {
reverse_proxy 192.168.1.30
}

# 假設 Reverse Proxy Server 和 Mail Server 是同一台電腦,且要指定 port 給 Mail Server 使用
mail.riverye.com {
reverse_proxy localhost:9527
}

QA4. 如何看某 port 的流量紀錄?

會特別提到這個,是因為當初沒注意到 Fortinet FortiGate 的 NAT 有啟用,因此用 API 打 mailcow 時,雖然有設定 IP 檢查,卻沒照預期運作。
才會有需要看某 port 的流量紀錄需求,可在終端機中使用 tcpdump 指令。

# 想看 443 port
$ tcpdump -f port 443

QA5. 如何將 mailcow 更新到最新?

$ cd /opt/mailcow-dockerized
$ ./update.sh

QA6. 如何避免有人惡意想要嘗試登入後台?

可以使用 Fail2ban, mailcow 的介面,能直接設定

小結

自行架設的過程當中,會學到許多知識,尤其是硬體到軟體都自己弄時,會發現自己不會的東西很多,而不停地去瞭解接觸到的關鍵字,趁記憶猶新時,寫下此篇紀錄,以防之後忘了

medium 文章連結:https://riverye.medium.com/1d80c469efec
本文同步發布於 小菜的 Blog https://riverye.com/

備註:之後文章修改更新,以個人部落格為主

--

--

被端走的小菜

大家好,我是被端走的小菜。以個人部落格更新為主:https://riverye.com/