この記事を作った動機
最近、Google (Gmail) とかに深く関係があるのは嫌であることや、中央集権的な SAAS サービスへの不信がある。そこで、自前のメールサーバを持ちたいと思い、Mailcow を使おうとしたので不完全でいいので作業過程の記録を取りたい。
前提条件
- Arch Linux 環境で作業を行い、Mailcow 公式サポートはない状態である
- 専用の物理 PC を割り当てる
- クリーンインストールで、Gnome デスクトップ環境や最低限のパッケージが入った、Arch Linux 環境
- スリープを無効化している。-> gnomeの設定のメモ ⚙
- firewalld は導入していないこと -> Prepare your system - mailcow: dockerized documentation
- できれば
yayコマンド を導入する - NetworkManager を使っている。
- DNS サーバにクラウドフレアを使っている。
設定要件
- 自分の LAN (VPN) 環境のみからメールの送信を受け付け、グローバル IP 空間からはメールの送信を受け付けない
- メールの受信についての対策は、Mailcow 標準に頼りたい
- 利用者は自分や自分が許可した少数の身内のみ
- メールサーバ自体は直接グローバル IP 空間には晒さず、VPN や LAN のネットワーク空間を転送するようにして利用する。
ネットワーク構成
ネットワーク構成としては、通常のメールサーバではグローバル空間に配置してファイヤウォールに必要な分だけ慎重に穴を開けるなどのスタンスを取ると考えられるが、今回のはセキュリティーの観点から、そうはしなかった。
基本的には、メールサーバは直接グローバル空間には晒さず、かつNAT環境下にある自宅の専用に用意したサーバを使うという観点から、別の専用にグローバル空間とつながっていて固定IP持っている中継サーバ(VPS)で、ポート転送などを行うという形態を取った。また、セキュリティの観点から メールを送受信したり、サーバを管理できるユーザは、VPNによって自宅のLAN内にアクセスできる人間のみとし、グローバル空間からは、SMTPポートだけ、晒して、メールは送受信できるようにしつつ、外部の人間は今回構築するメールサーバに対して、リレーとして使ったり、送信を命令することはできないようにしている。メールを送信できる人は、メールサーバと同じLANに属しているユーザだけであり、メールの受信はどこからでもスパムでないこと、不正でないことを前提に、スパムフィルターで弾かれなかったものが受け付けられるという形態を取る。
中継には VPS を使い、メールサーバとVPS間は専用に用意したVPNネットワークで接続される。これにより、NAT超えも実現しながら、メールサーバを直接グローバル空間に晒さずに済むというものである。注意点としてはメールサーバ側のルーティングや、VPS側のファイヤウォール、転送設定がを間違っていると、セキュリティリスクになる点を留意する。
イメージ用の図いろいろ
ネットワーク構成の概要
大まかなルート構成
VPSにおけるポート転送と特別なルーティング(nftables)で成立
通常のSMTPとして成立するルート
外部のメールサーバからの見え方
メール送受信のためのフロントエンドアクセスが出来る範囲
SMTP 関連パケットのルーティングについて
メール受信時の経路
メール送信、SMTP における応答通信時における経路
不正な SMTP パケットの経路
ネットワーク設定
VPS プロバイダの設定
VPS の設定
メールサーバ本体の設定
説明用の仮定
メールアドレス
xxxx@your.domain.comのようにする。
メールサーバについて
mx.your.domain.comにホストすることにする。- IPアドレスを
160.251.xxx.xxxとして仮定する。
Mailcow のインストール
docker 環境の導入
# 必要なパッケージのインストール (jq は mailcow の依存関係)
yay -Sy docker docker-compose jq
# sudo pacman -Sy docker docker-compose jq
# サービスの有効化
sudo systemctl enable --now docker
# 必要であれば管理用ユーザを docker グループに追加し、権限を付与する
sudo usermod -aG docker [targetUser]
# 念のため再起動
sudo systemctl reboot
IP アドレスの固定
今回は、NetworkManager を Gnome 環境に組み合わせた状態なので、Gnome の GUI から設定を行った。
Mailcow のインストール
以下は公式ドキュメントの引用である。設定を生成するスクリプトによって、聞かれる設定については、今回は HostName を mx.your.domain.com のようにした。
su umask 0022 cd /opt git clone https://github.com/mailcow/mailcow-dockerized cd mailcow-dockerized ./generate_config.sh
Mailcow の起動 (su 環境)
docker compose pull
docker compose up -d
動作確認
別の PC から、Mailcow のフロントエンドを開き、ログインすることで動作確認する。Mailcow におけるデフォルトの管理者の情報は以下のとおりである。-> ログイン情報の出典
初期ログイン情報
- ユーザ名
admin - パスワード
moohoo
フロントエンドにアクセスする
※ 初回起動時は、一定時間待たないとフロントエンドが出てこないので注意する。
-
任意のブラウザを開き、Mailcow がインストールされた PC にアクセスする。設定を厳密にはしていないので証明書のエラーが出るがここでは動作確認を目的としているのでとにかく進める。
-
管理者ログインページに遷移し、ログインする。
-
ダッシュボードが表示される。
DNS 設定をする
/opt/mailcow-dockerized/mailcow.conf
# Enable DNS-01 challenge (instead of HTTP-01)
ACME_DNS_CHALLENGE=y
# Specify your DNS provider plugin (see provider list below)
# Example: dns_servercow for Servercow, dns_cf for CloudFlare, dns_aws for AWS Route53
ACME_DNS_PROVIDER=dns_cf
# Email address for ACME account registration
ACME_ACCOUNT_EMAIL=your@Valid.emali.com
/opt/mailcow-dockerized/data/conf/acme/dns-01.conf
CF_Token = "Your secret token"
CF_Account_ID = "Your secret ID"
Cloudflare において、アカウントIDを確認する
ホーム画面から、workers のところを押すと以下のように見える。
Cloudflare において “Please verify your email” で API トークンを生成できないとき
本人確認ができていないということで、拒絶されているので何かしらの形で本人確認をしたことにする必要がある。正式な方法は分かっていないが、以下のようにして、ドメイン登録など本人確認が必要な操作をしようとすると出てくる、“Verify your account"の項目を使って、本人確認をした状態で、API キーを取得しようとすることはできることが分かった。
Email Routing の無効化
Cloudflare では単に、Email routing の設定に移動して、disable という赤いボタンを押すだけでは、十分にロックされた MX レコードを削除しきれない。
以下の画像に示されるように、赤く囲った部分に対象のドメインが無い状態にしないと、DNS レコードの画面から、自分でドメインを設定できる状態に持ち越せない。
DNS レコードを追加
メールサーバまでの経路を作成
メールサーバ自体にルーティング
- 名前
mx.your.domain.com
- タイプ
A - 内容
160.251.xxx.xxx
メールサーバに誘導
- 名前
your.domain.com
- タイプ
A - 内容
mx.your.domain.com
認証系 (要確認)
SPF
だれがメールをyour.domain.comとして送信して良いかを IP や ドメイン名で設定する。今回はドメインを指定する例を示す。
- 名前
your.domain.com
- タイプ
TXT - 内容
"v=spf1 a:mx.your.domain.com -all"
DMARC
認証に失敗したメールをどう扱うか示す。p=noneで破棄して送信失敗の通知だけする、p=quarantineでスパムとして扱う、p=rejectで配送しないになる。
- 名前
_dmarc.your.domain.com
- タイプ
TXT - 内容
"v=DMARC1; p=quarantine"
DKIM
メールが配送過程で改ざんされていないか確かめる。名前に、dkim._domainkeyの接頭辞が必要である。内容は例示として簡略化したものを示し、各自適切に設定する必要がある。Mailcow における設定値については、mailcow-にて-dkim-を確認取得するを参照する。
- 名前
dkim._domainkey.your.domain.com
- タイプ
TXT - 内容
"v=DKIM1;k=rsa;t=s;s=email;p=..."
逆引きホスト名の修正
以下のように双方向に名前解決して、それらが一致するようにする。VPS の管理画面などから設定する。(反映に時間がかかるため数日ほど放置してみること)
- イメージ
mx.your.domain.com. -> 160.251.xxx.xxx
160.251.xxx.xxx -> mx.your.domain.com.
- 設定内容の例
mx.your.domain.com.
- 設定の検証
# mx.your.domain.com. -> 160.251.xxx.xxx
dig mx.your.domain.com.
# ; <<>> DiG 9.20.19 <<>> mx.your.domain.com.
# ;; global options: +cmd
# ;; Got answer:
# ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 6491
# ;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
#
# ;; OPT PSEUDOSECTION:
# ; EDNS: version: 0, flags:; udp: 1232
# ;; QUESTION SECTION:
# ;mx.your.domain.com. IN A
#
# ;; ANSWER SECTION:
# mx.your.domain.com. 300 IN A 160.251.xxx.xxx
#
# ;; Query time: 248 msec
# ;; SERVER: 192.168.24.1#53(192.168.24.1) (UDP)
# ;; WHEN: Sun Aug 09 05:57:27 JST 2026
# ;; MSG SIZE rcvd: 65
# 160.251.xxx.xxx -> mx.your.domain.com.
dig -x 160.251.xxx.xxx
# ; <<>> DiG 9.20.19 <<>> -x 160.251.xxx.xxx
# ;; global options: +cmd
# ;; Got answer:
# ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 58919
# ;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
#
# ;; OPT PSEUDOSECTION:
# ; EDNS: version: 0, flags:; udp: 1232
# ;; QUESTION SECTION:
# ;127.185.xxx.xxx.in-addr.arpa. IN PTR
#
# ;; ANSWER SECTION:
# 127.185.xxx.xxx.in-addr.arpa. 86400 IN PTR mx.your.domain.com.
#
# ;; Query time: 59 msec
# ;; SERVER: 192.168.24.1#53(192.168.24.1) (UDP)
# ;; WHEN: Sun Aug 09 05:57:33 JST 2026
# ;; MSG SIZE rcvd: 91
おまけ
Mailcow にて DKIM を確認(取得)する
DNS の値として設定すべき DKIM の値は既に Mailcow が生成しているのでそれを使う。その値について確認する方法を以下に画像で示す。確認には、Mailcow のフロントエンドを利用する。
mailcow/unbound コンテナにおいて、unhealthyとなり、メールが一切送受信できなくなる問題について (追記 2026/8/31)
以下に示す github の issue にも書かれているが、私の環境においても IPv6 による名前解決が unbound の設定においてデフォルトで有効になっており、それが障害を起こしていたという事例が確認された。
- ARM64: unbound 1.19 up but unhealthy · Issue #5649 · mailcow/mailcow-dockerized
https://github.com/mailcow/mailcow-dockerized/issues/5649 (2026年8月31日)
具体的には以下のような経過を辿った。
- 通常どうりメールが送受信でき何も問題なさそうに見える
- しばらく数週間後くらいして、例えばヤフーのメール認証のメールが10分くらい送れて届くなど障害が現れてくる
- それから2日後、メールが送受信できないことが発覚し、調査することになった。
具体的な修正内容
/opt/mailcow-dockerized/data/conf/unbound/unbound.conf の設定内容を IPv6 を使わないように修正する。以下は、設定ファイルの一部を例に示す。
- 設定前
server:
verbosity: 1
interface: 0.0.0.0
interface: ::0
logfile: /dev/console
do-ip4: yes
do-ip6: yes
do-udp: yes
do-tcp: yes
- 設定後
server:
verbosity: 1
interface: 0.0.0.0
#interface: ::0
logfile: /dev/console
do-ip4: yes
do-ip6: no
do-udp: yes
do-tcp: yes
調査において見られた症状
docker psにおいて、unboundコンテナが、unhealthyステータスになっている。- Mailcow のフロントエンドの管理者画面において、Poxtfix などで MX レコードに関する名前解決が失敗している旨のログが散見される。
warning: Unable to look up MX host mx.your.domain.com for Recipient address main@your.domain.com: Temporary failure in name resolution
warning: Unable to look up MX host xxxxxxx.in.tmems-jp.trendmicro.com for Recipient address xxxxxx@xxxxxx.xxxxxxx.ac.jp: Temporary failure in name resolution
sudo tcpdump -i any port25を実行すると、メール送信時に、パケットが送信された様子がすぐに見られない。
関連する記事
使った画像とか
- Windows 7(Vista) デフォルトのアイコン
- PC のアイコン
- ルータのアイコン
- ハブのアイコン
- サーバーのアイコン
- インターネットのアイコン
- 人のアイコン
- mailcow: dockerized documentation
https://docs.mailcow.email/ (2026年8月4日) - Arch Linux
https://archlinux.org/ (2026年8月4日) - File:Tux.svg - Wikimedia Commons
https://commons.wikimedia.org/wiki/File:Tux.svg (2026年8月4日) - Google, Public domain, via Wikimedia Commons
https://commons.wikimedia.org/wiki/File:Gmail_icon_(2020).svg (2026年8月13日) - Microsoft, Public domain, via Wikimedia Commons
https://commons.wikimedia.org/wiki/File:Microsoft_Outlook_Icon_(2025–present).svg (2026年8月13日) - SoftEther VPN Project - SoftEther VPN Project
https://www.softether.org/ (2026年8月13日) - Proton Mail: Get a free email account with privacy and encryption | Proton
https://proton.me/mail (2026年8月13日)
参考にしたサイトとか
-
Prepare your system - mailcow: dockerized documentation
https://docs.mailcow.email/getstarted/prerequisite-system/#supported-os (2026年8月4日) -
Arch Linux - docker-compose 5.4.0-1 (x86_64)
https://archlinux.org/packages/extra/x86_64/docker-compose/ (2026年8月4日) -
Arch Linux - docker 1:29.7.1-1 (x86_64)
https://archlinux.org/packages/extra/x86_64/docker/ (2026年8月4日) -
Arch Linux - jq 1.8.2-1 (x86_64)
https://archlinux.org/packages/extra/x86_64/jq/ (2026年8月4日) -
Prepare your system - mailcow: dockerized documentation
https://docs.mailcow.email/getstarted/prerequisite-system/#firewall-ports (2026年8月4日) -
Install mailcow - mailcow: dockerized documentation
https://docs.mailcow.email/getstarted/install/ (2026年8月4日) -
Domain cannot match hostname (how add my FQDN?) - mailcow community
https://community.mailcow.email/d/972-domain-cannot-match-hostname-how-add-my-fqdn/9 (2026年8月5日) -
“Please verify your email” stuck + cannot update email - possibly in suppression li - General / Dashboard - Cloudflare Community
https://community.cloudflare.com/t/please-verify-your-email-stuck-cannot-update-email-possibly-in-suppression-li/922040 (2026年8月5日) -
Where can I find my account_id - General / Dashboard - Cloudflare Community
https://community.cloudflare.com/t/where-can-i-find-my-account-id/164431 (2026年8月5日) -
sysctl.conf(5) - Linux manual page
https://man7.org/linux/man-pages/man5/sysctl.conf.5.html (2026年8月7日) -
ARM64: unbound 1.19 up but unhealthy · Issue #5649 · mailcow/mailcow-dockerized
https://github.com/mailcow/mailcow-dockerized/issues/5649 (2026年8月31日) -
container unbound unhealthy - mailcow community
https://community.mailcow.email/d/2977-container-unbound-unhealthy/49 (2026年8月31日) -
mailcowdockerized-unbound-mailcow-1 is unhealthy - mailcow community
https://community.mailcow.email/d/3174-mailcowdockerized-unbound-mailcow-1-is-unhealthy/11 (2026年8月31日)