PostfixとDovecotを使ったメールサーバはポピュラーなので、サイトを検索するといくつか設定方法がヒットしますが、ある程度セキュリティを取り入れた設定となるとあまり実例が見つかりません。そのなかで、分かりやすかったサイトがあったのでそれを参考に構築してみました。
SSL/TLSでIMAP、STARTTLSでSMTP認証を行います。メールアカウントとパスワードはLinuxのシステムを使わずPostfix側で行います。メーラー(MUA)はLMTPプロトコルでDovecotからPostfixに送りインターネットに送信するようにします。
パッケージのインストール
postfix(必須) dovecot(必須) postgrey(オプション) opendkim(オプション) fail2ban(オプション) RoundCube – webmail(オプション)
apt install postfix dovecot-core dovecot-imapd dovecot-lmtpd postfix-policyd-spf-python sasl2-bin
SSL Certificate
SSL Certificateはフリーの StartSSL を使いました。まずStartSSLサイトでユーザー登録してサーバー鍵で作ったCSRを使いサイトで登録したホスト名に対してCSRをペーストします。するとzipファイルを作ってくれるのでそれをダウンロードします。zipファイルにはいくつかサーバごとにzipが纏められていますが、 OtherServer.zip を展開して、サーバ証明と中間証明を結合します。StartSSLのルート証明書も一緒についてきますが、Ubuntu(16.04 LTS Xenial)等のディストリビューションにはすでにあるのでそれを使います。
Let’s Encryptを使う場合はウェブサーバーが必要になります。 (オススメ)
ファイヤーウォールで次のポートを開けます。
port 25 (SMTP), 587(submission), 143(imap) and 993 (imaps)
optional: 80(http), 443(https)
メールアカウント
パスワードは平文パスワードを暗号化したHUSHを使います。次のようにして作成します。
sudo doveadm pw -s SHA512-CRYPT -p <平文パスワード>
暗号化したHUSH情報は /etc/dovecot/users に保存します。
パスワードのチェックは次のようにします。
sudo doveadm pw -t ’HUSH’
例)doveadm pw -t ’{SHA512-CRYPT}$6$VaEOV5m...'
postmaster_address がないというエラーがある場合、/etc/dovecot/conf.d/15-lda.conf に次のように追加します。
postmaster_address = postmaster@{server名}
ログの解析
エラーがでたらサイトで検索してみるにしても、ログをみて原因を発見し簡単に直ることも多いものです。ターミナルを別に開き、tail -f /var/log/mail.log で常時監視します。さらに、認証でのエラーがメールサーバの時は特に多いので、/etc/dovecot/conf.d/10-logging.conf で次のようにしてデバッグします。設定が問題なく完成したらもとに戻します。
auth_debug_passwords = yes
Fail2banのインストール(Optional)
ユーザーの制限にFail2banがいいとのことので入れてみました。Iptablesのlimitとあまり違いがないみたいだけど、メールで知らせてくれたりと機能的には優れています。
設定はとても簡単で/etc/fail2ban/jail.d に設定ファイル追加だけです。Ubuntu Xenialではdefaults-debian.conf がインストールされていて、sshがデフォルトで設定してあります。それを参考に例えばメールサーバーの場合、次の内容で設定ファイルを作ります。
[postfix-rbl]
enabled = true
sudo systemctl restart fail2ban
で再起動すれば新しい設定が有効になります。iptables で調べるには、
sudo iptables -S
-P INPUT ACCEPT
-P FORWARD ACCEPT
-P OUTPUT ACCEPT
-N f2b-postfix-rbl
-N f2b-sshd
-A INPUT -p tcp -m multiport --dports 25,465,587 -j f2b-postfix-rbl
-A INPUT -p tcp -m multiport --dports 22 -j f2b-sshd
-A f2b-postfix-rbl -j RETURN
-A f2b-sshd -j RETURN
とこのように表示されFail2ban が動いているのが分かります。
opendkimのインストール
sudo apt-get install opendkim opendkim-tools
/etc/opendkim.conf
Syslog yes
UMask 007
Domain hottuna.tk
KeyFile /etc/dkimkeys/myselector.private
Selector myselector
Socket inet:8891@localhost
UserID opendkim
PidFile /var/run/opendkim/opendkim.pid
OversignHeaders From
TrustAnchorFile /usr/share/dns/root.key
キーを作成します。
cd /etc/dkimkeys
sudo opendkim-genkey -s myselector -d <server name>
sudo chown opendkim: *
DNSレコードのtxtを編集します。
myselector._domainkey IN TXT "v=DKIM1; k=rsa; s=email; p=xxxxxxxxxxxxxxxxxxxxxxxxxx"
postfixの設定をします
/etc/postfix/main.cf
milter_default_action = accept
milter_protocol = 2
smtpd_milters = inet:localhost:8891
non_smtpd_milters = inet:localhost:8891
/etc/default/opendkim
SOCKET="inet:8891@localhost"
再起動します
systemctl restart opendkim
systemctl restart postfix
dkimのテストしてみます
host -t TXT myselector._domainkey.hottuna.tk
または
dig myselector._domainkey.hottuna.tk txt
結果
; <<>> DiG 9.11.3-1ubuntu1.8-Ubuntu <<>> myselector._domainkey.hottuna.tk txt
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 62394
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 4, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;myselector._domainkey.hottuna.tk. IN TXT
;; ANSWER SECTION:
myselector._domainkey.hottuna.tk. 3600 IN TXT "v=DKIM1; h=sha256; k=rsa; p=.....
メールヘッダーのチェックの方法は次のサイトにメールヘッダーをコピーして調べます
1 Authentication-Results spf=pass (sender IP is xx.xx.xx.xx) smtp.mailfrom=hottuna.tk; hotmail.com; dkim=pass (signature was verified) header.d=hottuna.tk;hotmail.com; dmarc=temperror action=none header.from=hottuna.tk;
他DNSレコード編集
逆引きはVPS等の管理者に連絡。
MX A [IP ADDRESS]
MX mx.[DOMAIN NAME]
TXT v=spf1 +a:[DOMAIN NAME]
+a:mx.[DOMAIN NAME] +mx ~a
MYSELECTOR._DOMAINKEY TXT v=DKIM1; h=sha256; k=rsa; s=email; p=M……
設定例
postfix
/etc/postfix/main.cf
compatibility_level = 2
command_directory = /usr/sbin
daemon_directory = /usr/lib/postfix/sbin
data_directory = /var/lib/postfix
mail_owner = postfix
myhostname = mx.<server name>
mydomain = <server name>
myorigin = $mydomain
inet_interfaces = all
mydestination = localhost, mx.$mydomain
local_recipient_maps = unix:passwd.byname $alias_maps
unknown_local_recipient_reject_code = 550
mynetworks = 127.0.0.0/8, 192.168.10.0/24, 192.168.1.0/27, 192.168.250.1/32, 192.168.200.0/24
virtual_transport = lmtp:unix:private/dovecot-lmtp
virtual_mailbox_domains = $mydomain
virtual_alias_maps = hash:/etc/postfix/virtual_aliases
relay_domains =
relayhost =
alias_maps = hash:/etc/aliases
alias_database = hash:/etc/aliases
smtpd_banner = $myhostname ESMTP
debugger_command =
PATH=/bin:/usr/bin:/usr/local/bin:/usr/X11R6/bin
ddd $daemon_directory/$process_name $process_id & sleep 5
sendmail_path = /usr/sbin/postfix
newaliases_path = /usr/bin/newaliases
mailq_path = /usr/bin/mailq
setgid_group = postdrop
inet_protocols = ipv4
message_size_limit = 10485760
#smtpd_tls_cert_file=/etc/ssl/certs/ssl-cert-snakeoil.pem
#smtpd_tls_key_file=/etc/ssl/private/ssl-cert-snakeoil.key
smtpd_tls_CAfile = /etc/ssl/certs/ca-certificates.crt
smtpd_tls_cert_file = /etc/ssl/certs/<server name>.crt
smtpd_tls_key_file = /etc/ssl/private/<server name>.key
#smtpd_tls_security_level = encrypt
#smtp_tls_security_level = encrypt
smtpd_tls_security_level = may
smtp_tls_security_level = may
smtpd_tls_mandatory_ciphers = high
smtpd_tls_mandatory_exclude_ciphers = aNULL, MD5
smtpd_tls_mandatory_protocols = !SSLv2, !SSLv3
smtpd_sasl_auth_enable = yes
smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth
smtpd_tls_auth_only = yes
smtpd_recipient_restrictions = permit_sasl_authenticated,
reject_invalid_hostname,
reject_unknown_recipient_domain,
reject_unauth_destination,
reject_rbl_client sbl.spamhaus.org,
permit
smtpd_helo_restrictions =
permit_mynetworks,
permit_sasl_authenticated,
# check_client_access cidr:/etc/postfix/local.cidr,
reject_invalid_helo_hostname,
reject_non_fqdn_helo_hostname,
reject_unknown_helo_hostname
recipient_delimiter = +
non_smtpd_milters=inet:127.0.0.1:8891
smtpd_milters=inet:127.0.0.1:8891
milter_default_action = accept
milter_protocol = 2
!SSLv2のエラーがある場合は次のように設定します。
smtpd_tls_mandatory_protocols = TLSv1
Optional:
[ここから]
gmail宛のメールをリレーサーバーにする場合:
/etc/postfix/main.cf に追加します。
transport_maps = hash:/etc/postfix/transport
smtp_sasl_auth_enable = yes
smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd
smtp_sasl_security_options = noanonymous
mtp_sasl_mechanism_filter = plain, login
smtp_use_tls = yes
/etc/postfix/transport
gmail.com smtp:[smtp.gmail.com]:587
/etc/postfix/sasl_passwd
[smtp.gmail.com]:587 <user name>@gmail.com:<gmail password>
sudo chmod 400 /etc/postfix/sasl_passwd
sudo postmap /etc/postfix/sasl_passwd
sudo postmap /etc/postfix/transport
[ここまで]
/etc/postfix/master.cf
smtp inet n - y - - smtpd
submission inet n - y - - smtpd
-o smtpd_sasl_auth_enable=yes
pickup unix n - y 60 1 pickup
cleanup unix n - y - 0 cleanup
qmgr unix n - n 300 1 qmgr
tlsmgr unix - - y 1000? 1 tlsmgr
rewrite unix - - y - - trivial-rewrite
bounce unix - - y - 0 bounce
defer unix - - y - 0 bounce
trace unix - - y - 0 bounce
verify unix - - y - 1 verify
flush unix n - y 1000? 0 flush
proxymap unix - - n - - proxymap
proxywrite unix - - n - 1 proxymap
smtp unix - - y - - smtp
relay unix - - y - - smtp
showq unix n - y - - showq
error unix - - y - - error
retry unix - - y - - error
discard unix - - y - - discard
local unix - n n - - local
virtual unix - n n - - virtual
lmtp unix - - y - - lmtp
anvil unix - - y - 1 anvil
scache unix - - y - 1 scache
maildrop unix - n n - - pipe
flags=DRhu user=vmail argv=/usr/bin/maildrop -d ${recipient}
uucp unix - n n - - pipe
flags=Fqhu user=uucp argv=uux -r -n -z -a$sender - $nexthop!rmail ($recipient)
ifmail unix - n n - - pipe
flags=F user=ftn argv=/usr/lib/ifmail/ifmail -r $nexthop ($recipient)
bsmtp unix - n n - - pipe
flags=Fq. user=bsmtp argv=/usr/lib/bsmtp/bsmtp -t$nexthop -f$sender $recipient
scalemail-backend unix - n n - 2 pipe
flags=R user=scalemail argv=/usr/lib/scalemail/bin/scalemail-store ${nexthop} ${user} ${extension}
mailman unix - n n - - pipe
flags=FR user=list argv=/usr/lib/mailman/bin/postfix-to-mailman.py
${nexthop} ${user}
/etc/postfix/reject_sender
touch reject_sender
postmap /etc/postfix/reject_sender
/etc/postfix/virtual_aliases
postmaster root
webmaster root
# Person who should get root's mail
root (user1)
info@<server name> (user1)
sudo adduser --system --home /var/vmail --uid 550 --group --disabled-login vmail
sudo postmap /etc/postfix/virtual_aliases
dovecot
/etc/dovecot/dovecot.conf
!include_try /usr/share/dovecot/protocols.d/*.protocol
listen = *
dict {
}
!include conf.d/*.conf
!include_try local.conf
/etc/dovecot/conf.d/10-auth.conf
disable_plaintext_auth = yes
auth_mechanisms = plain login
!include auth-system.conf.ext
/etc/dovecot/conf.d/10-logging.conf : (デバッグ用です)
log_path = syslog
auth_debug_passwords = yes # for debug
plugin {
}
/etc/dovecot/conf.d/10-mail.conf
mail_location = maildir:/var/vmail/%d/%n
passdb {
driver = passwd-file
args = scheme=CRYPT username_format=%u /etc/dovecot/users
}
userdb {
driver = static
args = uid=vmail gid=vmail home=/var/vmail/%d/%n
}
namespace inbox {
inbox = yes
}
/etc/dovecot/conf.d/10-master.conf
service imap-login {
inet_listener imap {
port = 0
}
inet_listener imaps {
port = 993
ssl = yes
}
}
service pop3-login {
inet_listener pop3 {
}
inet_listener pop3s {
}
}
service lmtp {
unix_listener /var/spool/postfix/private/dovecot-lmtp {
mode = 0666
user = postfix
group = postfix
}
}
service imap {
}
service pop3 {
}
service auth {
unix_listener /var/spool/postfix/private/auth {
mode = 0666
user = postfix
group = postfix
}
user = $default_internal_user
}
service auth-worker {
user = $default_internal_user
}
service dict {
unix_listener dict {
}
}
/etc/dovecot/conf.d/10-ssl.conf
ssl = required
ssl_cert = </etc/letsencrypt/live/<mydomain>/fullchain.pem
ssl_key = </etc/letsencrypt/live/<mydomain>/privkey.pem
ssl_protocols = !SSLv3
ssl_cipher_list = kEECDH:+kEECDH+SHA:kEDH:+kEDH+SHA:+kEDH+CAMELLIA:kECDH:+kECDH+SHA:kRSA:+kRSA+SHA:+kRSA+CAMELLIA:!aNULL:!eNULL:!SSLv2:!RC4:!MD5:!DES:!EXP:!SEED:!IDEA:!3DES
/etc/dovecot/conf.d/15-lda.conf
postmaster_address = postmaster@<server name>
protocol lda {
}
/etc/dovecot/conf.d/20-imap.conf
/etc/dovecot/conf.d/20-lmtp.conf
/etc/dovecot/conf.d/20-pop3.conf
Optional: ユーザーパスワードの作成
pass-creator.sh
#!/bin/sh
pass=`date +%N | sha256sum | base64 | head -c 16 ; echo`
domain=`postconf -f | grep ^mydomain | sed 's/^mydomain\s*=\s*\(.*\)$/\1/'`
passfile="users"
readable_pass="users-pass.txt"
DOVECOT_CONF="/etc/dovecot"
echo
echo -n "Name: "
read name
echo
mailpass=`doveadm pw -s SHA512-CRYPT -p $pass`
doveadm pw -t $mailpass -p $pass | grep -q \(verified\)
if [ "$?" -eq "0" ]; then
echo "Password check --> OK"
else
echo "Password check --> Failed"
exit 1
fi
echo "${name}@${domain}:${mailpass}" >> $DOVECOT_CONF/$passfile
echo "${name}@${domain} : ${pass}" >> $readable_pass
echo
echo "Account : ${name}@${domain}"
echo "Password : ${pass}"
echo
exit 0
Postgrey
/etc/postfix/main.cf
smtpd_recipient_restrictions =
check_policy_service inet:127.0.0.1:10023
/etc/default/postgrey
OSTGREY_OPTS="--inet=10023"
Roundcubeの設定
install
apt install roundcube roundcube-mysql roundcube-plugins php-net-idna2
データベース MySQL:
CREATE DATABASE roundcubemail /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */;
GRANT ALL PRIVILEGES ON roundcubemail.* TO 'roundcube'@'<roundcube IP>' IDENTIFIED BY '<password>';
FLUSH PRIVILEGES;
RoundCube:
roundcube HOST:
cd /usr/share/dbconfig-common/data/roundcube/{install | upgrade}
mysql -h <mysql IP> -u roundcube -D roundcubemail -p < mysql
/etc/roundcube/debian-db.php
<?php
$dbuser='roundcube';
$dbpass='<password>';
$basepath='';
$dbname='roundcubemail';
$dbserver='<IP or localhost>';
$dbport='3306';
$dbtype='mysql';
/etc/roundcube/config.inc.php
<?php
$config = array();
include_once("/etc/roundcube/debian-db-roundcube.php");
$config['default_host'] = 'ssl://<host name>';
$config['smtp_server'] = 'tls://<host name>';
$config['smtp_port'] = 587;
$config['smtp_user'] = '%u';
$config['smtp_pass'] = '%p';
$config['support_url'] = '';
$config['product_name'] = 'Roundcube Webmail';
$config['des_key'] = 'x*********************';
$config['plugins'] = array(
'archive',
'zipdownload',
);
$config['skin'] = 'larry';
/etc/roundcube/defaults.inc.php
...
$config['smtp_server'] = '<host name>';
$config['smtp_port'] = 587;
$config['smtp_user'] = '';
$config['smtp_pass'] = '';
$config['smtp_auth_type'] = '';
$config['smtp_auth_cid'] = null;
$config['smtp_auth_pw'] = null;
$config['smtp_helo_host'] = '';
$config['smtp_timeout'] = 0;
$config['smtp_conn_options'] = null;
$config['mime_types'] = '/etc/roundcube/mime.types';
$config['log_dir'] = '/var/log/roundcube/';
$config['temp_dir'] = '/var/cache/roundcube';
...
...
$config['cipher_method'] = 'AES-256-CBC';
...
/etc/hosts(ポートフォワーディングしている場合)
...
<HOST IP> <host name> # e.g: 192.168.1.1 mymail.com
...
/etc/nginx/sites-enabled/mail
server {
listen 80;
server_name <host name>;
#location = /50x.html {
# root /usr/share/nginx/html;
#}
#error_page 404 /404.html;
#error_page 500 502 503 504 /50x.html;
location /webmail {
alias /var/lib/roundcube;
index index.php
error_log /var/log/nginx/roundcube.error;
access_log /var/log/nginx/roundcube.access;
# Favicon
location ~ ^/webmail/favicon.ico$ {
root /var/lib/roundcube/skins/classic/images;
log_not_found off;
access_log off;
expires max;
}
# Robots file
location ~ ^/webmail/robots.txt {
allow all;
log_not_found off;
access_log off;
}
# Deny Protected directories
location ~ ^/webmail/(config|temp|logs)/ {
deny all;
}
location ~ ^/webmail/(README|INSTALL|LICENSE|CHANGELOG|UPGRADING)$ {
deny all;
}
location ~ ^/webmail/(bin|SQL)/ {
deny all;
}
# Hide .md files
location ~ ^/webmail/(.+\.md)$ {
deny all;
}
location ~ ^/webmail/\. {
deny all;
access_log off;
log_not_found off;
}
#Roundcube fastcgi config
location ~ /webmail(/.*\.php)$ {
fastcgi_pass unix:/run/php/php7.2-fpm.sock;
fastcgi_split_path_info ^/webmail/(.+\.php)(/.*)$;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $request_filename;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param PHP_VALUE open_basedir="/tmp/:/usr/share/roundcube:/var/cache/roundcube:/var/lib/roundcube:/etc/roundcube:/var/lib/roundcube/temp:/var/log/roundcube:/usr/share/php";
include fastcgi_params;
}
}
}
/etc/php/7.2/fpm/php.ini
date.timezone = Asia/Tokyo
systemctl reload php7.2-fpm
インストーラーの設定:(設定後’false’に変えます)
/etc/roundcube/defaults.inc.php
$config['enable_installer'] = true;
cd /usr/share/roundcube
ln -s /etc/roundcube config
cd /var/lib/roundcube
ln -s /usr/share/roundcube/installer/ .
cd /etc/roundcube
chown root:www-data config.inc.php debian-db.php defaults.inc.php
chmod 640 config.inc.php debian-db.php defaults.inc.php
mkdir -p /var/cache/roundcube
chown www-data: /var/log/roundcube /var/cache/roundcube
chmod 640 /var/log/roundcube /var/cache/roundcube
wget http://svn.apache.org/repos/asf/httpd/httpd/trunk/docs/conf/mime.types
mv mime.types /etc/roundcube
debian系は設定が独自なのでDBチェックエラーは無視します。
メールの送受信のテストが済んだらインストーラーを外します。
$config['enable_installer'] = false;
rm /var/lib/roundcube/installer
Roundcubeのスキン
有料のスキンは機能豊富で良いのですが無料でシンプルなスキンをインストールしてみます。
https://github.com/EstudioNexos/mabola
追記:multiple domainの設定
非常に困ったことに古いドメインを使わざるを得ない状況なったので調べてみました。
DDNSの設定:
IPアドレス、mxドメインはそのままです。
Let’s encrypt:
サブドメインだけでなく、old_domainと組み合わせてマルチドメイン化ができます。これによって認証が可能になります。
Postfix:
ログや検索で調べた結果、つぎのところを変更します。
mydestination = localhost, $myhostname, mx.$old_domain
virtual_mailbox_domains = $mydomain, $old_domain
これで着信はできるようになりました。
References:
https://appbead.com/blog/how-to-setup-mail-server-on-debian-8-jessie-with-postfix-dovecot-1.html https://appbead.com/blog/how-to-setup-mail-server-on-debian-8-jessie-with-postfix-dovecot-2.html Roundcube RainLoop Webmail https://www.digitalocean.com/community/tutorials/how-to-install-and-configure-dkim-with-postfix-on-debian-wheezy Arch:OpenDKIM Debian:OpenDKIM