勉強したことのメモ

Webエンジニア / プログラマが勉強したことのメモ。

Podmanでメールサーバ用コンテナ(postfix / dovecot)を導入する方法

  Podman サーバー

かなり前にCentOS6系にメールサーバを導入する方法をメモしたが、これをPodmanコンテナで実現したい。まず、送信メールはGmail等で迷惑メール扱いされても問題無く、受信したメールはThunderbirdで確認できるようにしたい。また、コンテナのメモリ割り当てはできる限り少なくしたい。以下に対応方法をメモ。

 

やりたいこと

  • PHPからメールサーバ用コンテナを通してメール送信
  • 受信メールはThunderbird等、クライアントソフトから確認できるようにしたい
  • メールサーバ用コンテナのメモリ割り当ては極力少なくしたい(100MB以下)

尚、勉強中・本番運用はするかどうかわからないため以下の通り適当な部分もある。

  • セキュリティ関連はあまり意識しない
  • 受信側(Gmail等)で迷惑メール扱いされてもいい
  • WebコンテナやDBコンテナのdocker-compose.ymlとは切り離す(メールサーバは個別で起動・削除する想定)

 

環境について

VPS

今回はKAGOYA CLOUD VPSのCPU1コア / メモリ1GBプランで作業した。SSH接続は公式案内の通り以下でログインできる。

  • 接続ポート -> 22
  • ユーザ名 -> root
  • パスワード or 秘密鍵 -> インスタンス作成時に選択したもの

ホスト(VPS)側

  • AlmaLinux 8.10 (Cerulean Leopard)

コンテナ側

  • podman version 4.9.4-rhel

 

対応方法

Dockerfile

# 最小構成のalpine linuxイメージを指定
FROM alpine:latest

# dovecot(受信サーバ) / postfix(送信サーバ) / shadow(ユーザーやグループの管理ユーティリティ) / linux-pam(ユーザーの認証処理の管理用) / bash(シェル環境)の追加
RUN apk add --no-cache postfix dovecot shadow linux-pam bash

# ユーザー作成とパスワード設定(mail_user / mail_passwordは適宜変更)
RUN adduser -D -h /home/mail_user mail_user && \
    echo "mail_user:mail_password" | chpasswd && \
    mkdir -p /home/mail_user/Maildir/new \
             /home/mail_user/Maildir/cur \
             /home/mail_user/Maildir/tmp && \
    chown -R mail_user:mail_user /home/mail_user && \
    chmod -R 700 /home/mail_user/Maildir

# 各種設定ファイルの配置
COPY main.cf /etc/postfix/main.cf
COPY dovecot.conf /etc/dovecot/dovecot.conf
COPY users /etc/dovecot/users
COPY entrypoint.sh /entrypoint.sh

# postfix / dovecot設定ファイルのパーミッション変更、コンテナ起動時に実行されるスクリプト(entrypoint.sh)に実行権限を付与
RUN chmod 644 /etc/postfix/main.cf /etc/dovecot/dovecot.conf && \
       chmod +x /entrypoint.sh

# ネットワークポートを指定
EXPOSE 25 143

# 最初に実行するスクリプトを指定
CMD ["/entrypoint.sh"]

dovecot.conf

# バージョン指定
dovecot_config_version = 2.4.0
dovecot_storage_version = 2.4.0

# IMAP受信を許可
protocols {
  imap = yes
}

# すべてのIPv4アドレスからの接続を許可
listen = *

# パスフレーズの送信方法。平文を許可
auth_mechanisms = plain login
auth_allow_cleartext = yes

# パスワードファイルのパス
passdb passwd-file {
  passwd_file_path = /etc/dovecot/users
}

# ユーザーDBファイルのパス
userdb passwd-file {
  passwd_file_path = /etc/dovecot/users
}

# メールの保存形式
mail_driver = maildir

# メールの保存先パス
mail_path = ~/Maildir

# 暗号化設定
ssl = no

# 本番運用時に暗号化をyesにする場合は以下で証明書ファイルの場所も指定する。また、ボリューム設定でマウントも必要。
#ssl_cert = </etc/letsencrypt/live/path/to/fullchain.pem
#ssl_key = </etc/letsencrypt/live/path/to/privkey.pem

users

まず、以下でパスワードを生成する。

podman run --rm alpine:latest mkpasswd -m sha-512 【パスワード】

以下の形でusersファイルを作成する。

ユーザ名:{SHA512-CRYPT}【生成したパスワード】

例としてユーザーが「mail_user」で生成したパスワードが「xxxxx」の場合は以下になる。

mail_user:{SHA512-CRYPT}xxxxx

main.cf

# 動作互換性バージョン
compatibility_level = 2

# ホスト名とドメインの設定
myhostname = mail.test.com
mydomain = test.com
myorigin = $myhostname

# 全てのインターフェイスからの接続を許可
inet_interfaces = all

# IPv4のみ許可
inet_protocols = ipv4

# 指定したドメイン宛てに受信した場合、転送せずサーバ内に保存
mydestination = $myhostname, localhost.$mydomain, localhost, $mydomain

# メール保存先
home_mailbox = Maildir/

# コンテナネットワークからの送信を無条件許可
mynetworks = 127.0.0.0/8, 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16

# 転送設定やデータベースを無効にしエラー回避
alias_maps =
alias_database =

コンテナ以外から送信したい場合

コンテナからではなく自宅PCから送信したいような場合で尚且つテスト運用の場合だと、mynetworksに自宅PCのIPアドレスを追記すればよい。SMTP認証なしで送信できる筈。

本番運用の場合(SMTP認証ありかつIP指定なしにする場合)は別途設定がいる模様。

entrypoint.sh

#!/bin/sh

# コンテナ終了時にpostfix / dovecotを安全に終了
trap "postfix stop; dovecot stop; exit 0" 15 2

# ログファイル作成
touch /var/log/messages

# 所有者の自動修正(コンテナ起動時にマウントされて権限がリセットされる可能性があるため)
chown -R mail_user:mail_user /home/mail_user

# Postfix起動
postfix start

# Dovecotを起動
dovecot

# コンテナ維持とログ出力
exec tail -f /var/log/messages

docker-compose.yml

services:
    # メールサーバーコンテナ用設定
    mail:
        container_name: mail-container
        image: localhost/mail-server:latest
        restart: always
        ports:
            - "25:25"
            - "143:143"
        volumes:
            - mail-data:/home/mail_user:Z
        networks:
             web-mail-net:
                ipv4_address: 10.89.30.5
        deploy:
            resources:
                limits:
                    memory: 64M

# ボリューム設定
volumes:
    mail-data:
        external: true

# ネットワーク設定
networks:
    # webコンテナとは接続しておく
    web-mail-net:
        driver: bridge
        ipam:
          config:
            - subnet: 10.89.30.0/24

ビルドとコンテナの起動

前述の通り作成したファイルは全て同じディレクトリにアップロードし、ビルド及びコンテナ起動する。

# アップロードしたディレクトリに移動
cd /path/to/mail-server

# ビルド
podman build -t localhost/mail-server .

# 構文チェック
podman compose config

# コンテナの生成
podman compose up -d

mail_test.php

ブラウザからアクセス可能なディレクトリに以下をアップロードしておく。

<?php
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\SMTP;

require_once __DIR__ . '/../../vendor/autoload.php';

mb_language('japanese');
mb_internal_encoding('UTF-8');

$mail = new PHPMailer(true);
$mail->CharSet = 'UTF-8';
$mail->Encoding = 'base64';

try {
    // 通信ログを出力
    $mail->SMTPDebug = SMTP::DEBUG_SERVER; 

    $mail->isSMTP();

    // docker-compose.ymlで指定したIPアドレスを記述
    $mail->Host       = 'xxx.xxx.xxx.xxx';
    $mail->Port       = 25;
    $mail->SMTPAuth   = false;
    $mail->SMTPOptions = [
        'ssl' => [
            'verify_peer' => false,
            'verify_peer_name' => false,
            'allow_self_signed' => true
        ]
    ];

    // 送信(作成したユーザー@ドメイン)
    $mail->setFrom('mail_user@mail.test.com', 'コンテナ管理者');

    // 受信(任意)
    $mail->addAddress('xxxxxxxx@ymail.ne.jp');
    $mail->addAddress('xxxxxxxx@gmail.com');

    $mail->Subject = 'PHPからのテストメール';
    $mail->Body    = 'コンテナ間連携でのメール送信テストです。';

    $mail->send();
    echo "\n送信成功\n";

} catch (Exception $e) {
    echo "\n送信失敗: {$mail->ErrorInfo}\n";
}

ブラウザから上記ファイルにアクセスすると送信できる筈。

Thunderbird側設定

手動設定からIMP設定で以下を選択・入力する。

  • サーバ名 -> サーバのIPアドレス
  • ポート -> 143
  • ユーザ名 -> 作成したユーザ名
  • パスワード -> 作成したパスワード
  • セキュリティ系 -> 通常のパスワードで平文

適当なメールアドレスから「作成したユーザー@mail.test.com」に送信するとThunderbirdで受信できる筈。

 

所感

メモした内容で送受信できる筈、というか当時は送受信確認できた。あとは迷惑メールフィルタリングされないようSPF・DKIM・逆引き等の設定をしたいところ。

 - Podman サーバー

  関連記事

Podmanで導入したPHPの設定ファイル(php.ini)変更と高速化に関する設定方法
Podmanで導入したPHPの設定ファイル(php.ini)変更と高速化に関する設定方法

Podmanで導入したPHPの設定ファイル(php.ini)の内容を変更したい。 ...

PodmanでMailpit用コンテナを作成しPHPからテストメールを送受信する方法
PodmanでMailpit用コンテナを作成しPHPからテストメールを送受信する方法

開発中などでPHPからテストメールを送信したい。以前メモしたmailtrapを使 ...

PodmanでPython用コンテナを作成しデータベース用コンテナに接続する方法
PodmanでPython用コンテナを作成しデータベース用コンテナに接続する方法

PodmanでPython用コンテナを作成しデータベース(MariaDB)用コン ...

Podmanで導入したデータベース(MariaDB)用コンテナのチューニングに関する設定方法
Podmanで導入したデータベース(MariaDB)用コンテナのチューニングに関する設定方法

先日Podmanでデータベース(MariaDB)用コンテナを導入したが、当該コン ...

Podmanで作成したApache用コンテナにLet's Encryptを導入しHTTPS接続できるようにする方法
Podmanで作成したApache用コンテナにLet's Encryptを導入しHTTPS接続できるようにする方法

先日Podmanで作成したApache用コンテナに対してドメインを割り当てたが、 ...