メールサーバの構築

さくらインターネットのVPSにメールサーバを構築した際の備忘録です。

設定の詳細までは記載しませんが一例として参考程度にはなると思います。
 

前提条件

Apache2.X、MySQLおよびphpMyAdminのインストールと設定が完了していること
※どちらもremi版をインストールしてあります。

項目 設定値 備考
ホスト名 wwwNNNNzz.sakura.ne.jp さくらのVPSサーバ名
ローカルメールボックス /var/spool/ユーザ名 サーバに存在するユーザ用のメールボックス
ローカルエイリアス /etc/aliases ローカルの別名ファイル
バーチャルドメイン1 vdomain1.jp 独自ドメイン1
バーチャルドメイン2 vdomain2.jp 独自ドメイン2
バーチャルドメインメールボックス /home/mailuser/%d/%u MailDir方式
%d=ドメイン名、%u=ユーザ名
バーチャルドメインメールグループ vmail(GID:10000) バーチャルドメインのメールディレクトリのグループ(共通)
バーチャルドメインメールユーザ vmail(UID:10000) バーチャルドメインのメールディレクトリのユーザ(共通)
データベース名 postfix  
データベースユーザ名 postfix  

【参考】メールを受け取る仕組みはどうなっていますか?

参考サイトにあるMTA(Mail Transfer Agent)、MDA(Mail Delivery Agent)、MRA(Mail Retrieval Agent )を、当サイトでは、MTA:postfix、MDA:dovecot-lmtp、MRA:dovecotで構成しています。
 

PostfixAdmin

ダウンロード

最新版をhttp://sourceforge.net/projects/postfixadmin/からダウンロードしてきます。
wgetコマンドが便利です。
 

解凍

ダウンロードしたファイルを/usr/share以下に解凍しました。
解凍するとディレクトリ名はphpadmin-x.xx(x.xxはバージョン番号)になりますので、以下コマンドでソフトウェアリンクを作成しバージョン管理できるようにしました。

 # ln -s postfixadmin-x.xx postfixadmin

 

設定

設定方法はINSTALL.TXTに記載されています。
以下簡単に手順を説明します。
 

1.データベースを作成

データベース名:postfixでデータベースを作成します。
作成はphpMyAdminで行いました。
 

2.設定ファイルの編集

config.inc.phpをコピーするか、もしくは、新規作成してconfig.local.phpを編集します。

以下はconfig.local.phpの例です。自身の環境に合わせて修正してください。

<!--?php
/**
 * Contains configuration options that override the default config file
 */

/*****************************************************************
 *  !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
 * You have to set $CONF['configured'] = true; before the
 * application will run!
 * Doing this implies you have changed this file as required.
 * i.e. configuring database etc; specifying setup.php password etc.
 */
$CONF['configured'] = true;

// In order to setup Postfixadmin, you MUST specify a hashed password here.
// To create the hash, visit setup.php in a browser and type a password into the field,
// on submission it will be echoed out to you as a hashed value.
$CONF['postfix_admin_url'] = '/postfixadmin';
$CONF['database_type'] = 'mysql';
$CONF['database_host'] = 'localhost';
$CONF['database_user'] = 'postfix';
$CONF['database_password'] = 'XXXXXXXXXX';
$CONF['database_name'] = 'postfix';
$CONF['admin_email'] = 'postmaster@wwwNNNNzz.sakura.ne.jp';
$CONF['encrypt'] = 'dovecot:CRAM-MD5';
$CONF['dovecotpw'] = '/usr/bin/doveadm pw';
$CONF['min_password_length'] = 6;
$CONF['page_size'] = '20';
$CONF['domain_path'] = 'YES';
$CONF['domain_in_mailbox'] = 'NO';
$CONF['aliases'] = '50';
$CONF['mailboxes'] = '50';
$CONF['maxquota'] = '100';
$CONF['quota'] = 'YES';
$CONF['quota_multiplier'] = '1024000';
$CONF['transport'] = 'NO';
$CONF['transport_options'] = array (
    'virtual',  // for virtual accounts
    'local',    // for system accounts
    'relay'     // for backup mx
);
$CONF['transport_default'] = 'virtual';
$CONF['vacation'] = 'NO';
$CONF['special_alias_control'] = 'YES';
$CONF['user_footer_link'] = 'http://wwwNNNNzz.sakura.ne.jp/postfixadmin/main';
$CONF['show_footer_text'] = 'YES';
$CONF['footer_text'] = 'Return to change-this-to-your.domain.tld';
$CONF['footer_link'] = 'http://wwwNNNNzz.sakura.ne.jp/postfixadmin';
$CONF['create_mailbox_subdirs']=array('Drafts','Spam','Sent','Trash');
$CONF['create_mailbox_subdirs_host']='localhost';
$CONF['create_mailbox_subdirs_prefix']='';
$CONF['used_quotas'] = 'YES';
$CONF['new_quota_table'] = 'YES';


// Alias Control
// Postfix Admin inserts an alias in the alias table for every mailbox it creates.
// The reason for this is that when you want catch-all and normal mailboxes
// to work you need to have the mailbox replicated in the alias table.
// If you want to take control of these aliases as well set this to 'YES'.

// Alias control for superadmins
$CONF['alias_control'] = 'YES';

// Alias Control for domain admins
$CONF['alias_control_admin'] = 'YES';

// Special Alias Control
// Set to 'NO' if your domain admins shouldn't be able to edit the default aliases
// as defined in $CONF['default_aliases']
$CONF['special_alias_control'] = 'NO';

// Alias Goto Field Limit
// Set the max number of entries that you would like to see
// in one 'goto' field in overview, the rest will be hidden and "[and X more...]" will be added.
// '0' means no limits.
$CONF['alias_goto_limit'] = '0';

// Alias Domains
// Alias domains allow to "mirror" aliases and mailboxes to another domain. This makes
// configuration easier if you need the same set of aliases on multiple domains, but
// also requires postfix to do more database queries.
// Note: If you update from 2.2.x or earlier, you will have to update your postfix configuration.
// Set to 'NO' to disable alias domains.
$CONF['alias_domain'] = 'YES';

//
// END OF CONFIG FILE
//

※上記で$CONF['configured'] = falseに設定するとwellcome画面が表示されるだけになります。
※$CONFIG['encrypt']と$CONFIG['dovecotpw']の設定に関しては使用するdovecotのバージョンに合わせて設定が必要です。例ではdovecot-2.x用です。
※また、この設定はdovecot.confのパスワード暗号化方式とも一致する必要があります。
 

次にWEBサーバ経由でsetup.phpを実行できるように設定します。

/etc/httpd/conf.dにpostfixadmin.confでファイルを作成します。
※/etc/httpd/conf/httpd.confがhttpd起動時に読み込まれますが、httpd.conf内にconf.d/*.confを読み込むようにデフォルトで設定されていますので、XXX.confになるように作成します。
※バーチャルホストの設定を複数設定している場合は、include conf.d/postfixadmin.confを記述する場所で、どのサーバのURLでアクセスした場合にpostfixadminを使えるようにするかをコントロールできます。
※この際は、デフォルトのhttpd.confでIncludeしている箇所をコメントにして無効にする必要があります。

以下は、postfixadmin.confの例です。ご自身の環境に合わせて修正してください。

#  Web application to manage Postfix email server
#

<Directory "/usr/share/postfixadmin/">
 AllowOverride AuthConfig
 Order Deny,Allow
 Deny from All
 Allow from 127.0.0.1
 Allow from 自宅のルータに割り当てられたWAN側IPアドレス(グローバルIPアドレス)
</Directory>

Alias /postfixadmin /usr/share/postfixadmin
Alias /PostFixAdmin /usr/share/postfixadmin
Alias /PostfixAdmin /usr/share/postfixadmin

※上記の例ではローカルホストと自宅からのみアクセスを許可しています。
※自宅からのみにアクセスを制限した場合は、ルータの電源ON/OFFなどで割り当てられるIPアドレスが変更になる可能性があります。
 

3.セットアップの実行

WEBブラウザーから「http://wwwNNNNzz.sakura.ne.jp/postfixadmin/setup.php」にアクセスします。
セットアップのチェックが実行され、postfixadminの特別な管理用ユーザのアカウントを作成します。
アカウントが作成されるとメッセージが表示されますのでそれに従って、config.inc.phpを編集してください。

一旦、終了して再度「http://wwwNNNNzz.sakura.ne.jp/postfixadmin」にアクセスすれば、バーチャルドメイン、メールユーザやエイリアスなどの登録が可能です。

postfixadminで登録するものは、postfixのバーチャルドメインマップ、バーチャルエイリアスマップ、dovecotのuserdbやpassdbなどに使われます。
 

Postfix

インストール

インストールは以下のコマンドで実施しました。

 # yum install postfix

依存関係のあるモジュールもすべてインストールしました。
 

sendmailの停止

※sendmailが起動している場合にのみ実施します。

# service sendmail stop
# chkconfig sendmail off
# alternatives --config mta
sendmail.postfixを選択します。 

 

設定

/etc/postfixにあるmain.cfを環境に合わせて編集します。

以下は、main.cfの例です。自身の環境に合わせて修正してください。

# --------------- local settings ------------------
inet_interfaces                 = all
inet_protocols                  = ipv4
mynetworks_style                = host
alias_maps                      = hash:/etc/aliases
relay_domains                   =

とりあえずは、上記の設定でローカルユーザのメールの送受信は可能になるはずです。
記述のないオプションはデフォルトが使用されます。

デフォルトの値を確認するには以下のコマンドで行います。

# postconf -d
または
# postconf -d inet_interfaces 

inet_interfacesの箇所を別のパラメータに変更すれば個別で値を確認できます。
半角スペースで区切れば複数のパラメータを一度に確認できます。
 

Postfix SMTPサーバに対するDovecot SASLの設定

今回はdovecotを使ってSMTPサーバ(smtpd)でのSASL認証サーバを構築します。

以下のコマンドでSMTPサーバ(smtpd)でのSASLサポートを確認します。

# postconf -a

 

dovecotが表示されればSMTPサーバでのSASLサポートをdovecotで構築できます。

ちなみに以下のコマンドでSMTP+LMTPクライアント(smtp+lmtp)でのSASLサポートを確認できます。

# postconf -A


以下がDovecot SASL認証に関するPostfix SMTPサーバ(smtpd)の設定例になりますので、main.cfに追記します。

# ---------------------- SASL PART (Server) -----------------
smtpd_sasl_auth_enable         = yes
smtpd_sasl_local_domain        = $myhostname
smtpd_sasl_exceptions_networks = $mynetworks
smtpd_sasl_security_options    = noplaintext,noanonymous
broken_sasl_auth_clients       = yes
smtpd_sasl_type                = dovecot
# Can be an absolute path, or relative to $queue_directory
smtpd_sasl_path                = private/auth

※smtpd_sasl_security_optionsには最低限noanonymousは設定してください。
※smtpとsmptdは異なりますので注意してください。ここではsmptdになります。
※dovecot側にもSASL認証の設定が必要です。
 

Cyrus-SASLの停止

今回はDovecotを利用しますのでCyrus-SASLを停止します。

以下のコマンドで停止および自動起動しないように設定します。

# chkconfig saslauthd off
# service saslauthd stop

 

バーチャルドメインに関する設定

以下はバーチャルドメイン用のmain.cfの例です。

# --------------- VIRTUAL DOMAINS ----------------------
virtual_mailbox_domains             = mysql:/etc/postfix/mysql_virtual_domains_maps.cf
virtual_mailbox_base                = /home/mailuser
virtual_mailbox_maps                = mysql:/etc/postfix/mysql_virtual_mailbox_maps.cf
virtual_mailbox_limit_maps          = mysql:/etc/postfix/mysql_virtual_mailbox_limit_maps.cf
virtual_alias_maps                  = mysql:/etc/postfix/mysql_virtual_alias_maps.cf
virtual_minimum_uid                 = 10000
virtual_uid_maps                    = static:10000
virtual_gid_maps                    = static:10000
virtual_transport                   = lmtp:unix:private/dovecot-lmtp
dovecot_destination_recipient_limit = 1

各マップはデータベースにクエリを発行し、その結果を使用しています。
データベースへの登録は、先に導入したpostfixadminで行います。
それぞれのファイルは、/usr/share/postfixadmin/DOCUMENTS/POSTFIX_CONF.txtを参考にして記述してください。
最初はローカルファイルのマップを使って動作確認をしたのちデータベースを利用するように変更するとうまくいかないときの切り分けが簡単になるかもしれません。

postfixで利用可能なマップ形式は以下のコマンドで確認できます。

# postconf -m


なお、以下のコマンドでテストが可能です。

# postmap -q vdomain1.jp mysql:/etc/postfix/mysql_virtual_domains_maps.cf
vdomain1.jp

-qの後に実際のバーチャルドメイン名(検索キー)を入力して、同じ名前のみが表示されれば成功です。

TLSに関する設定

# ---------------------- TLS PART --------------------------------
smtpd_tls_auth_only                 = yes
smtpd_tls_CAfile                    = /etc/pki/server1/cacert.crt
smtpd_tls_cert_file                 = /etc/pki/server1/mail-server.crt
smtpd_tls_key_file                  = /etc/pki/server1/mail-server.key
smtpd_tls_session_cache_database    = btree:/var/lib/postfix/smtpd_scache
smtpd_tls_security_level            = may
smtpd_tls_received_header           = yes
smtpd_tls_loglevel                  = 1
tls_random_source                   = dev:/dev/urandom

セキュリティに関する設定

# ---------------------- Security PART ----------------------
smtp_tls_protocols                  = !SSLv2, !SSLv3
smtp_tls_mandatory_protocols        = !SSLv2, !SSLv3
smtpd_tls_protocols                 = !SSLv2, !SSLv3
smtpd_tls_mandatory_protocols       = !SSLv2, !SSLv3
smtpd_banner                        = $myhostname ESMTP Unknown
smtpd_helo_required                 = yes
disable_vrfy_command                = yes
unknown_local_recipient_reject_code = 550
maps_rbl_reject_code                = 550
default_rbl_reply                   = $rbl_code <$recipient>: Recipient address rejected: User unknown in local recipient table
header_checks                       = pcre:/etc/postfix/header_checks
#warning: the restrictions reject_unknown_(sender|recipient)_domain
#will trigger if your DNS becomes unavailable
smtpd_client_restrictions           = permit_mynetworks,
                                      check_client_access hash:/etc/postfix/access,
                                      check_client_access cidr:/etc/postfix/client.cidr,
                                      reject_rbl_client all.rbl.jp,
                                      reject_rbl_client bl.spamcop.net,
                                      reject_rbl_client multi.surbl.org,
                                      reject_rbl_client sbl-xbl.spamhaus.org,
                                      permit
smtpd_helo_restrictions             = permit_mynetworks,
                                      check_helo_access hash:/etc/postfix/access,
                                      check_client_access cidr:/etc/postfix/client.cidr,
                                      reject_invalid_hostname,
                                      permit
smtpd_sender_restrictions           = permit_mynetworks,
                                      hash:/etc/postfix/reject_sender,
                                      reject_unknown_sender_domain,
                                      reject_non_fqdn_sender
smtpd_recipient_restrictions        = permit_mynetworks,
                                      permit_sasl_authenticated,
                                      reject_unauth_destination
smtpd_data_restrictions             = reject_unauth_pipelining,
                                      reject_multi_recipient_bounce,
                                      permit

上記は、POODLE SSLv3.0 脆弱性問題対応を含んでいます。

master.cfの編集

以下の様に変更しました。

smtp      inet  n       -       n       -       -       smtpd
  -o receive_override_options=no_address_mappings
submission inet n       -       n       -       -       smtpd
  -o smtpd_tls_security_level=encrypt
  -o smtpd_sasl_auth_enable=yes
  -o milter_macro_daemon_name=ORIGINATING
  -o smtpd_sasl_type=dovecot
  -o smtpd_sasl_path=private/auth
  -o smtpd_sasl_security_options=noanonymous,noplaintext
  -o smtpd_sasl_local_domain=$myhostname
  -o smtpd_client_restrictions=permit_sasl_authenticated,reject
  -o smtpd_recipient_restrictions=permit_sasl_authenticated,reject_unauth_destination
smtps     inet  n       -       n       -       -       smtpd
  -o smtpd_tls_wrappermode=yes
  -o smtpd_sasl_auth_enable=yes
  -o smtpd_client_restrictions=permit_sasl_authenticated,permit_mynetworks,reject

Dovecot

インストール

POODLE SSLv3.0 脆弱性問題に対応するには、dovecot-2.1以降でなければダメなようです。
dovecot-2.0.9でもssl_cipher_listを使えば一見対応できそうですが、実際の接続時にTLSv1.0およびTLS1.2が使用できないため接続できませんでした。
これを回避するには、パッチがあたったものを利用するかdovecot-2.1以降を使うことになります。
そのため、ここではdovecot-2.2.x(atrpms-testing)をインストールしました。
 

atrpmsレポの設定

以下のコマンドを実行してサインキーをインポートします。

# rpm --inport http://packages.atrpms.net/RPM-GPG-KEY.atrpms

次にatrpmsのrepoパッケージをダウンロードし、インストールを実行します。

# cd /usr/local/src/rpm
# wget http://packages.atrpms.net/dist/el6/atrpms-repo/atrpms-repo-6-7.el6.i686.rpm
# rpm -ivH atrpms-repo-6-7.el6.i686.rpm

/etc/yum.repos.d/にatrpms関連のrepoが追加されています。

dovecot-2.2.10のインストール

dovecot-2.1以降をインストールするにはperl(JSON::XS)が要件になりますので事前にインストールが必要です。
以下のコマンドでdovecot-2.2.Xをatrpms-testingからインストールします。

# yum --disablerepo=\* --enablerepo=atrpms-testing install dovecot

設定

dovecotの設定ファイルは、/etc/dovecot/dovecot.confとconf.d以下にある*.confなどを読み込むようですが、面倒なのでdovecot.confだけを使用する様に変更しています。

protocols = imap pop3 lmtp
disable_plaintext_auth = yes
ssl=yes
ssl_ca = </etc/pki/server1/cacert.crt
ssl_cert = </etc/pki/server1/mail-server.crt
ssl_key = </etc/pki/server1/mail-server.key
mail_location = maildir:/home/maiuser/%d/%n
first_valid_uid = 10000
last_valid_uid = 10000
maildir_copy_with_hardlinks = yes
mail_plugins = quota

# Should saving a mail to a nonexistent mailbox automatically create it?
lda_mailbox_autocreate = yes

# Should automatically created mailboxes be also automatically subscribed?
lda_mailbox_autosubscribe = yes

# Having "login" also as a mechanism make sure outlook can use the auth smtpd as well
# http://wiki.dovecot.org/Authentication/Mechanisms
auth_mechanisms = cram-md5 plain login
passdb {
  driver = sql
  args = /etc/dovecot/sql.conf
}
userdb {
  driver = sql
  args = /etc/dovecot/sql.conf
}
# ++++++++++++++++++++++++ conf.d/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 lmtp {
  unix_listener /var/spool/postfix/private/dovecot-lmtp {
   group = postfix
   mode = 0600
   user = postfix
  }

  # Create inet listener only if you can't use the above UNIX socket
  #inet_listener lmtp {
    # Avoid making LMTP visible for the entire internet
    #address =
    #port =
  #}
  process_min_avail = 5
  executable = lmtp -L
}
service imap {
  # Most of the memory goes to mmap()ing files. You may need to increase this
  # limit if you have huge mailboxes.
  vsz_limit = 256M

  # Max. number of IMAP processes (connections)
  process_limit = 1024
}
service pop3 {
  # Max. number of POP3 processes (connections)
  process_limit = 1024
}
#auth_verbose = yes
#auth_debug = yes
#auth_debug_passwords = yes
service auth {
  unix_listener auth-userdb {
    group = vmail
    mode = 0600
    user = vmail
  }
  # Postfix smtp-auth
  unix_listener /var/spool/postfix/private/auth {
    mode = 0660
    # Assuming the default Postfix user and group
    user = postfix
    group = postfix
  }
}
service dict {
  # If dict proxy is used, mail processes should have access to its socket.
  # For example: mode=0660, group=vmail and global mail_access_groups=vmail
  unix_listener dict {
    mode = 0600
    user = vmail
    group = vmail
  }
}

#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

protocol imap {
  mail_plugins = $mail_plugins imap_quota
  imap_client_workarounds = delay-newmail
}
protocol pop3 {
  mail_plugins = $mail_plugins quota
  pop3_uidl_format = %08Xu%08Xv
  pop3_client_workarounds = outlook-no-nuls oe-ns-eoh
}
protocol lmtp {
  postmaster_address = postmaster@wwwNNNNzz.sakura.ne.jp
  mail_plugins = quota sieve
  info_log_path = /var/log/dovecot-lmtp.log
}
dict {
  quotadict = mysql:/etc/dovecot/dict-quota.conf
}
plugin {
  quota2 = dict:User quota::proxy::quotadict
  quota = dict:Domain quota:%d:proxy::quotadict
  acl = vfile:/etc/dovecot/acls
  trash = /etc/dovecot/trash.conf
  sieve_global_path = /home/sieve/globalfilter.sieve
  sieve = ~/dovecot.sieve
  sieve_dir = ~/sieve
  sieve_global_dir = /home/sieve/
  #sieve_extensions = +notify +imapflags
  sieve_max_script_size = 1M
  #sieve_max_actions = 32
  #sieve_max_redirects = 4
}
namespace {
# Namespace type: private, shared or public
type = private
# Hierarchy separator to use. You should use the same separator for all
# namespaces or some clients get confused. '/' is usually a good one.
# The default however depends on the underlying mail storage format.
separator = .
# Prefix required to access this namespace. This needs to be different for
# all namespaces. For example "Public/".
prefix = INBOX.
# Physical location of the mailbox. This is in same format as
# mail_location, which is also the default for it.
#location =
# There can be only one INBOX, and this setting defines which namespace
# has it.
inbox = yes
# If namespace is hidden, it's not advertised to clients via NAMESPACE
# extension or shown in LIST replies. This is mostly useful when converting
# from another server with different namespaces which you want to depricate
# but still keep working. For example you can create hidden namespaces with
# prefixes "~/mail/", "~%u/mail/" and "mail/".
hidden = no
}
ssl_protocols = !SSLv2 !SSLv3

※2.0との変更点としては、protocolsにsieveを記述するとエラーになるので削除しました。
※ssl_protocols = !SSLv2 !SSLv3がPOODLE SSLv3.0 脆弱性問題対応箇所です。
※/etc/dovecot/sql.confと/etc/dovecot/dict-quota.confは/usr/share/postfixadmin/DOCUMENTS/DOVECOT.txtを参考にして記述してください。

imap/pop3を使用しない(imaps/pop3sのみ使用する)ようにするにはport=0を記載します。

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

以下の箇所のコメントを外せば、dovecotの詳細確認が可能です。

#auth_verbose = yes
#auth_debug = yes
#auth_debug_passwords = yes

Postfixの起動

# service postfix start

Dovecotの起動

# service dovecot start

動作確認は/var/log/mailogを確認してください。

Firewallの設定例

-A RH-Firewall-1-INPUT -p tcp -m state -m tcp --dport 25 --state NEW -j ACCEPT
-A RH-Firewall-1-INPUT -p tcp -m state -m tcp --dport 465 --state NEW -j ACCEPT
-A RH-Firewall-1-INPUT -p tcp -m state -m tcp --dport 587 --state NEW -j ACCEPT
-A RH-Firewall-1-INPUT -p tcp -m state -m tcp --dport 995 --state NEW -j ACCEPT

上から順に、smtp,SMTP over SSL/TLS,サブミッションポート,POP3 over SSL/TLSになります。
POP3(110番)は使用しませんので、ファイアーウォールで閉じています。
POP3を開けていた場合、「メールサーバが攻撃を受けている」に記載したように総当り攻撃を受けるので注意が必要です。

ディストリビューション

CentOS 6.x