自宅サーバー構築譚：DockerコンテナにPostfixをインストール / 全メール受信サーバー

（2023/11/15 追記ここから）
この記事の設定ですと、「自分のドメインの存在しないユーザー宛メールはエラーメールとなって転送されてくる」という挙動になります。これを（なるべく）抑制する為に微調整した記事を書きました。完全ではありませんが、御参考になれば幸いです。
[私的サーバー構築日誌：Postfix](https://qiita.com/katz_engineer/items/637f6708ed83b58f30ef)
（2023/11/15 追記ここまで）

# 能書き

[自宅サーバー構築譚：基本構想](https://qiita.com/katz_engineer/items/cb592be44daa28a51d9b)に基づく自宅サーバー構築、[Ubuntu22.04LTSインストールその2](https://qiita.com/katz_engineer/items/033471b69143bf76650e)の続きです。

スミマセン。ここで謝っておきます。私、メールサーバーを舐めてました。メールサーバーは自宅サーバーの華だとか、生意気を言って申し訳ありませんでした。:bow_tone1:

今、メールサーバー(MTA)を立てるのは大変なんですね。迷惑メール対策でガッチガチに固められて、気を使わなきゃいけない点が増えてます。技術的にかなり面倒な感じ。そしてGoogleとかの世界的大手メールサービスがそれを強要してます。やって出来ない事はないけれど、とても大変です。

と言う訳で、私の自宅サーバーにおけるメールサーバー(MTA)は、志を低くします。

# 目標

[メールサーバー関連作業初回](https://qiita.com/katz_engineer/items/9e8716c8bdf2bb1a54a8)に掲げた作業の題目を再掲します。

1. DovecotのLMTP ←完了
1. DovecotのIMAP ←完了
1. Postfix ←イマココ

そういう訳で。今回はPostfixをDockerコンテナに立てます。

そして志を低く、外部へはメールを一切送信しないサーバーとします。エラーメールも出しません。全ドメインの全ユーザーを受信します。

外部へ発信しないのでSMTP-Authも無しです。

これにもリスクがあるんですけども。何かの間違いで迷惑メールの攻撃対象になっちゃったりなんかしたら、山のようなメールをすべて受け取る事になってしまいます。

もしかするとPostfixの設定をきちんとすれば対策できるのかも知れませんが、私にそこまでの知識がありません。調べても、そういう設定に関する記事が出てきませんし。本格的にPostfixの勉強をしないとダメそうです。仕方が無いので、このリスクは甘受する事にします。

# 参考文献

Postfixの基本的な設定に関する情報。

- [CentOS 7 の Postfix で独自ドメインの設定 - Qiita](https://qiita.com/bezeklik/items/438eadbdb06672f3c3b6)
- [LMTP_README - Postfixのぺーじ － 和訳ドキュメント (2.0.x)](http://www.postfix-jp.info/trans-2.0/readme/LMTP_README.jp)

Postfixを受信専用にする為の関連情報を集めました。ちょっと数が多いです。

- [Postfixで特定のドメイン宛以外のメールを削除したい - KITA-SAN.BLOG](https://kita-san.blog/computer-related/postfix-discard/)
- [Postfixアドレス書き換え](http://www.postfix-jp.info/trans-2.3/jhtml/ADDRESS_REWRITING_README.html)
- [Postfix の拡張メールアドレス - tmtms のメモ](https://blog.tmtms.net/entry/2014/12/04/postfix-ext-address)
- [Postfix 設定パラメータ](http://www.postfix-jp.info/trans-2.1/jhtml/postconf.5.html)
- [[Postfix]特定のドメインのみ受信しそれ以外は別アドレスに転送する - OSSリファレンス](https://infraref.blogspot.com/2011/06/postfix.html)
- [【postfix】送信元（From）によるメール拒否（smtpd_sender_restrictions ） - server-memo.net](https://www.server-memo.net/server-setting/postfix/smtpd_sender_restrictions.html)
- [regexp_table - Postfix 正規表現テーブルの書式](http://www.postfix-jp.info/trans-2.1/jhtml/regexp_table.5.html)
- [Postfix バーチャルドメインホスティング Howto](http://www.postfix-jp.info/trans-2.1/jhtml/VIRTUAL_README.html)
- [バーチャルドメイン - Postfix チュートリアル](http://tmtm.org/ja/postfix/tutorial/virtual.html)

DockerにPostfixをインストールする方法は、この記事を参考にしました。

- [UbuntuのDockerコンテナにPostfixをインストールする](https://zenn.dev/flyingbarbarian/articles/5bb1d38b1ada40)

なお、きっちりと送信も可能なメールサーバーにした事例を見つけましたので、参考までに。

- [Ubuntu 22.04にPostfix+Dovecot(SASL認証)を構築しGmail/Yahooメールの迷惑メール判定に合格するまで - 星空の下のプログラミング](https://likesapphire.jp/20221214/postfix-dovecot-sasl-opendkim/)

そこで出てくるなりすましメール対策の解説。

- [送信ドメイン認証（SPF / DKIM / DMARC）の仕組みと、なりすましメール対策への活用法を徹底解説 - エンタープライズIT COLUMNS - IIJ](https://ent.iij.ad.jp/articles/172/)

# 準備

## Dockerコンテナ構築用ディレクトリ

まず、準備するフォルダは`/opt/postfix`とします。

```console
sudo mkdir /opt/postfix
```

```console
sudo chgrp docker /opt/postfix
```

```console
sudo chmod g+w /opt/postfix
```

これらの操作の結果、`/opt/postfix`ディレクトリの権限はこうなります。

```console
$ ls -dl /opt/postfix
drwxrwxr-x 2 root docker 2 Jun  4 11:34 /opt/postfix
```

## Postfix設定ファイル

上記のディレクトリの中に、Postfix関連ファイルを準備します。

Postfixの設定`main.cf`はこんな感じにしました。

- ドメイン`example.com`は、説明用の仮設定です。お金を出して買った自分だけのドメインに置き換えて下さい。
- IPアドレス`172.16.1.3`とポート番号`24`は、[Dovecotで設定したLMTPサーバー](https://qiita.com/katz_engineer/items/9e8716c8bdf2bb1a54a8)に合わせて下さい。LXDコンテナではなくて、そのホストマシンを設定します。
- ユーザー`taro`は、色んな宛先に来たメールを受け取る、転送先ユーザーです。

```console
MYDOMAIN=example.com
LMTP_IPADDR=172.16.1.3
LMTP_PORT=24
MYUSER=taro
```

```console
cat <<___ >/opt/postfix/main.cf
compatibility_level = 3.6

mydomain = $MYDOMAIN
myhostname = mail.\$mydomain
myorigin = \$mydomain

inet_protocols = ipv4
inet_interfaces = all

mydestination = $MYDOMAIN
local_recipient_maps =

mynetworks = 127.0.0.0/8

alias_maps = hash:/etc/aliases
mailbox_transport = lmtp:inet:$LMTP_IPADDR:$LMTP_PORT

smtpd_banner = \$myhostname ESMTP
biff = no

readme_directory = no

virtual_alias_domains = regexp:/etc/virtual_domains
virtual_alias_maps = regexp:/etc/virtual_users

mailbox_size_limit = 0
recipient_delimiter = +
___
```

全ドメインの全ユーザーを受信する為に、Postfixの仮想ドメインを利用します。その設定は下記の通りです。`$MYDOMAIN`以外のドメイン宛に来たメールは、全て`$MYUSER`に転送します。

```console
cat <<___ >/opt/postfix/virtual_domains
!/^$MYDOMAIN\$/ OK
___

cat <<___ >/opt/postfix/virtual_users
!/^.*@$MYDOMAIN\$/ $MYUSER@$MYDOMAIN
___
```

# Dockerコンテナ構築

## 関連ファイルの用意

`docker-compose.yml`ファイルはこうなります。

```console
cat <<___ >/opt/postfix/docker-compose.yml
version: '3.8'
services:
  postfix1:
    build: .
    volumes:
      - ./main.cf:/etc/postfix/main.cf
      - ./virtual_domains:/etc/virtual_domains
      - ./virtual_users:/etc/virtual_users
    ports:
      - "25:25"
___
```

そして`Dockerfile`ファイルです。

```console
cat <<___ >/opt/postfix/Dockerfile
FROM ubuntu:22.04
RUN apt update && apt upgrade -y
RUN DEBIAN_FRONTEND=noninteractive apt install postfix -y
COPY entrypoint.sh /
ENTRYPOINT ["/entrypoint.sh"]
___
```

最後に、起動時に実行される`entrypoint.sh`です。下記のようになります。内容の詳細は[参考文献](https://zenn.dev/flyingbarbarian/articles/5bb1d38b1ada40#entrypoint.sh)を参照ください。

```console
cat <<___ >/opt/postfix/entrypoint.sh
#!/bin/bash
postfix start
postmap /etc/virtual_domains
postmap /etc/virtual_users
cp /etc/resolv.conf /var/spool/postfix/etc/resolv.conf
postfix reload
tail -f /dev/null
___
chmod +x /opt/postfix/entrypoint.sh
```

## 構築

特別な事は何もありません。

```console
cd /opt/postfix
docker compose up -d
```

# 動作確認

## 知らないドメイン宛

適当なドメインの適当なメールアドレスに送信してみます。

```console:ホスト側
nc -C 172.16.1.3 25 <<___
ehlo sender.home
mail from: ubuntu@example.com
rcpt to: hanako@test.home
data
From: ubuntu@example.com
To: hanako@test.home
Subject: test mail

hello, world
.
quit
___
```

知らないドメインの知らない人宛のメールは`$MYUSER`（今回は`taro`）に届きます。今回はIMAPを使わず、`/home/taro/Maildir`を直接覗いてみます。新着メールは`Maildir/new`ディレクトリに置かれる筈です。

```console:ホスト側
lxc shell dovecot1
```

```console:LXDコンテナ内
cd /home/taro/Maildir/new
ls -t | head -n1 | xargs cat
exit
```

実行結果はこんな感じになります。

```console:LXDコンテナ内
# cd /home/taro/Maildir/new
# ls -t | head -n1 | xargs cat
Return-Path: <ubuntu@example.com>
Delivered-To: taro@example.com
Received: from mail.example.com ([192.168.0.1])
        by dovecot1 with LMTP
        id RiRsKroZfGQeGQAA9sUnBg
        (envelope-from <ubuntu@example.com>)
        for <taro@example.com>; Sun, 04 Jun 2023 13:57:30 +0900
Received: from sender.home (unknown [172.16.1.3])
        by mail.example.com (Postfix) with ESMTP id A02A93A8
        for <hanako@test.home>; Sun,  4 Jun 2023 04:57:30 +0000 (UTC)
From: ubuntu@example.com
To: hanako@test.home
Subject: test mail

hello, world
# exit
logout
```

## 実在ユーザー宛

`$MYDOMAIN`ドメインの実在ユーザー宛だと、きちんとその人に届きます。

```console:ホスト側
nc -C 172.16.1.3 25 <<___
ehlo sender.home
mail from: ubuntu@example.com
rcpt to: ubuntu@example.com
data
From: ubuntu@example.com
To: ubuntu@example.com
Subject: test mail

hello, world
.
quit
___
```

```console:ホスト側
lxc shell dovecot1
```

```console:LXDコンテナ内
cd /home/ubuntu/Maildir/new
ls -t | head -n1 | xargs cat
exit
```

実行結果。

```console:LXDコンテナ内
# cd /home/ubuntu/Maildir/new
# ls -t | head -n1 | xargs cat

Return-Path: <ubuntu@example.com>
Delivered-To: ubuntu@example.com
Received: from mail.example.com ([192.168.0.1])
        by dovecot1 with LMTP
        id gITxHiojfGRDGQAA9sUnBg
        (envelope-from <ubuntu@example.com>)
        for <ubuntu@example.com>; Sun, 04 Jun 2023 14:37:46 +0900
Received: from sender.home (unknown [172.16.1.3])
        by mail.example.com (Postfix) with ESMTP id 728883B0
        for <ubuntu@example.com>; Sun,  4 Jun 2023 05:37:46 +0000 (UTC)
From: ubuntu@example.com
To: ubuntu@example.com
Subject: test mail

hello, world
# exit
logout
```

# 仕舞い

不正中継しないよう、全メールを黙って受信してしまう設定が出来ました。これを使えば、メール送信のテストなんかも可能になりそうです。

ともあれ、これで「連絡を受けるだけ」の、人様に迷惑を掛けないメールサーバーが出来ました。やったね:thumbsup_tone1: