Ubuntu 22.04 でメールサーバーを作ったのでメモ

令和にもなって自分でメールサーバーを作ってみたのでメモ。

OS は Ubuntu 22.04。

パッケージ更新後に自動的に再起動

メールとは関係ないけど apt で再起動が必要な更新があった場合は自動的に再起動するようにした。

/etc/apt/apt.conf.d/50unattended-upgrades:

Unattended-Upgrade::Automatic-Reboot "true";

Lets Encrypt

TLS 証明書を作るために certbot をインストール。自分はさくらのクラウドのDNSを使ってるのでそれ用のモジュールも追加。

# apt install certbot python3-certbot-dns-sakuracloud

https://certbot-dns-sakuracloud.readthedocs.io/en/stable/ に従って /root/.secrets/certbot/sakuracloud.ini を作っておく:

dns_sakuracloud_api_token = XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
dns_sakuracloud_api_secret = XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

証明書作成:

# certbot certonly --dns-sakuracloud --dns-sakuracloud-credentials ~/.secrets/certbot/sakuracloud.ini -m hoge@example.com -d \*.example.com -d \*.example.net

証明書の期限が近づいたら自動的に更新するように cron に設定:

/etc/cron.weekly/letsencrypt:

#!/bin/bash
certbot renew

[追記] ↑ 自動的に /etc/cron.d/certbot が作られるからこれは不要だった。

Postfix

SMTP サーバーとして Postfix をインストール。

# apt install postfix postfix-policyd-spf-python

root 宛のメールは自分に転送するように設定。

/etc/aliases:

root: tommy
# newaliases

master.cf の submission(587ポート) と smtps(465ポート)のコメントを外して有効にする。

/etc/postfix/master.cf:

submission inet n       -       y       -       -       smtpd
  -o syslog_name=postfix/submission
  -o smtpd_tls_security_level=encrypt
  -o smtpd_sasl_auth_enable=yes
  -o smtpd_tls_auth_only=yes
  -o smtpd_reject_unlisted_recipient=no
  -o smtpd_client_restrictions=$mua_client_restrictions
  -o smtpd_helo_restrictions=$mua_helo_restrictions
  -o smtpd_sender_restrictions=$mua_sender_restrictions
  -o smtpd_recipient_restrictions=
  -o smtpd_relay_restrictions=permit_sasl_authenticated,reject
  -o milter_macro_daemon_name=ORIGINATING
smtps     inet  n       -       y       -       -       smtpd
  -o syslog_name=postfix/smtps
  -o smtpd_tls_wrappermode=yes
  -o smtpd_sasl_auth_enable=yes
  -o smtpd_reject_unlisted_recipient=no
  -o smtpd_client_restrictions=$mua_client_restrictions
  -o smtpd_helo_restrictions=$mua_helo_restrictions
  -o smtpd_sender_restrictions=$mua_sender_restrictions
  -o smtpd_recipient_restrictions=
  -o smtpd_relay_restrictions=permit_sasl_authenticated,reject
  -o milter_macro_daemon_name=ORIGINATING

受信メールを SPF チェックする。

/etc/postfix/master.cf:

spfcheck  unix  -       n       n       -       0       spawn
  user=policyd-spf argv=/usr/bin/policyd-spf /etc/postfix-policyd-spf-python/policyd-spf.conf

main.cf はこんな感じで。そんなに特殊なことはしてないはず。

/etc/postfix/main.cf:

compatibility_level = 3.6
alias_maps = hash:/etc/aliases
myhostname = host.example.com
mydestination = $myhostname, $mydomain
home_mailbox = Maildir/
smtpd_relay_restrictions =
 permit_mynetworks
 permit_sasl_authenticated
 reject_unauth_destination
 check_policy_service unix:private/spfcheck
smtpd_helo_required = yes
mailbox_size_limit = 0
message_size_limit = 102400000
recipient_delimiter = +-
strict_rfc821_envelopes = yes
smtpd_use_tls = yes
smtpd_tls_cert_file = /etc/letsencrypt/live/example.com/fullchain.pem
smtpd_tls_key_file = /etc/letsencrypt/live/example.com/privkey.pem
smtpd_tls_loglevel = 1
smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth
mua_client_restrictions =
mua_helo_restrictions =
mua_sender_restrictions =

IMAP は Dovecot を使うので SASL として Dovecot を使用するのと、SPF チェック用の設定 check_policy_service をしているくらい。

mua_*_restrictions は master.cf の submission と smtps に書かれてるので、設定しておかないと warning が出るので空で設定しておく。

Dovecot

IMAP サーバーとして Dovecot をインストール。

# apt install dovecot-imapd

143 ポートは使わないので無効化。

/etc/dovecot/conf.d/10-master.conf:

service imap-login {
  inet_listener imap {
    port = 0
  }
  inet_listener imaps {
    port = 993
    ssl = yes
  }

Postfix 認証用の Socket ファイルを指定。

/etc/dovecot/conf.d/10-master.conf:

service auth {
〜〜
  unix_listener /var/spool/postfix/private/auth {
    mode = 0666
    user = postfix
    group = postfix
  }
〜〜
}

メールボックスは各ユーザーのホーム直下の Maildir

/etc/dovecot/conf.d/10-mail.conf:

mail_location = maildir:~/Maildir

TLS 証明書は Lets Encrypt のやつ。

/etc/dovecot/conf.d/10-ssl.conf:

ssl_cert = </etc/letsencrypt/live/example.com/fullchain.pem
ssl_key = </etc/letsencrypt/live/example.com/privkey.pem

パスワードはデフォルトで OS のユーザーパスワードと同じものが使われるけど、外から叩かれるものなので OS のパスワードとは変えておきたい。

/etc/dovecot/conf.d/10-auth.confauth-system.conf.ext をコメントアウトして1行追加:

#!include auth-system.conf.ext
!include auth-hoge.conf.ext

専用の認証設定ファイルを作成。

/etc/dovecot/conf.d/auth-hoge.conf.ext:

passdb {
  driver = passwd-file
  args = scheme=SHA512-CRYPT username_format=%u /etc/dovecot/users
}

userdb {
  # <doc/wiki/AuthDatabase.Passwd.txt>
  driver = passwd
  # [blocking=no]
  #args = 

  # Override fields from passwd
  #override_fields = home=/home/virtual/%u
}

passdbauth-passwdfile.conf.ext から、userdbauth-system.conf.ext からコピー。

パスワードファイルの /etc/dovecot/users はこんな形式:

ユーザー名:{SHA512-CRYPT}$6$Gm.4X5ktmas.00pC$z9zEBRJvyyAtuczb81eyr26K/sdjkt9uZ.9mgQT1RR6s6JijHxdnyhQtDGnu70DV9v9Ijkn0bvWYFfkOFWZij0

ハッシュ文字列はこんな風にして作成できる:

# doveadm pw -s SHA512-CRYPT -p hogehoge
{SHA512-CRYPT}$6$Gm.4X5ktmas.00pC$z9zEBRJvyyAtuczb81eyr26K/sdjkt9uZ.9mgQT1RR6s6JijHxdnyhQtDGnu70DV9v9Ijkn0bvWYFfkOFWZij0

fail2ban

Postfix や Dovecot の認証が同じIPアドレスから複数回失敗したときにそのIPアドレスからの接続をブロックするために fail2ban をインストール。デフォルトで SSH 認証にも効くようになってる。

# apt install fail2ban

/etc/fail2ban/jail.d/postfix.conf:

[postfix-sasl]
enabled = true

/etc/fail2ban/jail.d/dovecot.conf:

[dovecot]
enabled = true

デフォルトでは10分以内に5回認証に失敗したら10分間ブロックする。

証明書更新時にサービスをリロードする

はてぶで、証明書更新時にサービスをリロードしないといけないのでは…という指摘があったので追記。

たしかにその通りでした 🙏

/etc/letsencrypt/renewal-hooks/post 配下に実行ファイルを置いておくと証明書が更新されたときに実行してくれるので、次のようなファイルを実行権つきで置いておく。

/etc/letsencrypt/renewal-hooks/post/postfix

#!/bin/bash
/usr/sbin/postfix reload

/etc/letsencrypt/renewal-hooks/post/dovecot

#!/bin/bash
/usr/sbin/dovecot reload

Postfix は証明書ファイルは smtpd プロセスが読み込んでて、smtpd プロセスはある程度動作したら自動的に再起動するので、この処理は実はやらなくてもいい。けどちゃんとやっといた方が安心感はある。

Dovecot は imap-login プロセスが TLS の処理をしてて、これは接続毎に起動されるんだけど、証明書ファイルの読み込みは config という別のプロセスがやっててこれは明に指示しないと再読込してくれないのだった。

DNS の設定

ちゃんと書いておいた方がいいかもしれないと思って追記。

上にも書いたけど DNS はさくらのクラウドのサービスを使ってる。1ゾーンあたり44円/月。安い。

メールサービスなので、MX と A と SPF(TXT) と PTR は必須。 こんな感じで設定:

@     MX   10 mx.example.com.
@     TXT  v=spf1 mx -all
mx    A    192.0.2.1
host  A    192.0.2.1

最後の host(host.example.com)は、Postfix の myhostname に書いたホスト名。これを PTR に設定しておく。 MTA によってはクライアントのIPアドレスを逆引きして正引きした結果がそのIPアドレスを含まないと接続を拒否されることがあるので。 PTR はサーバーのIPアドレスを管理してる業者じゃないと設定できない。業者によってやり方は異なる。 Oracle Cloud は無料で使えるんでそこにメールサーバー立てようかと思ってたんだけど、無料だと PTR を設定できないので断念した。

しかし大昔は自力で DNS サーバーも立ててたんだけど面倒くさくなってしまったな…。