'DNSの話まで'
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful

This commit is contained in:
Rikuoh Tsujitani 2023-08-25 23:13:45 +09:00
parent 7a407e0698
commit 2eaef7928c

46
content/post/test.md Normal file
View file

@ -0,0 +1,46 @@
---
title: "MailuでWeb UI付きのメールサーバを所有する"
date: 2023-08-25T19:40:24+09:00
draft: true
tags: ['tech']
---
初夏の辺りには[こんなこと]()を言っていたが、せっかくVPSの計算資源が余っているのでやはり自前でメールサーバを建てることにした。数多の艱難辛苦に見舞われた10年前と今では状況がずいぶん違う。今やDockerがあり、優れたOSSがあり、これまでに培ってきたトラブルシューティングの知見がある。躓いたらいつでもコンテナを破棄してやり直せばいい。なにか建てるたびにディレクトリの至るところに引っかき傷を残していた10年前とは違う。
[Mailu]()というOSSがある。メールサーバに必要な構成が統合されていて全部よしなにやってくれる上にWeb UIまで付いてくるすごいやつだ。こんなのがあるんだったらVPSを契約している身でわざわざ外部の事業者に金を払っている場合ではない。そうして、僕は意気揚々とサーバの構築に乗り出したのだった。**結論から言うと、考えが甘かった。** 相変わらずメールサーバは手強い。本稿はMailUを利用したメールサーバの構築について記す。
## ファイルの取得と編集
`docker`および`docker-compose`はすでに導入されているものとする。専用のユーザでホームディレクトリ直下に作業フォルダを作成する。以降は`docker-compose.yml`の雛形をコピペして持ってくる形が一般的だが、Mailuの場合は[セットアップウィザード]を使うとユーザの意図に適った設定ファイルを出力してくれる。当然、これらのファイルはdocker-compose.ymlと`mailu.env`ファイルなので後からでも編集できる。ただし、動作検証を済ませるまではWebメールクライアントを有効にした方がよいと思われる。
重要なポイントとして、ポート設定の`80:80`と`443:443`の左側は必ず他の番号に変更しなければらない。メールサーバ以外のサービスを一切立ち上げていないのならともかく、これらの内向きポートは確実に専有されている。僕は`7900:80`、`8443:443`にした。メールサーバなのにHTTP/HTTPSポートが必要なのはタイトル通りWeb UIが備わっているためだ。この修正に際して`mailu.env`に以下の追記が求められる。
```env
REAL_IP_HEADER=X-Real-IP
REAL_IP_FROM=あんたのグローバルIP
```
ウィザードの"Choose how you wish to handle security"の欄はいまいちピンと来ないかもしれない。しかし最終的には大抵`letsencrypt`か`mail-letsencrypt`を選択することになる。いや、SSL証明書ならもう持っているけど ……そう思うのも無理はないが、その方が明らかに楽できる。とはいえ、下手に連続施行して取得規制に引っかかっては困るので準備が整うまでは`cert`を選択することをおすすめする。
セットアップウィザードの甲斐あって他に修正すべき箇所はあまりない。**今は。**もし皆さんがCloudflareなどのCDNを間に挟んで**いなければ**ここからの話はかなりスムーズになる。だが、今どきそんな人いるか それこそ10年前とは違う。今やなんでもCDNの時代だ。なんでもCDNの上に乗っているものだからオリジンサーバが文字通り雲隠れしたように見える。ところがメールサーバはそれが通用しない。だから面倒くさいんだ。
## 特殊なDNSの設定
Cloudflareの設定を例にとる。メールサーバに用いるドメインを選択して**DNS → レコード**からレコードを設定する。通常であればサーバのIPアドレスをAレコードでドメインと紐づけておしまいだが、メールサーバの場合は「プロキシ」を有効にしては**ならない。** 適用後の表示が「DNSのみ」になるように設定する。
つまり、メールサーバに用いるドメインはCloudflareの恩恵を受けられない。それがなにを意味するのか 彼らのSSL証明書を使えないのだ。僕がこのブログで散々おすすめしているCloudflareのオリジンサーバ証明書はもちろん、エッジ証明書すらもらえない。そう、同じドメイン下なら使える証明書がメールサーバに振ったサブドメインに限っては使えないので、別の証明書を新たに発行しなければならないのである。
もちろんすでに持っているSSL証明書がCDNのものではなく、それこそLet's encryptとかZero SSLなら使い回せる。しかし、本稿で紹介するのはDockerを利用した構築方法だ。Dockerの内部で動いているサーバから外部の証明書を直接参照する方法は用意されていない。公式の手段では特定のディレクトリにコピペする形をとる。
とはいうものの、大半の人が使っている無料のSSL証明書は有効期限が3ヶ月しかない。3ヶ月ごとにいちいち更新した証明書をコピペするのか あるいは別途、スクリプトを書いてcronに実行させる ウーン、どうにも洗練さに欠ける。僕たちは最先端のOSSでちょっぱやのメールサーバを建てているはずじゃなかったのか
そこで、前述した`letsencrypt`が顔をのぞかせる。これはメールサーバが初回起動時に設定したドメイン用の証明書を自動で取得して、更新も実行してくれる設定なのだ。こいつに任せておけばこの問題はDockerコンテナの内部で完結する。よし、話はこれで終わりか 後は起動して寝るだけか 残念、もう一つある。
このOSSはWeb UIを備えている。つまりブラウザで管理画面に接続できる。どのURLで なにも工夫していなければメールサーバのドメインと同じはずだ。そうすると、厄介な話になる。Let's encryptは80番ポートを使って証明書を取得する。たとえHTTPSでしか接続を受け付けたくなくとも開けておかなければならない。にも拘らずCloudflareの恩恵を受けていないので、エッジ証明書は存在しない。とんでもなくガバい管理画面の出来上がりだ。
あれ、`letsencrypt`の設定が自動で取得してくれるのでは いいや、そいつはDockerコンテナの中にあるのでnginxのリバースプロキシで指定できない。じゃあ……一体どうするんだ。ブラウザ用の証明書も別にとれってのか 一体何枚の証明書がいるんだ 全然便利でもなんでもないじゃないか
実はすばらしい解決策がある。メールサーバ用のサブドメインと、管理画面用のサブドメインを別々に用意すればいい。hogafuga.comというサイトがあったとすると、Aレコードをmail.hogefuga.comに振ってこっちを管理画面用にする。そして、メールサーバ用にはmx.hogefuga.comなどを割り当てて、MXレコードを振る。
この時、`letsencrypt`の設定で自動取得させるドメインの対象は`mx.hogefuga.com`の方だ。`mail.hogefuga.com`はただのWebフロントエンドに過ぎないので堂々とCloudflareのプロキシを有効にできる。こうすると`mx.hogefuga.com`はメールクライアントで設定する際にしか用いられないのでWebの方の心配をする必要がなくなり、`mail.hogefuga.com`はCloudflareの恩恵がさんさんと降り注いで勝手にSSL化される寸法となる。
簡単そうに言ったけどな、この解決策を探し当てるまでに2日もかかったよ僕は。もしかしてこれって割と当たり前のメソッドだったりする