MySQLでメールアドレスが管理できるようメールサーバを構築
PostfixAdminを使わずにMySQLでメールアドレスが管理できるようメールサーバ(Postfix/Dovecot)を構築した時のメモ
CentOS7にPostfixをインストール
(※本サイトの「CentOS7に最新のPostfix3.4をインストール」を参照ください)
CentOS7にdovecotをインストール
(※本サイトの「CentOS7に最新のdovecot2.3.7.2をインストール」を参照ください)
CentOS7にMySQLをインストール
(※本サイトの「CentOS7にMySQL公式リポジトリを使って最新のMySQL8.0をインストール」を参照ください)
専用ユーザとディレクトリを作成
# groupadd -g 10000 vmail # useradd -g vmail -u 10000 vmail -s /sbin/nologin -M # mkdir /var/spool/vmail # chown vmail:vmail /var/spool/vmail # chmod 700 /var/spool/vmail
Postfixの設定
/etc/postfix/main.cf
変更前にバックアップ
# cp -p /etc/postfix/main.cf /etc/postfix/main.cf_`date "+%Y%m%d%H%M%S"`
# メールサーバのホスト名 #myhostname = host.domain.tld #myhostname = virtual.domain.tld ↓ myhostname = mail.example.com # メールのドメイン名 #mydomain = domain.tld ↓ mydomain = example.com # ローカルで配送依頼されたメールの送信元アドレスに付加するドメイン名 #myorigin = $myhostname #myorigin = $mydomain ↓ myorigin = $mydomain # メールを受け取るサーバ範囲 #inet_interfaces = all #inet_interfaces = $myhostname #inet_interfaces = $myhostname, localhost inet_interfaces = localhost ↓ inet_interfaces = all # プロトコル #inet_protocols = ipv4 ↓ inet_protocols = ipv4 # メール配送トランスポート使って配送されるドメインリスト mydestination = $myhostname, localhost.$mydomain, localhost #mydestination = $myhostname, localhost.$mydomain, localhost, $mydomain #mydestination = $myhostname, localhost.$mydomain, localhost, $mydomain, #mail.$mydomain, www.$mydomain, ftp.$mydomain ↓ mydestination = localhost # メールの保存形式と保存先 #home_mailbox = Mailbox #home_mailbox = Maildir/ ↓ home_mailbox = Maildir/ # ヘッダーチェックの有効化 #header_checks = regexp:/etc/postfix/header_checks ↓ header_checks = regexp:/etc/postfix/header_checks # postfixのバージョン情報の非表示 #smtpd_banner = $myhostname ESMTP $mail_name #smtpd_banner = $myhostname ESMTP $mail_name ($mail_version) ↓ smtpd_banner = $myhostname ESMTP unknown
※最終行に追記 # SASL認証 smtpd_sasl_auth_enable = yes smtpd_sasl_type = dovecot smtpd_sasl_path = private/auth smtpd_sasl_security_options = noanonymous smtpd_sasl_local_domain = $myhostname # 古いバージョンのAUTHコマンドの互換(Outlook Express を使用する場合のみ有効にする) #broken_sasl_auth_clients = yes # VRFYコマンドの無効 disable_vrfy_command = yes # HELOコマンドの要求 smtpd_helo_required = yes # HELOコマンドで通知されたFQDNに応じての接続制限 smtpd_helo_restrictions = permit_mynetworks, reject_invalid_hostname, reject_unknown_client, permit # クライアントコマンドの接続制限 smtpd_client_restrictions = permit_mynetworks, reject_unknown_client, permit # MAIL FROMコマンドの接続制限 smtpd_sender_restrictions = reject_unknown_sender_domain # RCPT TOコマンドの接続制限 smtpd_recipient_restrictions = permit_mynetworks, permit_sasl_authenticated, reject_unauth_destination # ETRNコマンドの接続制限 smtpd_etrn_restrictions = permit_mynetworks, reject_invalid_hostname # メールメッセージの上限(20M) message_size_limit = 20971520 # メールボックスサイズの上限(2G) mailbox_size_limit = 2147483648 ### バーチャルドメイン ### local_transport = local virtual_transport = virtual virtual_uid_maps = static:10000 virtual_gid_maps = static:10000 virtual_minimum_uid = 10000 virtual_mailbox_base = /var/spool/vmail virtual_alias_maps = mysql:/etc/postfix/mysql/virtual_alias.conf.ext virtual_alias_domains = $virtual_alias_maps virtual_mailbox_maps = mysql:/etc/postfix/mysql/virtual_mailbox.conf.ext virtual_mailbox_domains = mysql:/etc/postfix/mysql/virtual_domains.conf.ext virtual_mailbox_limit = 2147483648
/etc/postfix/header_checks
変更前にバックアップ
# cp -p /etc/postfix/header_checks /etc/postfix/header_checks_`date "+%Y%m%d%H%M%S"`
### メーラーで拒否 ### /^X-Mailer:.*DM Mailer/ REJECT /^X-Mailer:.*Direct Email/ REJECT ### タイトルで拒否 ### /^Subject:.*</#.*@.*>/ REJECT ### メールアドレスで拒否 ### /^From:.*</#.*@.*>/ REJECT /^Return-Path:.*</#.*@.*>/ REJECT ### 添付の拡張子で拒否 ### /^content-(type|disposition):.*name[ [:space:] ]*=.*\.(ade|adp|apk|appx|appxbundle|bat|cab|chm|cmd|com|cpl|dll|dmg|exe|hta|inf|ins|isp|iso|jar|js|jse|lib|lnk|mde|msc|msi|msix|msixbundle|msp|mst|nsh|pif|reg|scr|sct|shb|shs|sys|swf|vb|vbe|vbs|vxd|wsc|wsf|wsh)/ REJECT ### グリニッジ標準時で拒否(日本は+0900) ### if /^Date/ !/Date:.*+0900/ REJECT endif
submission ポートを使って送信するための設定
/etc/postfix/master.cf
変更前にバックアップ
# cp -p /etc/postfix/master.cf /etc/postfix/master.cf_`date "+%Y%m%d%H%M%S"`
#submission inet n - n - - 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 ↓ submission inet n - n - - smtpd -o smtpd_sasl_auth_enable=yes -o smtpd_client_restrictions=permit_sasl_authenticated,reject
Dovecotの設定
/etc/dovecot/dovecot.conf
変更前にバックアップ
# cp -p /etc/dovecot/dovecot.conf /etc/dovecot/dovecot.conf_`date "+%Y%m%d%H%M%S"`
#POP3とIMAP4を有効 #protocols = imap pop3 lmtp submission ↓ protocols = imap pop3 #IPV4のみ #listen = *, :: ↓ listen = * #dovecotであることを隠す #login_greeting = Dovecot ready. ↓ login_greeting = ready.
/etc/dovecot/conf.d/10-auth.conf
変更前にバックアップ
# cp -p /etc/dovecot/conf.d/10-auth.conf /etc/dovecot/conf.d/10-auth.conf_`date "+%Y%m%d%H%M%S"`
#SSLなしの認証を許可 #disable_plaintext_auth = yes ↓ disable_plaintext_auth = no #認証時のメカニズム auth_mechanisms = plain ↓ auth_mechanisms = plain login #コメントアウト !include auth-system.conf.ext ↓ #!include auth-system.conf.ext
/etc/dovecot/conf.d/10-ssl.conf
変更前にバックアップ
# cp -p /etc/dovecot/conf.d/10-ssl.conf /etc/dovecot/conf.d/10-ssl.conf_`date "+%Y%m%d%H%M%S"`
ssl = required ↓ #ssl = required ssl_cert = </etc/pki/dovecot/certs/dovecot.pem ssl_key = </etc/pki/dovecot/private/dovecot.pem ↓ #ssl_cert = </etc/pki/dovecot/certs/dovecot.pem #ssl_key = </etc/pki/dovecot/private/dovecot.pem
※「10-ssl.conf」ではコメントアウトして、「local.conf」で設定をまとめてます。
複数のファイルを修正する必要があり、管理するのが面倒なのでファイルを作成してまとめて記述します。
/etc/dovecot/local.conf を作成
### 10-mail.conf ### mail_location = maildir:/var/spool/vmail/%d/%n first_valid_uid = 10000 first_valid_gid = 10000 mail_plugins = quota ### 10-master.conf ### service imap-login { inet_listener imap { port = 143 } inet_listener imaps { #port = 993 #ssl = yes } } service pop3-login { inet_listener pop3 { port = 110 } inet_listener pop3s { #port = 995 #ssl = yes } } service auth { # Postfix smtp-auth unix_listener /var/spool/postfix/private/auth { mode = 0600 user = postfix group = postfix } } ### 10-ssl.conf ### ssl = yes ssl_cert = </etc/pki/dovecot/certs/dovecot.pem ssl_key = </etc/pki/dovecot/private/dovecot.pem ### 20-imap.conf ### protocol imap { imap_client_workarounds = delay-newmail tb-extra-mailbox-sep mail_plugins = $mail_plugins imap_quota } ### 20-pop3.conf ### protocol pop3 { pop3_client_workarounds = outlook-no-nuls oe-ns-eoh mail_plugins = $mail_plugins } ### 90-quota.conf ### plugin { quota = maildir:User quota } ### auth-sql.conf.ext ### passdb { driver = sql args = /etc/dovecot/dovecot-sql.conf } userdb { driver = sql args = /etc/dovecot/dovecot-sql.conf.ext }
MySQLでメールアドレスを管理
MySQL用の追加モジュールをインストール
# yum --enablerepo=gf-plus install postfix3-mysql # yum --enablerepo=gf-plus install dovecot23-mysql
データベース・ユーザの作成と権限を設定
MySQLにrootでログイン
# mysql -u root -p Enter password: [パスワード入力][Enter]
データベースの作成
CREATE DATABASE IF NOT EXISTS [データベース名] CHARACTER SET [文字コード] COLLATE [照合順序]; mysql> CREATE DATABASE IF NOT EXISTS mail_db CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;
ユーザの作成
常にrootユーザ使うのは、権限が強すぎてセキュリティ上よくないので、専用ユーザを作成します。
CREATE USER IF NOT EXISTS [ユーザ名]@[ホスト名] IDENTIFIED BY [パスワード]; mysql> CREATE USER IF NOT EXISTS 'mail_user'@'localhost' IDENTIFIED BY 'mailPassword-888';
ユーザに権限を付与
GRANT [権限] ON [データベース名].[対象のテーブル名] TO [ユーザ名]@[ホスト名]; mysql> GRANT SELECT, INSERT, UPDATE, DELETE, LOCK TABLES ON mail_db.* TO 'mail_user'@'localhost';
ドメインテーブルの作成
mysql> USE mail_db; mysql> CREATE TABLE `domain` ( `domain_id` TINYINT UNSIGNED NOT NULL AUTO_INCREMENT, `domain_name` VARCHAR(50) NOT NULL, PRIMARY KEY (`domain_id`), UNIQUE KEY `domain_index1`(`domain_name`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
ドメインデータの登録
mysql> INSERT INTO domain (`domain_name`) VALUES ('example.com'); mysql> SELECT * FROM domain; +-----------+-------------+ | domain_id | domain_name | +-----------+-------------+ | 1 | example.com | +-----------+-------------+
メールユーザテーブルの作成
mysql> CREATE TABLE `mail` ( `mail_id` SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT, `user_name` VARCHAR(50) NOT NULL, `domain_id` TINYINT UNSIGNED NOT NULL, `password` VARCHAR(150) NOT NULL, `quota_storage` SMALLINT UNSIGNED NOT NULL DEFAULT '0', `quota_messages` SMALLINT UNSIGNED NOT NULL DEFAULT '0', `forward` TEXT NOT NULL, PRIMARY KEY (`mail_id`), UNIQUE KEY `mail_index1`(`user_name`, `domain_id`), CONSTRAINT `mail_index2` FOREIGN KEY (`domain_id`) REFERENCES domain(`domain_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
メールユーザの登録
mysql> INSERT INTO mail (`user_name`, `domain_id`, `password`, `quota_storage`, `quota_messages`, `forward`) VALUES ('test', '1', '{SHA512...省略', 0, 0, 'test@example.com,test@yahoo.co.jp'); mysql> INSERT INTO mail (`user_name`, `domain_id`, `password`, `quota_storage`, `quota_messages`, `forward`) VALUES ('sample', '1', '{SHA512...省略', 2048, 10000, ''); mysql> INSERT INTO mail (`user_name`, `domain_id`, `password`, `quota_storage`, `quota_messages`, `forward`) VALUES ('info', '1', '{SHA512...省略', 2048, 10000, 'test@example.com,sample@example.com'); mysql> SELECT * FROM mail; +---------+-----------+-----------+----------------+---------------+----------------+-----------------------------------------------------+ | mail_id | user_name | domain_id | password | quota_storage | quota_messages | forward | +---------+-----------+-----------+----------------+---------------+----------------+-----------------------------------------------------+ | 1 | test | 1 | {SHA512...省略 | 0 | 0 | test@example.com,test@yahoo.co.jp | | 2 | sample | 1 | {SHA512...省略 | 2048 | 10000 | | | 3 | info | 1 | {SHA512...省略 | 2048 | 10000 | test@example.com,sample@example.com | +---------+-----------+-----------+----------------+---------------+----------------+-----------------------------------------------------+
※パスワードを「SHA512-CRYPT」で登録する場合、予めdoveadmコマンドでパスワードのハッシュ値を取得しておきます。
# doveadm pw -s SHA512-CRYPT -p "[パスワード]" {SHA512...省略
※quota_storage
単位=MB (0 ~ 65535)
2048:2GB
0:無制限
※quota_messages
単位=件数 (0 ~ 65535)
10000:10000件
0:無制限
※message_size_limit、mailbox_size_limit、virtual_mailbox_limit要検討
※forward(転送する場合に設定)
複数の場合はカンマ「,」区切
※転送元にもメールを残す場合は自分のメールアドレスも設定します。MySQL連携用SQL
ディレクトリ作成
# mkdir -p /etc/postfix/mysql/
/etc/postfix/mysql/virtual_domains.conf.ext
user = mail_user password = mailPassword-888 hosts = localhost dbname = mail_db query = SELECT dm.domain_name FROM domain AS dm WHERE dm.domain_name = '%s'
/etc/postfix/mysql/virtual_mailbox.conf.ext
user = mail_user password = mailPassword-888 hosts = localhost dbname = mail_db query = SELECT dm.domain_name || '/' || ml.user_name || '/' || FROM mail AS ml INNER JOIN domain AS dm ON (ml.domain_id = dm.domain_id) WHERE ml.user_name || '@' || dm.domain_name = '%s';
/etc/postfix/mysql/virtual_alias.conf.ext
user = mail_user password = mailPassword-888 hosts = localhost dbname = mail_db query = SELECT forward FROM mail AS ml INNER JOIN domain AS dm ON (ml.domain_id = dm.domain_id) WHERE ml.user_name || '@' || dm.domain_name = '%s' AND ml.forward != '';
/etc/dovecot/dovecot-sql.conf.ext
driver = mysql #default_pass_scheme = PLAIN default_pass_scheme = SHA512-CRYPT connect = host=localhost dbname=mail_db user=mail_user password=mailPassword-888 password_query = SELECT password FROM mail AS ml INNER JOIN domain AS dm ON (ml.domain_id = dm.domain_id) WHERE ml.user_name || '@' || dm.domain_name = '%u'; user_query = SELECT '/var/spool/vmail/%d/%n' AS home, 10000 AS uid, 10000 AS gid, '*:storage=' || CAST(ml.quota_storage AS CHAR || , 'M') AS quota_rule, '*:messages=' || CAST(ml.quota_messages AS CHAR || ) AS quota_rule2 FROM mail AS ml INNER JOIN domain AS dm ON (ml.domain_id = dm.domain_id) WHERE ml.user_name || '@' || dm.domain_name = '%u'; iterate_query = SELECT ml.user_name || '@' || dm.domain_name AS user FROM mail AS ml INNER JOIN domain AS dm ON (ml.domain_id = dm.domain_id);
PostfixとDovecotを再起動
# systemctl restart postfix.service # systemctl restart dovecot.service
iptablesの設定
(※本サイトの「CentOS7を安全に運用する為の初期設定(iptablesの設定)」を参照ください)
smtp(25)、submission(587)、pop3(110)、imap(143)ポートを許可
/etc/sysconfig/iptables
変更前にバックアップ
# cp -p /etc/sysconfig/iptables /etc/sysconfig/iptables_`date "+%Y%m%d%H%M%S"`
# smtp -A INPUT -p tcp -m state --state NEW -m tcp --dport 25 -j ACCEPT # submission -A INPUT -p tcp -m state --state NEW -m tcp --dport 587 -j ACCEPT # pop3 -A INPUT -p tcp -m state --state NEW -m tcp --dport 110 -j ACCEPT # imap -A INPUT -p tcp -m state --state NEW -m tcp --dport 143 -j ACCEPT
修正後のiptables
*filter :INPUT DROP [0:0] :FORWARD DROP [0:0] :OUTPUT ACCEPT [0:0] # 確立済みの通信は許可 -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT # 自ホストからの通信は全て許可 -A INPUT -i lo -j ACCEPT # pingは許可(1秒間に1回の制限) -A INPUT -p icmp -m limit --limit 1/s --limit-burst 1 -j ACCEPT # プライベートアドレスを破棄 -A INPUT -s 10.0.0.0/8 -j DROP -A INPUT -s 172.16.0.0/12 -j DROP -A INPUT -s 192.168.0.0/16 -j DROP # ローカルループバックアドレスを破棄 -A INPUT -s 127.0.0.0/8 -j DROP # リンクローカルアドレスを破棄 -A INPUT -s 169.254.0.0/16 -j DROP # テストネットワークアドレスを破棄 -A INPUT -s 192.0.2.0/24 -j DROP -A INPUT -s 198.51.100.0/24 -j DROP -A INPUT -s 203.0.113.0/24 -j DROP # クラスDを破棄 -A INPUT -s 224.0.0.0/4 -j DROP # クラスEを破棄 -A INPUT -s 240.0.0.0/4 -j DROP # Current networkを破棄 -A INPUT -d 0.0.0.0/8 -j DROP # ブロードキャストアドレスを破棄 -A INPUT -d 255.255.255.255 -j DROP # データを持たないパケットを破棄 -A INPUT -p tcp --tcp-flags ALL NONE -j DROP # SYNフラッド攻撃と思われる接続を破棄 -A INPUT -p tcp -m state --state NEW ! --syn -j DROP # ステルススキャン攻撃と思われる接続を破棄 -A INPUT -p tcp --tcp-flags ALL ALL -j DROP # フラグメントパケット攻撃と思われる接続を破棄 -A INPUT -f -j DROP # ssh :SSH - [0:0] :SSH_ATTACK - [0:0] # -A INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT # 同じホストから60秒以内に5回のSSH接続があったら、そのホストからのSSH接続を10分間受け付けない -A INPUT -p tcp -m state --state NEW -m tcp --dport 10022 -j SSH -A SSH -m recent --name sshbadcon --rcheck --seconds 600 -j REJECT -A SSH -m recent --name sshcon --rcheck --seconds 60 --hitcount 5 -j SSH_ATTACK -A SSH -m recent --name sshcon --set -A SSH -j ACCEPT -A SSH_ATTACK -m recent --name sshbadcon --set -A SSH_ATTACK -j LOG --log-prefix "iptables:SSH_ATTACK: " -A SSH_ATTACK -j REJECT # http -A INPUT -p tcp -m state --state NEW -m tcp --dport 80 -j ACCEPT -A INPUT -p tcp -m state --state NEW -m tcp --dport 443 -j ACCEPT # smtp -A INPUT -p tcp -m state --state NEW -m tcp --dport 25 -j ACCEPT # submission -A INPUT -p tcp -m state --state NEW -m tcp --dport 587 -j ACCEPT # pop3 -A INPUT -p tcp -m state --state NEW -m tcp --dport 110 -j ACCEPT # imap -A INPUT -p tcp -m state --state NEW -m tcp --dport 143 -j ACCEPT -A INPUT -j LOG --log-prefix "iptables:" --log-level=warning -A INPUT -j REJECT --reject-with icmp-host-prohibited -A FORWARD -j REJECT --reject-with icmp-host-prohibited COMMIT
iptablesの再起動
# systemctl restart iptables.service