Ubuntu20.04にメールサーバーをセットアップする方法（modoboaで dovecot, postfix)

更新日2021年5月4日

PostfixSMTPサーバー（メールを送る）とDovecotIMAP/POP3サーバー（メールを受け取る）で動作するように設計されたModoboa（無料のオープンソースメールホスティング。Webで管理できる。ISCライセンス。Pythonプログラム）を使用してUbuntu20.04で独自の電子メールサーバーをセットアップする。また、既存のapache2.4上でModoboa管理画面を表示させ、nginx, uwsgiサービスを無効にする。これにより、メールサーバーとWebサーバーを同時に立ち上げる。

・無制限のメールボックスと無制限のメールドメイン
・MySQL/MariaDB、またはPostgreSQLデータベースをサポート（自動インストール）
・デフォルトではModoboaはnginxのWebサーバー（Port=25）を使用。WebメールクライアントとWebベースの管理パネルを提供するため。
・Webベースの管理パネルでメールエイリアスを簡単に作成できる
・Let's Encryptとの統合してSSL化
・amavisフロントエンドがあり、スパムをブロック。
・PostfixおよびDovecotと互換性あり

まずは、VPS、ドメイン名を購入する。RAM2G以上のもの（500M-1Gを使用）

# MXレコードを作成する（Mail Exchangeレコード）

RecordType: MX
Hostname: @
Address/Value: mail.<yourdomain>    e.g. mail.hogehoge.com
Time to Live(TTL): 90 seconds (あれば。）

# Modoboaインストーラーを使用してUbuntu20.04でメールサーバーをセットアップする

まずはパッケージの更新

```
$ sudo apt update
$ sudo apt upgrade -y
```

# GithubからModoboaのインストーラーをクローンするろおｔ
ダウンロードファイルを置けるDirectoryに移動してから、（私はユーザーのrootディレクトリ、/home/<username>/downloadを作っているので、そこへ移動）

```
git clone https://github.com/modoboa/modoboa-installer
```

gitがインストールされていなければ、

```
$ sudo apt-get update
$ sudo apt-get install git
```

を実行して、gitをインストール。

# PythonとModuleをインストール
ここでは説明しませんが、Python3をインストールしておいてください。
また、Python3.5以上であるならば、モジュールdistroをインストール。それ以下ならモジュールplatformをインストール。

```
$ pip install distro
```

# インストール前に構成ファイルを編集する


https://github.com/modoboa/modoboa-installer　のREADME.mdを参照しながら、次を実行。
yourdomain.comの部分は、自分のドメイン名に置き換えてください。

```
$ cd modoboa-installer
$ sudo python run.py --stop-after-configfile-check yourdomain.com
```

実行後、これが出ればOK.

```
Welcome to Modoboa installer!

Configuration file installer.cfg not found, creating new one.
```

installer.cfgが作られたことを確認してください。
それでは、構成ファイルであるinstaller.cfgを編集しましょう。

```
$ sudo nano installer.cfg
```

で、ファイルをOpen。以下を書き込む。
admin@example.comの部分を実際のメールアドレスに変更します。これは、アカウントの回復と重要な通知に使用されます。デフォルトの電子メールアドレスを使用すると、Let's Encryptの証明書を取得してインストールすることはできません。
デフォルトでは、構成ファイルの次の行に示されているように、PostgreSQLデータベースサーバーをインストールします。

```Installer.cfg
[certificate]
generate = true
type = letsencrypt

[letsencrypt]
email = admin@example.com

[database]
engine = postgres
host = 127.0.0.1
install = true
```

MariaDBデータベースサーバーを使用する場合は、エンジンをpostgresからmysqlに変更します。（ModoboaはMySQLの代わりにMariaDBをインストールします。）

```
[database]
engine = mysql
host = 127.0.0.1
install = true
```

ファイルを保存して閉じます。保存し終了するには、Ctrl+Xを押し、次にY、最後にEnterで保存します。

# メールサーバー名をホスト名として登録
mail.yourdomain.comの部分は、DomainのMXレコードに書き込んだ完全な形のドメイン名を入れる必要があります。

```
$ sudo hostnamectl set-hostname mail.yourdomain.com
```

# インストールの開始

まず、DNSレコードがインターネットに伝播されているかどうかを確認する必要があります。
使用するドメインレジストラによっては、DNSレコードが即座に伝播される場合と、伝播に最大24時間かかる場合があります。あなたは、https://dnsmap.io で、DNSの伝播を確認することができます。

メールサーバーのホスト名(yourdomain.com)を入力し、MXをプルダウンから選択。伝播されていることを確認してください。伝播されていれば、地図上に数多くの場所で、あなたのmail.yourdomain.comが表示されていれば、次に進んでインストールを開始してください。

DNSレコードがインターネット上にすでに伝播されている場合は、次のコマンドを実行してインストールを開始します。

```
$ sudo python3 run.py --interactive yourdomain.com
```

```
Welcome to Modoboa installer!

Warning:
Before you start the installation, please make sure the following DNS records exist for domain 'yourdomain.com':
  mail IN A   <IP ADDRESS OF YOUR SERVER>
       IN MX  yourdomain.com.

Your mail server will be installed with the following components:
modoboa automx amavis clamav dovecot nginx razor postfix postwhite spamassassin uwsgi radicale opendkim
```




# Webサーバーをnginxからapache2に変更する方法
Modoboaのデフォルトのインストーラーでは、自動的にnginxサーバーをインストールしてしまうため、Apache2を使用しているサーバーでは、Web管理画面が競合してしまう。よって、Apache2上でModoboaが動くようにする。

modoboaは/srv/modoboa/instanceがmodoboaプロジェクトのルートとなっている。wsgi.pyは/srv/modoboa/instance/instanceフォルダ内にある。これをapache2のVirtualHostのconf内で指定してやるとうまく動く。

まずは、apache2の/etc/apache2/sites-availableフォルダ内にmail.yourdomain.com.confファイルを作成。以下のような内容を書き込む。（mod_mdによるLet's EncryptでのSSL化を含んだファイルとなっています。）

```
MDomain mail.yourdomain.com
MDCertificateAgreement accepted

<VirtualHost *:443>

  SSLEngine on

  ServerName mail.yourdomain.com
  ServerAdmin yourmailaddress@gmail.com
  DocumentRoot /srv/modoboa/instance

  WSGIDaemonProcess mail.yourdomain.com.443 processes=2 threads=12 home=/srv/modoboa/instance python-home=/home/<username>/.virtualenvs/venv_mail python-path=/srv/modoboa/instance:/srv/modoboa/instance/instance:/srv/modoboa/env/lib/python3.8/site-packages
WSGIProcessGroup mail.yourdomain.com.443
  WSGIPassAuthorization On
  WSGIScriptAlias / /srv/modoboa/instance/instance/wsgi.py application-group=mail.yourdomain.com.443

  Protocols h2 http/1.1 acme-tls/1
  Alias /media/ /srv/modoboa/instance/media/
  Alias /sitestatic/ /srv/modoboa/instance/sitestatic/

  <Directory /srv/modoboa/instance/instance>
    <Files wsgi.py>
      Require all granted
    </Files>
  </Directory>

  <Directory /srv/modoboa/instance/media>
      Require all granted
  </Directory>

  <Directory /srv/modoboa/instance/sitestatic>
      Require all granted
  </Directory>

</VirtualHost>

<VirtualHost *:80>

  ServerName mail.yourdomain.com
  ServerAdmin koji.gotoda.dev@gmail.com
  DocumentRoot /srv/modoboa/instance
#  Redirect permanent / https://mail.yourdomain.com/

  WSGIDaemonProcess mail.yourdomain.com.443 processes=2 threads=12 home=/srv/modoboa/instance python-home=/home/<username>/.virtualenvs/venv_mail python-path=/srv/modoboa/instance:/srv/modoboa/instance/instance:/srv/modoboa/env/lib/python3.8/site-packages
  WSGIProcessGroup mail.yourdomain.com.80
  WSGIPassAuthorization On
  WSGIScriptAlias / /srv/modoboa/instance/instance/wsgi.py application-group=mail.yourdomain.com.80

  Protocols h2 http/1.1 acme-tls/1
  Alias /media/ /srv/modoboa/instance/media/
  Alias /sitestatic/ /srv/modoboa/instance/sitestatic/

  <Directory /srv/modoboa/instance/instance>
    <Files wsgi.py>
      Require all granted
    </Files>
  </Directory>

  <Directory /srv/modoboa/instance/media>
      Require all granted
  </Directory>

  <Directory /srv/modoboa/instance/sitestatic>
      Require all granted
  </Directory>

</VirtualHost>
```

Apache 2.2であれば、“Require all granted”のところを“Allow from all”に変更。
https://mail.yourdomain.com にアクセスし、以下のような画面が出れば完了。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/677977/45b43799-ba39-d60e-9583-4dc7450aa838.png)


# トラブル解消法（備忘録）
・すべてのサービスが起動したいるかを調べるために、それぞれのステータスを見てみる。

```
$ systemctl status postfix 
$ systemctl status dovecot 
$ systemctl status nginx 
$ systemctl status mariadb 
$ systemctl status clamav-daemon 
$ systemctl status amavis 
$ systemctl status uwsgi 
$ systemctl status Supervisor
```

再起動時に自動で起動しないアプリは起動するようにする。私の場合、clamav-daemonが停止していると、送信元のチェック時に約４０秒ほどかかり非常に遅くなった。clamav-daemonが動いているときは承認から送信までの時間が数秒で終わるようになった。
スタートアップに登録しておこう。

```
sudo update-rc.d clamav-daemon defaults
```



・confファイルに

```
<Location "/md-status">
  SetHandler md-status
</Location>
```
を追加することによって、https://yourdomain.com/md-status　にアクセスすると、mod_mdの状態を確認することができる。

・SSL証明書
私の場合、すでにapache2でWebServerを立ち上げ、mod_mdにてSSL化を行っていたので、mail.yourdomain.comにも同様にmod_mdでSSL化をした。よって、modoboaのSSL化を使用していないので、dovecotで使用する証明書がapache2の方に格納されているので、dovecotが起動しなかった。
dovecotとpostfixが参照している場所にapache2が獲得した証明書（pemファイル）をコピーする必要がある。しかも、自動的に。
自動化のためにはcronを使ってバッチ処理を行う。

mod_mdを使用したとき、証明書のある場所は/etc/apache2/md/domainsの中のそれぞれのドメイン名のフォルダの中にある。した二つのpemファイルである。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/677977/a505b849-6954-7064-719d-cdc52c334513.png)

/etc/dovecot/conf.d　ディレクトリ内の　10-ssl.conf　を開き、ssl_cert_fileとssl_key_fileの場所をみるて、ファイル名をfullchain.pemからpubcert.pemに変更しておく。

```10-ssl.conf
# PEM encoded X.509 SSL/TLS certificate and private key. They're opened before
# dropping root privileges, so keep the key file unreadable by anyone but
# root. Included doc/mkcert.sh can be used to easily generate self-signed
# certificate, just make sure to update the domains in dovecot-openssl.cnf
ssl_cert = </etc/letsencrypt/live/mail.take-my-order.com/pubcert.pem
ssl_key = </etc/letsencrypt/live/mail.take-my-order.com/privkey.pem
```

同様にpostfixのmain.cf内の証明書のpathも確認、変更する。
/etc/postfixフォルダに移動して、

```
$ sudo nano main.cf
```

43,44行目あたりを記載がある。
ファイル名をfullchain.pemからpubcert.pemに変更しておく。

```main.cf
smtpd_tls_key_file = /etc/letsencrypt/live/yourdomain.com/privkey.pem
smtpd_tls_cert_file = /etc/letsencrypt/live/yourdomain.com/pubcert.pem
```

次にapache2の証明書をdovecotとpostfixの参照場所にコピーし、権限を変更するスクリプトを以下のようにどこかのフォルダに用意する。

```\job\cronjob\copy_letsencrypt_pem.py
import os
import shutil
import pwd
import grp

PATH_APACHE2_PUBCERT = "/etc/apache2/md/domains/mail.yourdomain.com/pubcert.pem"
PATH_APACHE2_PRIVKEY = "/etc/apache2/md/domains/mail.yourdomain.com/privkey.pem"

PATH_LETSENCRYPT_PUBCERT = "/etc/letsencrypt/live/mail.yourdomain.com/pubcert.pem"
PATH_LETSENCRYPT_PRIVKEY = "/etc/letsencrypt/live/mail.yourdomain.com/privkey.pem"

shutil.copyfile(PATH_APACHE2_PUBCERT, PATH_LETSENCRYPT_PUBCERT)
shutil.copyfile(PATH_APACHE2_PRIVKEY, PATH_LETSENCRYPT_PRIVKEY)

uid = pwd.getpwnam("www-data").pw_uid
gid = grp.getgrnam("www-data").gr_gid
os.chown(PATH_LETSENCRYPT_PUBCERT, uid, gid)
os.chown(PATH_LETSENCRYPT_PRIVKEY, uid, gid)
os.chmod(PATH_LETSENCRYPT_PUBCERT, 0o755)
os.chmod(PATH_LETSENCRYPT_PRIVKEY, 0o755)
```

次にバッチ処理を設定する。rootで
```
crontab -e
```

[1]-[3]の選択画面が出たら、nanoを選ぶと楽でしょう。
次回からは選択画面は出ません。
最後の行にジョブを書き込む。時間はUTC。５つの数字を書き込むが左から、分、時、となっていく。
毎日処理するので、以下のように設定する。

```
# Edit this file to introduce tasks to be run by cron.
#
# Each task to run has to be defined through a single line
# indicating with different fields when the task will be run
# and what command to run for the task
#
# To define the time you can provide concrete values for
# minute (m), hour (h), day of month (dom), month (mon),
# and day of week (dow) or use '*' in these fields (for 'any').
#
# Notice that tasks will be started based on the cron's system
# daemon's notion of time and timezones.
#
# Output of the crontab jobs (including errors) is sent through
# email to the user the crontab file belongs to (unless redirected).
#
# For example, you can run a backup of all your user accounts
# at 5 a.m every week with:
# 0 5 * * 1 tar -zcf /var/backups/home.tgz /home/
#
# For more information see the manual pages of crontab(5) and cron(8)
#
# m h  dom mon dow   command
40 19 * * * python3 /job/cronjob/copy_letsencrypt_pem.py; touch /job/cronjob/RUN_copy_letsencrypt_pem
```

19+9(時差）は28時。午前４時４０分にジョブが走ることになる。
touchの部分は、ジョブが走った最後の時間を確認するためのものである。RUN_copy_letsencrypt_pemファイルの変更時刻を見れば、ジョブの走った最後の時間がわかる。

copy_letsencrypt_pem.pyを一度実行し、ファイルをコピーしてサーバーをリスタートしよう。

```
$ python3 /jop/cronjob/copy_letsencrypt_pem.py
```

```
$ sudo service dovecot stop
$ sudo service dovecot start
$ sudo service postfix stop
$ sudo service postfix start
```
でdovecotとpostfixを再起動。pemファイルを読み込ませる。

```
$ service --status-all
$ systemctl status dovecot
$ systemctl status postfix
```
とかで起動していることを確認する。



・/var/logフォルダ内のmail.logを開いて、正常に起動しているかを確認
postfixが動いてない場合、port25がほかに使用されていないかチェック。

```
$ sudo netstat -lnp |grep :25
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/677977/95f197f6-a898-16ae-4972-c2d1e7ab8c71.png)
おっと！使用されているので、起動できなかった。

```
$ ps aux |grep 637
```
でPIDから何がRUNしているかを確認して、KILL。さらに、Disableしておく。
私の場合はexim4というものが立ち上がっていた。必要ないので、消しておく。

```
$ sudo systemctl disable exim4
```

・apache2にセーブされている証明書を/etc/letsencrypt/live/domains/yourdomain.comフォルダにコピーして（自動コピー）最新のものに保つ方法。
cronをつかって、Apache2のmd_modがKeyファイルを更新したら、それをコピーペーストするジョブを毎日走らせておく。



# メールクライアントの設定
Outlook2016を使用。ほかのメーラーでもそう大きくは違わないでしょう。
まず、使用しているportをチェック。

```
$ sudo netstat -lnp
```
私の場合、

メール受信（dovecot側）設定は
IMAP
mail.yourdomain.com
SSL/TSL
port 993

メール送信（postfix側）設定は
SMTP
mail.yourdomain.com
STARTTSL
port 587

で正常に動作した。
ちなみに、SPF、DKIM、DMARCなどを有効にしないと、GMAILでの受信だと、ジャンクフォルダに配信されてしまった。

Outlook以外だと、
SMTPポート：25
送信ポート：587（Microsoft Outlookメールクライアントを使用する場合は465）
IMAPポート：143および993
を試してみよう。


# 電子メールの配信性能を改善する　
あと少しで、あなたのメールサーバーも１０点満点のすこあを獲得できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/677977/43c15fc1-85fb-7a3a-e4f8-bcad841223ca.png)

######A2HostingでのDomain設定を例にしています。

###SPFレコード
SPF（Sender Policy Framework）レコードは、電子メールを送信できるホストまたはIPアドレスを指定し、そのホストまたはIPアドレスのみがドメインに電子メールを送信できるようにするレコードです。
ドメインに、次のような新しいTXTレコードを作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/677977/ddd7e6c1-98c4-b15b-3137-e0847c4fd7e6.png)

###DKIMレコード
メールサーバーのWeb管理画面からDKIMのPublicKeyを取得する。
ドメイン名をクリックして、詳細画面を開く。
以下の画面で"Show Key"をクリック。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/677977/8997f0f2-94a1-0d21-f249-fe06ddeab567.png)

下部のBind/nameed Formatのグレーの部分に、あなたが設定したDKIMのフレーズが入っているはずなので、<yourDKIMword>._domainkey をレコードのHostNameに入れる。
内容には、すべての"を消し、v=DKIMから始まり、最後までつなげたものを入力する。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/677977/652a37af-29c5-98ff-9e63-6525543aef5a.png)

サンプル
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/677977/1d2f6007-6e5c-ed75-e57d-e8fef6a22743.png)
最後まで内容が見えませんが、ラストは私の例ですとDAQABまでです。

DKIMレコードがインターネットに伝播するまでに時間がかかる場合があります。使用するドメインレジストラによって、DNSレコードがすぐに伝播する場合と、伝播に最大24時間かかる場合があります。あhttps://www.dmarcanalyzer.com/dkim/dkim-check/　で、Selectorにあなたの設定したDKIMのフレーズ、あとはドメイン名を入力することにより、伝播を確認できます。伝播されていれば、公開KEYが表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/677977/83a8f7d5-1aff-d649-751c-2e1ad3952088.png)


###DMARCレコード
DMARCはドメイン名が電子メールのなりすましによって使用されるのを防ぎます。

DMARCレコードを作成するには、DNSマネージャーに移動してTXTレコードを追加します。名前フィールドに_dmarcと入力します。内容は以下のもののyourdomain.comを自分のものに変更し、入力します。

```
v=DMARC1; p=none; pct=100; rua=mailto:dmarc-reports@yourdomain.com
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/677977/32d0401b-ec70-fc12-86ca-c5082d325cdd.png)


あとは、サーバーを再起動し、インターネットに上記の３つのレコードが伝播すれば、１０点満点のメールサーバーになります。ジャンクメールになる確率もぐっと下がります。


・追加ドメイン登録時の注意事項ですが、ドメインの管理会社によって、mail.yourdomain.comにIP
IPを設定した方がいい場合があるので、設定しておこう。これがないとメールが届かない場合がある。

例えば、Freenomでドメインを購入した場合、次のようなレコードを追加しておこう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/677977/3d6f2b84-07cf-5d2b-5018-73df316c2b68.png)