久し振りにfrontier-lineサーバ経由でメールを送信しようとしたら、Relay Access Deniedエラーが出て送れない。この間、SMTPAuthを使うように設定して送信できることもチェックしたはずななのに。
 ネットで簡単に調べたら、

smtpd_recipient_restrictions = permit_mynetworks, permit_sasl_authenticated, reject_unauth_destination

はPostfix 2.10以降では使えなくて、かわりに、

smtpd_relay_restrictions = permit_mynetworks, permit_sasl_authenticated, reject_unauth_destination

をつかべし、という情報を拾った。設定ファイルを書き直してデーモンを上げ直したがやっぱり送れない。
 よくよく調べたら、Thunderbirdの送信サーバの設定が、SSL/TLSを使うようになっていなかったし、パスワード認証も無しになっていた。送信サーバの設定を、SSL/TLS使用かつ通常のパスワード認証に設定しなおしたら何の問題もなく送信できた。

SMTPAuth導入

|2015/4/30(木曜日)-23:06| カテゴリー: コンピューターの使い方関係
| コメントする

 以前、メールが送れないということを書き、サブミッションポートの設定とPOP before SMTPの設定で解決したと書いたのだけど、いつの間にかまた送れなくなっていた。dracdは動いていてくれるのだけど、送信しようとするとrelayできないというエラーになる。
 で、あきらめてSMTPAuthを導入することにした。SMTP認証の際、SMTP over SSLでユーザー名とパスワードを暗号化する。

 まず、Cyrus SASL2をインストール。


cd /usr/ports/security/cyrus-sasl2
make BATCH=yes WITHOUT_OTP=yes WITH_BDB=yes install clean

 次に、Cyrus saslauthd インストール。


cd /usr/ports/security/cyrus-sasl2-saslauthd
make BATCH=yes WITH_BDB=yes install clean

インストールできたら、


/usr/local/etc/rc.d/saslauthd start

で、デーモンを起動しておく。

 暗号化のためのOpenSSLをインストール。ソースをダウンロードして展開したディレクトリにcdした後、


./config
make
make test
make install

とやれば、


/usr/local/ssl/bin/openssl

にインストールされる。
 /etc/pki/tls/certsディレクトリが無いので作った後、


cd /etc/pki/tls/certs
/usr/local/ssl/bin/openssl req -new -x509 -nodes -days 365 -out mail.crt -keyout mail.key

を実行。いろいろきいてくるので、次のように入力。


Country Name (2 letter code) [AU]:JP
State or Province Name (full name) [Some-State]:
Locality Name (eg, city) []:
Organization Name (eg, company) [Internet Widgits Pty Ltd]:
Organizational Unit Name (eg, section) []:
Common Name (e.g. server FQDN or YOUR name) []:*.frontier-line.org
Email Address []:

 これが終わると、mail.crtとmail.keyができる。パーミッションを変更。


chmod 600 mail.key

セキュリティ証明書の作成。


/usr/local/ssl/bin/openssl x509 -in mail.crt -outform der -out mail.der

 次にPostfix本体の再インストール。一度make deinstallしてからmake reinstallとかするとうまくいく。


make WITH_SASL2=yes WITH_TLS=yes WITH_BDB=yes WITH_BDB_VER=41

で適当にインストール。
 portsから入れると/usr/local/sbin/postfixが動く。ソースから入れた時とディレクトリが違い、いろいろやってるとどっちかわからなくなるので要注意。

 もろもろの設定は次の通り。

/usr/local/etc/postfix/main.cfは、


myhostname = frontier-line.org
mydomain = frontier-line.org
myorigin = $mydomain
inet_interfaces = all
mydestination = $myhostname, localhost.$mydomain, localhost, $mydomain
relay_domains = $mydestination
alias_maps = hash:/etc/postfix/aliases
alias_database = hash:/etc/postfix/aliases
mail_spool_directory = /var/mail

とやっておいて、ファイルの最後に、SMTPAuthに必要な設定を追加。

smtpd_sasl_auth_enable = yes
smtpd_sasl_local_domain = $mydomain
smtpd_sasl_security_options = noanonymous
smtpd_recipient_restrictions = permit_mynetworks, permit_sasl_authenticated, reject_unauth_destination
broken_sasl_auth_clients = yes

さらに、TLSを使うための追加。

smtpd_tls_security_level = may
smtpd_tls_key_file = /etc/pki/tls/certs/mail.key
smtpd_tls_cert_file = /etc/pki/tls/certs/mail.crt
smtpd_tls_loglevel = 1
smtpd_tls_received_header = yes

添付ファイルの大きいのを受信できるようにするための設定を追加。

mailbox_size_limit= 102400000
message_size_limit = 51200000
body_checks_size_limit = 204800000

/etc/rc.confは、


saslauthd_enable="YES"
saslauthd_flags="-a sasldb"

を追加。saslauthdを自動起動するように設定。
postfixを最初に入れた時に変更した分


sendmail_enable="NO"
sendmail_submit_enable="NO"
sendmail_outbound_enable="NO"
sendmail_msp_queue_enable="NO"
postfix_enable="YES" 

はそのまま。

/usr/local/lib/sasl2/smtpd.confに、


pwcheck_method: auxprop

と書いておく。

/etc/periodic.confは、既に変更済みだが、


daily_clean_hoststat_enable="NO"
daily_status_mail_rejects_enable="NO"
daily_status_include_submit_mailq="NO"
daily_submit_queuerun="NO"

となっているのを確認。

/etc/mail/mailer.confは、


sendmail        /usr/local/sbin/sendmail
send-mail       /usr/local/sbin/sendmail
mailq                   /usr/local/sbin/sendmail
newaliases              /usr/local/sbin/sendmail

で、これは最初のインストールの時のまま。

/etc/make.confは、


PERL_VERSION=5.14.4
NO_MAILWRAPPER=YES
NO_SENDMAIL=YES

で、これも他のインストールで決めたまま変更なし。何も設定していないなら特に何かする必要は無いかも。

/usr/local/etc/postfix/master.cfで、以下の部分のコメントを外す。


smtp      inet  n       -       n       -       -       smtpd
  -o syslog_name=postfix/submission
  -o smtpd_tls_security_level=may

smtps     inet  n       -       n       -       -       smtpd
  -o syslog_name=postfix/smtps
  -o smtpd_tls_wrappermode=yes
  -o smtpd_sasl_auth_enable=yes

 smtp authユーザーを追加する。


saslpasswd2 -c username

で、登録したいユーザーをusernameのところに書くと、パスワードをきいてくる。
登録後は、


sasldblistusers2

で確認。この登録でデータベースができるので、所有者とパーミッションを変更。


chown cyrus:mail /usr/local/etc/sasldb2
chmod 640 /usr/local/etc/sasldb2

 /etc/servicesで、サブミッションポート587とSMTP over SSLのポート465がコメントアウトされていることを確認し、


/usr/local/sbin/postfix stop
/usr/local/sbin/postfix start

とやって、設定を確実に読み込ませる。

 デーモンが上がったら、


netstat -na | grep 587
netstat -na | grep 465

を実行し、この2つのポートをlistenしていることを確認する。

 TLSの動作確認は、


telnet localhost 25
してから、
EHLO localhost
STARTTLS
.

を順番に入力して様子を見る。

 今回、どういうわけか、newaliasesでできる/etc/aliasesがうまくpostfixに認識されず、データベースを開けないために接続が拒否され、外部からのメールが到達しないという現象にみまわれた。main.confで、


alias_maps = hash:/etc/postfix/aliases
alias_database = hash:/etc/postfix/aliases

と設定し、/etc/postfix/aliasesを書き換えたら


/usr/local/sbin/postalias  /etc/postfix/aliases

を実行するとエラーは出ない。メーラーデーモン共通で使えるaliasesでうまくいかない理由はよくわからない。

 Thunderbird側の設定は、
サーバ名:frontier-line.org
ポート番号:465
接続の保護:SSL/TLS
認証方式:通常のパスワード認証
で接続できる。

 なお、今回作ったTLSの証明書は、いわゆるオレオレ証明書なので、Thunderbird様から怪しいと怒られますorz。でもまあ、オレがrootでオレが設定してオレしか使わないオレ専用サーバなので、証明書もオレオレでいいんですよね。例外設定して警告しないようにしても問題なしです。

 mod_evasive入れたんで、ちょっとはDOS攻撃に強くなるかと思ったのだけど、それでも時々サーバが動かなくなる。OS自体は動いてるのだけど、swapを使い尽くして何もできなくなる。swap_pagerのエラーログが出続け、logrotateしてると、肝心のエラーが出始める直前の状態のログが流れ去っていたりする。原因究明のために、パソコンから端末を開いてtopコマンドを動かしっぱなしにしてみた。これだと、swapを使い尽くすと通信も激重になるので、端末画面にトラブルの状態がそのまま残る。
 その結果、原因はhttpdで、httpdの数はそれほどでもないが使用メモリが跳ね上がってるケースと、httpd1つの使用メモリはそれほどでもないが一度に大量に動いてメモリを食い尽くすケースの2通りが起きることがわかった。
 apacheからはプロセスの管理がデフォルトでeventになっているので、これを、PHPを使う場合のお薦めとされているpreforkに変更。
./configure –prefix=/usr/local/apache2 –enable-so –enable-mods-shared=all –enable-rewrite=shared –with-mpm=prefork
とやってから make install。
http -V
で、mpmがpreforkであることを確認。

 設定は、httpd.confで、extra/main.confとextra/mpm.confを見に行くようにしておいて、main.confでKeepAliveをOffにする。mpm.confは、
StartServers 5
MinSpareServers 5
MaxSpareServers 10
MaxRequestWorkers 12
MaxConnectionsPerChild 100
という、数を増やさず、接続回数100回で一度メモリを解放させるということにして様子を見ることにした。お行儀の悪いPHPが紛れ込んでもこの程度なら何とかなるかな。

 やってみた結果、まず、httpdのプロセスのSIZEが平均350Mくらいだったのが165M〜180Mに減り、WordPressの画像の多いページにアクセスしてもプロセスの数が無闇に増えることもなくなった。その分、アクセスが集中すると重くなるだろうとは思うが、最初だけ多少早くてもswapに落ち始めたらどのみち激重になって復活させるには強制リブートしかないので、それなら少しタイミングを外せばまた軽くなる方がましだろう。

先週末くらいからしばしばこのサーバが止まりまして、swap_pagerでエラー発生で、強制リブート以外に動かす手段が無くなります。

apacheのログを見てみると、WordPressのログインに連続して関係無いアドレスから連続アクセスがあったりして、まあよくあることだけど攻撃されてるなと。因果関係がはっきりしないのだけど、集中的な攻撃の後、FreeBSDがswap確保に失敗するということもあるようなので、DoS攻撃対策をして様子を見ようと思いました。

ApacheのDos対策モジュールというと、mod_evasiveが有名です。インストール記録もいろんなサイトさんにあるのだけど、実は罠が。Apache2.2までは検索して出てくるサイトさんのやり方でインストールができるのですが、2.4で同じようにするとエラーが出てインストール不可能です。2.Xで使える、と書いてあるのでつい信用して痛い目を見ました。どうも、2.4からApacheのAPI変更があったのがきいているようです。動かすには、ソースコードを何行か変更しなければならないのです。それで、探し回って、修正済みのものがhttp://sites.extremehosting.ca/mod_evasive24/で公開されているのを見つけました。

このファイルをダウンロードしてきて、/usr/local/srcに入れます。
tar zxvf mod_evasive_1.10.1_apache_2.4.tar.gz
で、mod_evasiveというディレクトリに展開されます。mod_evasive24.cが、mod_evasive20.cを置き換えたものになります。変なコードが仕組まれてないか、オリジナルのものとdiffで確認しましたが大丈夫のようです。
ウチでは、apacheは、/usr/local/apache2に入れているので、

cd mod_evasive
/usr/local/apache2/bin/apxs -i -a -c mod_evasive24.c

でインストールが完了します。

一応、インストールするにはapacheにmod_so.cが入ってないといけないので、

/usr/local/apache2/bin/apachectl -l

で確認してから作業します。

インストールが終わると、httpd.confに、

LoadModule evasive20_module modules/mod_evasive24.so

が追加されます。

動かすには、ログファイル出力先を用意します。どこに作ってもいいので、Apacheのログのところに入れることにしました。

mkdir /usr/local/apache2/logs/mod_evasive/
chown nobody:nobody /usr/local/apache2/logs/mod_evasive/

書き込めるようにファイル所有者を変えておきます。

httpd.confに次の内容を追加します。

<IfModule mod_evasive24.c>
DOSHashTableSize 3097
DOSPageCount 3
DOSSiteCount 20
DOSPageInterval 2
DOSSiteInterval 1
DOSBlockingPeriod 3600
# DOSWhitelist 127.0.0.1 テスト後にこれをコメントアウトし、ループバックアドレスは全部許可に。
DOSLogDir "/usr/local/apache2/logs/mod_evasive"
# DOSEmailNotify xxxxx@xxxx.jp ←拒否したIPアドレスをメール送付。
</IfModule>

これが終わったら、./apachectl graceful を実行して設定を反映させます。

./apachectl -M

を実行すれば、モジュールが組み込まれたことを確認できます。

動作確認は添付のPerlスクリプトを使って行います。

cd /usr/local/src/mod_evasive
chmod +x test.pl
/usr/local/src/mod_evasive/test.pl

を実行し、途中まではOKで、途中からForbiddenになれば問題なく動作しています。このテストが棲んだら、httpd.confのループバックアドレスのところのコメントを外し、ループバックについては全て信頼するという設定に変更し、再度、./apachectl graceful を実行します。どこからのアドレスを拒否したかをメールで受け取りたければ、コメントを外して送り先メールアドレスを書き込めばできるようです。うるさそうなのでやってませんが。

 この日記帳と、「南部博士専用」ブログでは、WordPressのContact Form7というプラグインを利用して、管理者宛メールの送信ページを作っているわけですが、これが動いていなかった。メールを送ろうとすると「メッセージの送信に失敗しました。間をおいてもう一度お試しいただくか、別の手段で管理者にお問い合わせ下さい。」と出る。
 postfixの設定をいろいろ見直したのだけどおかしなところはなく、メーラーからの送受信も正常で、WordPress側でpostfixのメール送信ポートが変えられないことが原因ではないかと気がついた。postfix側はサブミッションポートでメール転送要求を受け付けるのに、WordPress側にはデフォルトではポート設定オプションがない。ということは多分、旧来の25番を使おうとしているはず。
 そこで、プラグインのインストール画面からWP Mail SMTPを検索してインストールして有効化。設定項目に「メール」が出るので、
WordPressの全てのメールをSMTP経由で送信する、にチェック
SMTP Host localhost
SMTP Port 587
Encryption なし
Ausentication いいえ
のみ設定して変更を保存した結果、無事にContact formから管理者宛メールが送られるようになった。

 新サーバに移って暫くして、WorePressで画像がアップロードできないことに気がつきました。エラーとしては、uploads/2014/07というディレクトリが作れないのでパーミッションを正しく設定しているか確認せよ、という内容。
 イラスト掲示板の移転の時には、掲示板システムの機能でアップロードできていたので気がつきませんでした。
 で、順番にチェック。
(1)ファイルパーミッション
  777, 757, 707, 755全て試しました。uploadsだけじゃなく、その上のwp-content、年と日付のサブディレクトリまで全て同じに変えて順番に試したけどどれでやっても書き込めず失敗。
(2)php.iniのupload_tmp_dirの設定
 設定されている先のディレクトリが存在し、誰でも書き込めることを確認。
(3)php.iniのアップロードサイズの確認
memory_limit = 1700M
post_max_size = 1600M
upload_max_filesize = 1500M
某所でこっそりアップローダを置いてるので、かなり凶悪にでかいファイルを許す設定。
(4)httpd.confの設定。cgiモードではなくhttps組み込みで動作させる場合はphp.iniを設定しただけでは設定が反映されない。
php_value memory_limit 1700M
php_value post_max_size 1600M
php_value upload_max_filesize 1500M

 一応念のためPHPのcgiモードでWordPressを動かしてみたがダメ。VPSで運用してるのでディスクには充分余裕がある。
 一体何が原因かと小一時間悩んだ末、WordPressの管理画面から[設定]→[メディア]を見ると、アップロードディレクトリへのパスが、デフォルトはwp-content/uploadsのはずが、なぜかルートディレクトリからのフルパス指定になっていた。バージョンアップのタイミングとデータベース移転のタイミングが悪かったのか、それともまだ他に原因があるのかわからないが、旧サーバで使っていた設定が中途半端に残っていたらしい。これをデフォルトに戻してやることであっさり解決。なお、こいつをデフォルトに戻して変更を保存したら、項目自体が設定画面から出なくなった。やはり古いバージョン特有の何かだったのかもしれない。

 メールが送れなくて焦るの続き。実は解決してなかった。
 何で問題が発覚しなかったかというと、手元の端末からSSHトンネリングで接続して、localhostつまり手元のパソコンのSSHに向けてメール送信を1回やってしまうと、どこかにその情報が記録されてしまい、うっかりデフォルトメールサーバをlocalhostにしたままだとメールが送れてしまっていたから。デフォルトをfrontier-line.orgにして接続失敗で今日になって発覚orz。
 原因は以前書いた通りで解決策も大体以前書いた通りなんだけど、4時間ほどなにげに嵌まった。その原因は、最初にソースからpostfixを入れる→何かうまく行かない→portsから入れる、をやってしまい、ソースから入れた時の設定ファイルは/etc/postfixの下、portsから入れた時の設定ファイルは/usr/local/etc/portfixの下、で、案の定/etc/postfixの方をいじっていて何で設定が反映されないのかと悩みまくるという、まあ、あるあるある……なオチ。
 解決の作業の前にとりあえず確認。
grep submission /etc/services
で、
submission 587/tcp
submission 587/udp
が出れば、サブミッションポートは予約済み。
/usr/local/etc/portfix/master.cfで、次の2行のコメントアウトを外して有効にする。POP before SMTPで認証済みなので、他の認証オプション関係はすべてコメントアウトのままにしておく。
submission inet n – n – – smtpd
-o syslog_name=postfix/submission
2行目移行の行頭スペースは必須。
service postfix restartあるいはpostfix reloadで変更を反映させる。
netstat -na | grep 587
で、
tcp4 0 0 *.587 *.* LISTEN
と出るし、 sockstat -4lでも、
root master 2708 17 tcp4 *:587 *:*
となって、確かにポート587で待ってますよ、ということが確認できた。念のためtelnet localhost 587を実行して接続できることも確認した。

 さて、メールを送ろうとすると、サーバに接続はできるものの、
454 4.7.1 Relay access denied
となる。
/usr/local/sbin/postconf | grep mail_version
でバージョンを確認すると、portから入ったのは2.10.1だった。2.9以前ではsmtpd_recipient_restrictionsで設定していたパラメータが、2.10移行ではsmtpd_relay_restrictionsで設定するようになったのだけど、古いままにしていたので出たエラー。/usr/local/etc/postfix/main.cfに
smtpd_relay_restrictions = permit_mynetworks, check_client_access,btree:/usr/local/etc/dracd,check_relay_domains,reject
と書いてもう1回postfix reloadして、無事送信できることを確認した。

 新サーバもそれなりに稼働を始めたので安心していたのだが、いろいろテンパっててメールの受信確認はしたけど送信確認はしてなかった。まあ設定に間違いはないだろうということで安心していて、今日送信しようとしたらできない。メールサーバに接続できないというメッセージが出る。
 最初は自分の設定を疑ってサーバを調べた。ひょっとしてポート開いてないんじゃ……と、
sockstat -4l
したら、ちゃんと25番ポートでメールサーバが待ち受けている。
 これはひょっとしてOutbound Port 25 Blockingか、ということで確認を開始。
 まず、さくらのVPSサーバから出て行く方のチェック。
nslookup -type=mx gmail.com
して出てきたサーバの一つに
telnet alt1.gmail-smtp-in.l.google.com 25
とやって接続を確認した。つまりVPSから外に向かう方は25番ポートが開いている。
 次に、手元のMacのターミナルを開いて同じことをしたら、
telnet alt1.gmail-smtp-in.l.google.com 25
Trying 74.125.193.26…
telnet: connect to address 74.125.193.26: Operation timed out
telnet: Unable to connect to remote host
となってつながらない。つまり使っているプロバイダが25番ポートへの接続をブロックしている。ということは、submissionポート(587)を使うしかない。
 /etc/postfix/master.cfの
submission inet n – n – – smtpd
を活かし、オプションとして、
-o smtpd_etrn_restrictions=reject
のみを設定してpostfix reloadで設定を読み込ませる。
 ウチはちょっと古い方式の、qpopper+dracdでpop before smtpをやってるので、SMTP AUTHはさしあたり必要ない。
 dracをつかう設定は、main.cfの方で、
smtpd_recipient_restrictions = permit_mynetworks, check_client_access,btree:/usr/local/etc/dracd,check_relay_domains,reject
とやってるるので、オプションのclient_restrictionで指定する必要は無い。
 次にThunderbirdのアカウント設定のウィンドウを開き、左側のアカウントリストの一番下のサーバ設定を開く。サーバにこのサーバを指定し、接続ポートとして587を指定、パスワード認証も暗号化も一切無しにしておく(認証はpopperとdracがやるので)。これでメールを送れるようになった。やれやれ。