オタク日記
(Mac と Linux, 2019Q1)

目次

2019-03-13 (Wed): 宅外サーバ-2 (6: Bogofilter)
2019-03-06 (Wed): 宅外サーバ-2 (5: Certificate + 動作検証)
2019-02-27 (Wed): 宅外サーバ-2 (4: データ転送と稼働開始)
2019-02-20 (Wed): 宅外サーバ-2 (3: Mailman)
2019-02-13 (Wed): 宅外サーバ-2 (2: Postfix + Dovecot)
2019-02-06 (Wed): 宅外サーバ-2 (1:Ubuntu-18.04 + Certificates)

古い日記:
2018Q4   2018Q3   2018Q2   2018Q1  
2017Q4   2017Q3   2017Q2   2017Q1  
2016Q4   2016Q3   2016Q2   2016Q1  
2015Q4   2015Q3   2015Q2   2015Q1  
2014Q4   2014Q3   2014Q2   2014Q1  
2013Q4   2013Q3   2013Q2   2013Q1  


2019-03-13 (Wed): 宅外サーバ-2 (6: Bogofilter)

SpamBayes、ありがとう、さようなら

自宅サーバの Spam Filter として SpamBayes を使い始めたのが 2003 年だから、もう 15 年あまりになる……自分でもちょっと驚き。ともあれ、途中 日本語スパムと闘うに書いたように spambayes-1.0.4jp にしてから、日本語のスパムメールにも切れ味よく対処してくれるようになった。 その頃の印象は、Spam と判断されるメールの数に対して、 Unsure とされる数はその 1/10 - 1/5 くらいの間に落ち着いていた。 (SpamBayes は、メールを Ham/Unsure/Spam と分類する。 Unsure は、Ham/Spam と判断するには根拠が十分でないという分類で、 当然こには本来 Ham とされるべきメールが入ったり (False Alarm) Spam とされるべきメールが入る (Missing Spam) 事があるので、 常に確認したり、人手で SpamBayes のトレーニング用のフォルダに 仕分けする必要がある。)

その後、プラットフォームの OS も spambayes 自体もバージョンアップしてきたが、それにつれて、 spam/unsure の比率 (切れ味) が悪くなってきていて、 かつ、ham が unsure に紛れ込む割合も大きくなっていたようだが、 スパムの絶対数が減ってきた事もあり、 あまり気にしていなかった……大事なメールが unsure に行っていて見逃してしまい「青くなる」という事もたまに有ったが……。

今回の宅外サーバの OS 更新の際に、あまりよく考えずに spambayes-1.1b2 に上げて、しかも、database (~/.hammie.db) まで更新 (再構築) してしまった。Ham/spam のアーカイブは元のを使ったので、移行した当初は目立った問題は見えなかった。 が、自分から出したテストメールが、悉く unsure になったり、unsure に入った ham を強制的にアーカイブに移して training しても、 一向に false alarm が減らなくなっている事に気付いた。

~/.hammie.db の再構築とか、古い spambayes に戻すとか色々やってみたが、思わしい結果は得られなかった。というか、 大分前から、このような傾向が出てきていたような気もする。つまりは、 1.0.4jp から、1.1a4 他にアップデートした頃から、 既におかしくなっていたのかも知れない。

だとすると、最初にやるべき事は -1.1b2 の「日本語化」だろう。日本語化と言っても、 要するに、空白に区切られずに、 ずらずらと文字が並ぶ日本語の単語を「意味のある単位」に分ける、 つまり「わかちがき」を実現する事だが、幸い mecab-python{,3} などの、"tokenizer の Python binding" もいくつかあり、この際、MeCab による形態要素解析の復習も兼ねて…… なんて、「いっちょかみ気質」(スケベ心とも言う) が出て、ちょっと手を出しかけたが、1.1b2 の python 2→3 で、いきなり躓いた。 どうも、mail module の構成が変わっているらしい。 これは手強い (かも知れない) と、あっさり降参した。(Python の mail module で mail message を扱おうとして四苦八苦した経験のせいで、 今もトラウマの一つになっている。)

Bogofilter にする

SpamBayes を離れて、なおかつ Python に拘らないとすると、 選択肢は急に増える。が、PHP は嫌だな、とか、 わかち書きが容易に組込めるといいな、とか、 できれば deb package で、などと言いはじめると、 候補者は絞られる。最後は、(SpamBayes と同様に) procmail と一緒に使えそう、という事で Bogofilter に行く事にした。

が、よくよく調べてみると、「deb package で」と「わかち書き組込み」 は両立しそうもない事がわかってきた。大層がっかりしたが、 幸いにも、bogofilter の日本語対応 (Bogofilter+MeCab patch) というサイトを見付け、 そこで供給される patch を使い、 それに沿ってトライしてみる事にした。但し、このサイトでは、 macOS の上で、MeCab、Bogofilter 共にソースからコンパイルする。

Bogofilter インストール

ソースからコンパイルはちょっと敷居が高そうだったので、 deb package のソースからスタートする事にする。 まずは、環境の整備とソースの確保:

fukuda@digoc04:~% sudo apt update
fukuda@digoc04:~% sudo apt upgrade -y
fukuda@digoc04:~% wget \
    https://www.c-wind.com/bogofilter/bogofilter-1.2.4+mecab-0.1.patch.gz
fukuda@digoc04:~% sudo apt install libdb++.dev libmecab-dev automake 
fukuda@digoc04:~% mkdir build
fukuda@digoc04:~% cd build
fukuda@digoc04:~/build% apt source bogofilter 
fukuda@digoc04:~/build% cd bogofilter-1.2.4+dfsg1 

ついで、patch を当てて、comiple, install

fukuda@digoc04:~/build/bogofilter-1.2.4+dfsg1% zcat \
    ~/bogofilter-1.2.4+mecab-0.1.patch.gz | patch -p1 -T 
fukuda@digoc04:~/build/bogofilter-1.2.4+dfsg1% CFLAGS="-DWAKATI" \
    LIBS="-lmecab" ./configure
fukuda@digoc04:~/build/bogofilter-1.2.4+dfsg1% make
fukuda@digoc04:~/build/bogofilter-1.2.4+dfsg1% ldd src/bogofilter             
	linux-vdso.so.1 (0x00007ffc053e9000)
	libdb-5.3.so => /usr/lib/x86_64-linux-gnu/libdb-5.3.so (0x00007f332f169000)
	libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f332edcb000)
 #1)	libmecab.so.2 => /usr/lib/x86_64-linux-gnu/libmecab.so.2 (0x00007f332e9ff000)
	libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f332e60e000)
	libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f332e3ef000)
	/lib64/ld-linux-x86-64.so.2 (0x00007f332f76f000)
	libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f332e066000)
	libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f332de4e000)
fukuda@digoc04:~/build/bogofilter-1.2.4+dfsg1% sudo make install  #2)
	

ここに:

  1. #1) libmecab がちゃんと include されている事が大事。
  2. #2) できたバイナリは /usr/local/bin に install される。

できた /usr/local/bin/bogofilter を使って、 早速トレーニングしてみる。トレーニング用のサンプルは、SpamBayes のためのもの (Maildir/.spambayes.{ham,spam}/cur) をそのまま用いる:

fukuda@digoc04:~% bogofilter -n -B Maildir/.spambayes.ham/cur
fukuda@digoc04:~% bogofilter -s -B Maildir/.spambayes.spam/cur 

これでできた、wordlist を確認してみると

fukuda@digoc04:~% bogoutil -d .bogofilter/wordlist.db | lv 
.....
過 5 2 20190313
過ぎ 6 3 20190313
過ぎた 2 2 20190312
過ぎたら 2 0 20190312
過ぎて 4 1 20190312
過ぎる 3 2 20190312
過ご 0 1 20190312
過ごし 6 2 20190312
過ごした 0 1 20190312
過ごして 2 1 20190312
過ごす 2 1 20190312
過ごせる 4 0 20190314
過ち 1 0 20190312
過労 0 1 20190312
過去 42 16 20190313
過多 3 0 20190312
.....
      

のようになる。メッセージは utf-8 に変換されていて、 「わかちがき」はきちんと実行されているようだ。

このデータベースを使って、過去、SpamBayes で Unsure と判断されてきたメールメッセージ (の新しい方のいくつか) を、 仕分けてみる:

fukuda@digoc04:~% for i in Maildir/.SPAM.unsure/cur/155* ; do  
/usr/local/bin/bogofilter -v < $i
done
X-Bogosity: Unsure, tests=bogofilter, spamicity=0.499985, version=1.2.4+mecab-0.1
X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4+mecab-0.1
X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4+mecab-0.1
X-Bogosity: Unsure, tests=bogofilter, spamicity=0.500000, version=1.2.4+mecab-0.1
X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4+mecab-0.1
X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4+mecab-0.1
X-Bogosity: Spam, tests=bogofilter, spamicity=1.000000, version=1.2.4+mecab-0.1
X-Bogosity: Spam, tests=bogofilter, spamicity=1.000000, version=1.2.4+mecab-0.1
X-Bogosity: Spam, tests=bogofilter, spamicity=1.000000, version=1.2.4+mecab-0.1
X-Bogosity: Unsure, tests=bogofilter, spamicity=0.686971, version=1.2.4+mecab-0.1
......
      

総数 262 のうち、(Ham/Unsure/Spam) = (65, 63, 134) と仕訳されたので、 かなり大まかにだが、「判別不能」のメールの数を 1/4 以下にできた、と言って良いだろう。

実稼働のための設定

SpamBayes から、この Bogofilter に切り換えるには、 ~/procmailrc を以下のように変更する:

# :0 fw:hamlock
# | /usr/bin/sb_filter

#1)
:0fw
| /usr/local/bin/bogofilter -u -e -p

:0e
{ EXITCODE=75 HOST }
#2)
:0:
* ^X-Bogosity: Spam
.SPAM.spam/

:0:
* ^X-Bogosity: Unsure
.SPAM.unsure/

ここに

  1. #1) パイプで、Bogofilter を通して、スパムを検出、 その結果を上記の "X-Bogosity: ..." ヘッダに乗せて返す。-u (update) は、その結果に応じて、 wordlist をアップデートする (明示的に training しなくても、 メッセージが通る度に wordlist を強化するという事。)
  2. #2) Bogofilter が返す値によって、Maildir の下の各ディレクトリに振り分ける。

以上までで、受信したメールの振り分けはできるようになっている。 さらに、(SpamBayes と同様に) Unsure となったメールを手で Spam/Ham に仕分けて、filter をトレーニングするのだが、それを助ける script を書いて、 crontab で走らせる。

fukuda@digoc04:~% cat scripts/bogotrain
#!/bin/bash
bogofilter -s -B ~/Maildir/.spambayes.spam_new   #1)
bogofilter -n -B ~/Maildir/.spambayes.ham_new
doveadm move spambayes.spam MAILBOX spambayes.spam_new ALL #2)
doveadm move spambayes.ham MAILBOX spambayes.ham_new ALL 

ここに

  1. #1) .spambayes.{spam,ham}_new というフォルダを新たに作り、 そこへ手で spam/ham を移し、それに対してトレーニングする。
  2. #2) トレーニングが終ったメッセージは、 他のトレーニング済みのサンプルと同じ場所へ移す。

若干面倒になったが、Bogofilter には SpamBayes に有った 「重複してのトレーニングを避けるメカニズム」が備わってないため、 このようになった。

これを、下のように、sb_mboxtrain に代えて、crontab で走らせる。

fukuda@digoc04:~% crontab -l
SHELL=/bin/bash        #1)
PATH=/usr/local/bin:~/scripts:/usr/bin:/bin
USER=fukuda            #2)
#14 4,12,20 * * *  sb_mboxtrain -d ~/.hammiedb -s ~/Maildir/.spambayes.spam -g ~/Maildir/.spambayes.ham > /dev/null
57 4 */3 * * python ~/scripts/sitemap_gen.py --config=sitemap/config.xml 
22 */4 * * * source bogotrain #3)

ここに

  1. #1) 下の #3) のように書くためにはこれが必要。
  2. #2) これも bogotrain の中の doveadm のために必須。
  3. #3) デフォルトの dash では、source コマンドは認識されない。

以上のように設定しておいて、時偶、.SPAM.unsure に溜ったメールを、 .spambayes.{spam_new,ham_new} に振り分けておくと、4 時間ごとに wordlist をトレーニングして、このフォルダを空にしてくれる。

この態勢がほぼ固まってからまだ 3 日程しか経っていないが、その間新たに Unsure に入ったメールは 6 件で、それらも振り分けた結果、新しく Unsure とされるメールの数はさらに減りつつある。 このまま定常運転として良いだろう。


2019-03-06 (Wed): 宅外サーバ-2 (5: Certificates + 動作検証)

Let's Encrypt の Certificate

Letsencrypt の certbot で certificate を取得するのに、 % certbot apache ではなくて、 % certbot certonly --web-root を使う事にしてから、かなり見通しが良くなって、 設定と自動更新がすんなり行くようになり、本格稼働を始めたが、 そのうち少々不満も出てきた。

これらの問題自体を解消するのは難しくはないが、 「VH conf の書換えなしに % certbot renew を走らせる」 と両立させるとなると、結構悩まされた。

些かの試行錯誤の結果、000-default.conf を

<VirtualHost *:80>
        ServerName imap.otacky.jp
        ServerAlias smtp.otacky.jp

        ServerAdmin webmaster@localhost
        DocumentRoot /var/www/letsencrypt
        <Directory /var/www/letsencrypt>
                 Options FollowSymlinks
                 AllowOverride None
                 Require all granted
        </Directory>

        ErrorLog ${APACHE_LOG_DIR}/error.log
        CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>

とし、000-default-le-ssl.conf

<IfModule mod_ssl.c>
<VirtualHost *:443>
        ServerName imap.otacky.jp
        ServerAlias smtp.otacky.jp
....

....

Include /etc/letsencrypt/options-ssl-apache.conf
SSLCertificateFile /etc/letsencrypt/live/www.otacky.jp/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/www.otacky.jp/privkey.pem
</VirtualHost>
</IfModule>

とする事で、{http,https}://{smtp,imap}.otacky.jp/${filename} に対して、'Forbidden' (${filename} == '') もしくは、 'Not Found' (${filename} が存在しない場合) を返すようにできた。 勿論、renewal の場合に certbot が置く challenge file は問題無く読み出せる。

また、mailman.confmailman-le-ssl.confは、

<VirtualHost *:80>
ServerName lists.otacky.jp
DocumentRoot /var/www/letsencrypt                       #1)
ErrorLog /var/log/apache2/lists-error.log
CustomLog /var/log/apache2/lists-access.log combined

## Common Area Start
<Directory /var/lib/mailman/archives/>
    Options FollowSymLinks
    AllowOverride None
</Directory>
<Directory /usr/lib/cgi-bin/mailman/>
    AllowOverride None
    Options ExecCGI
    AddHandler cgi-script .cgi
    Require all granted
</Directory>
<Directory /var/lib/mailman/archives/public/>
    Options FollowSymlinks
    AllowOverride None
    Require all granted
</Directory>
<Directory /usr/share/images/mailman/>
    AllowOverride None
    Require all granted
</Directory>
## Common Area End 

Alias /pipermail/ /var/lib/mailman/archives/public/
Alias /images/mailman/ /usr/share/images/mailman/
ScriptAlias /cgi-bin/mailman/ /usr/lib/cgi-bin/mailman/
# ScriptAlias / /usr/lib/cgi-bin/mailman/listinfo  
ScriptAliasMatch ^/$ /usr/lib/cgi-bin/mailman/listinfo  #2)

RewriteEngine on                                        #3)
RewriteCond %{SERVER_NAME} =lists.otacky.jp
RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]
</VirtualHost>
	

ここに、

  1. #1) Renewal にしか使わないので、000-default.conf と共用する。
  2. #2) マッチングパターンを '/' のみ (その前後に何もつかない) とする。 (つまり、例えば letsencrypt の challange file が指定されると、これにマッチせず、 上の DocumentRoot からの path であると解釈される。
  3. #3) http://lists.otacky.jp/.... という URI を https://lists.otacky.jp/.... に書換える (HTTPS アクセスを強制する。)
<IfModule mod_ssl.c>
<VirtualHost *:443>
ServerName lists.otacky.jp
DocumentRoot /var/www/letsencrypt
ErrorLog /var/log/apache2/lists-error.log
CustomLog /var/log/apache2/lists-access.log combined
#####
# Common Area
#####
Alias /pipermail/ /var/lib/mailman/archives/public/
Alias /images/mailman/ /usr/share/images/mailman/
ScriptAlias /cgi-bin/mailman/ /usr/lib/cgi-bin/mailman/
ScriptAliasMatch ^/$ /usr/lib/cgi-bin/mailman/listinfo

Include /etc/letsencrypt/options-ssl-apache.conf
SSLCertificateFile /etc/letsencrypt/live/www.otacky.jp/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/www.otacky.jp/privkey.pem
</VirtualHost>
</IfModule>

以上、かなり入り組んでしまったが、要するに:

fukuda@digoc04:~% sudo certbot certonly --webroot 
    -w /var/www/html -d www.otacky.jp -d otacky.jp 
    -w /var/www/letsencrypt -d smtp.otacky.jp -d lists.otacky.jp -d imap.otacky.jp

で、certificate を作る事に対応していて、かつ

fukuda@digoc04:~% sudo certbot renew 

が問題なく走るようにできた、と言う事。勿論、letsencrypt は、expire までの期間が一ヶ月を切らないと、実際の renew はしてくれないし、-f オプションをつけて、 強制的に試す事もできるが、これは一週間のうちに 5 回まで、 という制限がある。なので、上記のような入り組んだ設定の妥当性を確認するには、 何かを変更したら、毎回

fukuda@digoc04:~% sudo certbot renew --dry-run

をやって確認しておくのが吉だろう

メールサーバの評価

自前のメールサーバを立てるとなると、何はともあれ確認しないといけないのは、 第三者中継チェックとブラックリストに載っていないか、だった。前者は、RBL.JP というところで確認していたが、どうやらこのサイトは閉鎖となったらしい。 (長らくお世話になり、ありがとうございました。)

ブラックリストチェックは、MxToolbox.com というところにお願いしていた。8 個くらいの主立ったブラックリストをウォッチしていて、 その結果を週一回メールで報告してくれる、という優れもの (しかも、 このクラスだと無料。) ただ、何故かモニタするホストを、IP で指定するようになっていて、 Droplet を変更すると当然 IP は変わるので、それを変更しないといけないのだけど、 どうやっていいのか分からない……。という事で、digoc04 でサービスを開始してからの一ヶ月あまり、Black List Check はやれていない……。

ただ、四苦八苦しているうちに、そのやり方が判明した上に、free relay check 以外のツールの使い方も解ってきて、新サーバの評価にフルに活用させていただいている。 下の図は、同サイトの SMTP test というページ:

MxToolBox SMTP Test
MxToolBox の SMTP Test

(私が解る範囲の) 主立った項目がカバーされていて、一安心。'SMTP Open Relay' や、'SMTP TLS' のチェックがあっと言うまに完了するので、「大丈夫かいな」 という気もしないではないが、まあ、悪い気はしない。実は第一項は、最初は Fail だった。IP アドレスが逆引きできない、と言われていたのだけど、 それをどう解消すれば良いのか解らなかった。かなり四苦八苦した結果、 正解は、DigitalOcean のサイトで設定する、しかもそれは、droplet の名前を、 digoc04.otacky.jp のように変えるという事で実現される……(何て解り難いんだぁ)。

従来からやっていた「ブラックリスト」の監視も、「monitor を一旦消してしまう」 事で、モニタすべきホストの IP Address を変更できる、という事が解って、 早速対処した。勿論、一週間ごとのメールはまだだが、 とりあえず今現在のブラックリストの現況は解る。どうやら、「セーフ」のようだ。

MxToolBox Blacklist Monitor
MxToolBox の Blacklist Monitor

が、何故か smtp.otacky.jp から友人のメールアドレスへは送れない……mail.log で

Mar  6 12:39:45 digoc04 postfix/smtp[32297]: 3F27617AB5D: \
    to=<xxxxx@sbcglobal.net>, relay=ff-ip4-mx-vip1.prodigy.net[144.160.159.21]:25, \
    delay=1.3, delays=0.35/0.02/0.72/0.18, dsn=5.3.0, status=bounced \
    (host ff-ip4-mx-vip1.prodigy.net[144.160.159.21] said: 553 5.3.0 \
    flph830 DNSBL:ATTRBL 521< 128.199.161.24 >_is_blocked. \
    For assistance forward this email to abuse_rbl@abuse-att.net...) \ 

などと言われてしまう。Error Code は '553' だが、実際には、 AT&T の SMTP サイトが、スパムと見做してしまう、という事らしい。

一年前にも同じエラーメッセージで弾かれたが、 今回は IP アドレスが変わっているのに、やっぱりダメ。 abuse_rbl@abuse-att.net にメールを書いたら、自動レスポンスが「24 - 48 時間後に、ブロックを解除して報告する」 と言ってきたが、48 時間過ぎたが返事はまだ無い。

MxToolBox は、ブラックリストに載ってない、というのだが…… 有償サービスに切り換えれば、ひょっとして捜索するブラックリストの範囲を広げて、 abuse-att が使っているリストもカバーしてくれるのかも知れないが、不確実だし 現在の無料の「お試し」と「有償サービス」の値段の格差 ($300/mo) が大きすぎて、 悩ましい。(MxToolBox もレスポンスが良いとは言えない——ウェブサイトも email による問い合わせに対しても。)


2019-02-27 (Wed): 宅外サーバ-2 (4: データ同期と稼働開始)

新旧のサーバの切り換えに際して、空白期間を最小限に留めるためには、

  1. データ (Web コンテンツ (counter/log を含む)、メールメッセージ等) の最終的同期
  2. 新サーバ内の FQDN を xxxx.waremo.mine.nu から、 xxxx.otacky.jp に変更する
  3. DNS の FQDN (xxxx.otacky.jp) を新サーバに向ける (A record の IP アドレスを新サーバのものに書き直す。)
  4. 新サーバで、certificates を取り直す。

の各ステップを迅速にやらないといけない。

データ同期

ここでは、rsync の際に user:group を保持する事が重要。そのためには、まず、 新旧のサーバで、user ID と group ID が統一されていないといけない。 今回は、Ubuntu -> Ubuntu の転送であるし、一般ユーザは fukuda 一人と決めてあるので、矛盾は無かった。(もし違っていたら、 どうするのが一番良いのか、ちょっと想像がつかない……。)

あと、転送元で user が読めない、また、転送先で user が書けないファイルをどう扱うかについても、ちょっと悩んだが、結局、

事にすれば、一番簡単にやれそう。つまり、digoc02 の /etc/ssh/sshd_config

.....
PermitRootLogin yes
# PermitRootLogin no 
.....

と設定し、digoc04 で

fukuda@digoc04:~% rsync -ua otacky.jp:Maildir/ Maildir 
fukuda@digoc04:~% sudo rsync -Cuav otacky.jp:/var/www/html/ \
    /var/www/html
fukuda@digoc04:~% sudo rsync -Cuav otacky.jp:/var/www/sweetspot \
    /var/www/
fukuda@digoc04:~% sudo rsync -Cuav otacky.jp:/var/www/cgi-bin \
    /var/www/
fukuda@digoc04:~% sudo rsync -Cuav otacky.jp:/etc/apache2/ \
    /etc/apache2/    
fukuda@digoc04:~% rsync -Cuav otacky.jp:Sync/ Sync/
fukuda@digoc04:~% rsync -Cuav otacky.jp:BasiliskII .
fukuda@digoc04:~% sudo rsync -auv root@otacky.jp:/var/lib/mailman/ \
    /var/lib/mailman/ 

とやれば良い。

FQDN まわりの設定変更

hostname が waremo.mine.nu から otacky.jp に替わるので、 関連する config file を変更する。然程多くはなくて、

Mailman の Arvchives は、元々 otacky.jp で動いていたので、FQDN としては問題無い筈だが、default URL に正しく /cgi-bin/mailman/ がついているかどうか確認しておく。

fukuda@digoc04:/var/lib/mailman% sudo bin/withlist -l sor
Loading list sor (locked)
The variable `m' is the sor MailList instance
>>> m.web_page_url
'http://lists.otacky.jp/cgi-bin/mailman/'
>>> 

また、次の DNS 変更を実行する前に、旧サーバ (digoc02) の上で、certificate を revoke しておくのが良いだろう:

fukuda@digoc02:~% sudo certbot/certbot-auto revoke \
      --cert-path=/etc/letsencrypt/live/www.otacky.jp/cert.pem 
fukuda@digoc04:~% sudo certbot revoke 
      --cert-path=/etc/letsencrypt/archive/www.waremo.mine.nu/cert1.pem

DNS 変更

これは、DynDNS の上で行なったので、一般的な手順を示す事はできないが、 要するに、

otacky.jp    60   A  128.199.xxx.xxx
	  

のような A record を作製 (IP Address を編集) すれば良い。

その際、ついでに、certificate を取得する全ての hostname (例えば、smtp.otacky.jp 他) の CNAME が明示的に作られている事を確認しておく。

LetsEncrypt Certificate

新しい hostname の組に対して、certificate を作製する。 旧 host では、apache モードを使ったが、 ssl 版の作り方が解ってしまえば、certonly モードの方が、使い易いようだ。

まず、certificate を取得する hostname 全てについて、アクセス可能な DocumentRoot を準備する。HTTP で公開する host については、既に設定がされている筈なので、 それをそのまま採用すれば良いが、そうでない hostname については、 以下のような 000-default.conf を作って:

<VirtualHost *:80>
        ServerName imap.otacky.jp
        ServerAlias smtp.otacky.jp
        ServerAdmin webmaster@localhost
        DocumentRoot /var/www/letsencrypt
        <Directory /var/www/letsencrypt>        
                 Options None
        </Directory>    

        ErrorLog ${APACHE_LOG_DIR}/error.log
        CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>

さらに

fukuda@digoc04:~% sudo a2ensite 000-default
fukuda@digoc04:~% sudo systemctl reload apache2

としておく。(/var/www/letsencrypt に (仮に) 空の index.html ファイルを置いて、他の server から % wget http://lists.otacky.jp/ 等として、 アクセスが可能であるである事を確認しておくと尚可。)

こうしておいて、certbot certonly コマンドで、certificate を作る。

fukuda@digoc04:~% sudo certbot certonly --webroot \
    -w /var/www/html -d www.otacky.jp -d otacky.jp \ 
    -w /var/www/letsencrypt -d smtp.otacky.jp -d lists.otacky.jp -d imap.otacky.jp
fukuda@digoc04:~% sudo certbot certificates
Saving debug log to /var/log/letsencrypt/letsencrypt.log

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Found the following certs:
  Certificate Name: www.otacky.jp
    Domains: www.otacky.jp imap.otacky.jp lists.otacky.jp otacky.jp smtp.otacky.jp
    Expiry Date: 2019-05-29 20:30:05+00:00 (VALID: 88 days)
    Certificate Path: /etc/letsencrypt/live/www.otacky.jp/fullchain.pem
    Private Key Path: /etc/letsencrypt/live/www.otacky.jp/privkey.pem
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

簡易チェックの稼働開始

それぞれのサーバの機能は、*.waremo.mine.nu であった時に、データも移して確認してあるので、今回問題になりそうなのは、 domain name (hostname) の変更と certificates 変更のみ。なので、 通常の「ページへアクセスをしてみる」「メールを送る/受けてみる」 などの機能チェックでは殆ど問題が出なかった。

ここまでのところで、otacky.jp サーバの移行は完了とする。


2019-02-20 (Wed): 宅外サーバ-2 (3: Mailman)

Mailman のインストールは予想どおり難航した。 しかし、その理由はこれまでのインストール自体の煩雑さ (厳格な file permission の設定が必要他) とは別に、Mailman を巡るあれこれが多様化している事もある:

この先、Mailman がいつまで必要とされるか解らないので、 あんまり頑張らずに、安全確実な「移行」を最優先しよう……と思ったけど、 3.x が、「Django ベース」である事を知って、 「これまで見てきたのと全く違う Django の Appli を触ってみるのも良いかな」 などというスケベ心がむくむくと……。で、ちょっと触ってみた。 案の定、「ちょっと」では済まなかったが、とにかく、 document を参考に、 (二三のモジュールを手でインストールしないといけなかったけど) 無事、 Django の runserver (devserver) で画面を表示できるところまで来た。

Mailman3
Devserver で表示させた Mailman 3 のトップページ

が、この先、mod-wsgi 経由で apache2 で公開する、とか、 既存の ML の archives をこの Mailman 3 に組込むとかなどは、 そもそも文書化されてないし、 自分でやるのは気が遠くなるくらい難しい気がして、結局断念することに!

で、結局は、-2.x に戻る事になったのだが、それでも何だか、Document に書いてある事がよく解らない。些かの cut & try の後、現行の Document 達が、上に書いた、二つの transport を明確に区別してないからではないか、 と思い始めた。Mailman 3 で凝りたのに、また、新しい方へ行こうとしたけど、 そっちでは、従来の list のアドレス (${listname}@otacky.jp) を引き継げない (${listname}@lists.otacky.jp とせざるを得ない) 事がわかり、 従来の alias_map オンリーで行く事にした。 (早く気がついて良かった :-p )

Mailman-2 をインストール・設定

上記の「問題」のせいで、従来一番信用できるとして来た Ubuntu の Server Guide/Mailman は、あまり参考にならなかった。 以下は、「alias_map を使う」という条件の下での、 最も単純明快な手順になっている (と思う)。

fukuda@digoc04:~% sudo apt install mailman    

これで config 画面が立ち上がり、default lang を選ばせるが、 terminal によっては、画面が乱れてうまく行かないかも知れない。 しかし、すぐ後 (下の #MM-3) で設定しなおせるので、無視して [OK] とする。

/etc/mailman/mm_cfg.py を編集して

from Defaults import *
MAILMAN_SITE_LIST = 'mailman'
DEFAULT_URL_PATTERN = 'http://%s/cgi-bin/mailman/'    #MM-1)
# DEFAULT_URL_PATTERN = 'http://%s/'
IMAGE_LOGOS         = '/images/mailman/'
DEFAULT_EMAIL_HOST = 'otacky.jp'                      #MM-2)
DEFAULT_URL_HOST   = 'lists.otacky.jp'
add_virtualhost(DEFAULT_URL_HOST, DEFAULT_EMAIL_HOST)
DEFAULT_SERVER_LANGUAGE = 'ja'                        #MM-3)
USE_ENVELOPE_SENDER    = 0              # Still used?
DEFAULT_SEND_REMINDERS = 0
MTA='Postfix'                                         #MM-4)

とする。comment 行は省いた。ここに

  1. #MM-1) 下の短かい方のパターンを勧める document もあるが、 ここは default のまま、とするべき。
  2. #MM-2) ${listname}@otacky.jp とするには、この組にしておくのが良い。
  3. #MM-3) 上の config pane で失敗しても、ここでこのように設定しておけば大丈夫。
  4. #MM-4) 全体のデフォルトが、transport を使うようになっているので これもデフォルトでは comment out されているが、alias_map を使うためには、 ここは MTA = 'Postfix' と明確に定義しておく事が必須。 [重要]

こうしておいて、最初の Mailing List として 'mailman' を作る。

fukuda@digoc04:~% sudo newlist mailman           
Enter the email of the person running the list: fukuda@otacky.jp
Initial mailman password: 
Hit enter to notify mailman owner...

上の #MM-4) が設定されていると、このように aliases が表示されず、代りに正しい場所に、aliases が作製される。 (sudo は必須。)

fukuda@digoc04:~% ls /var/lib/mailman/data -l 
total 36
-rw-rw-r-- 1 root list  1132 Feb  4 17:39 aliases
-rw-rw-r-- 1 list list 12288 Feb  4 17:39 aliases.db
-rw-rw-r-- 1 root list    10 Feb  4 15:32 last_mailman_version
.....

以降は、web 上で ML を作製・設定した方が早いが、 ここまでは必ずこの手順・設定に従って、'mailman' とその aliases がちゃんと作れている事を確認しておく事が重要。

Apache2 の設定

ここでは、http://lists.otacky.jp という url でアクセスできる、Mailman 専用の Virtual Host を作る事を目指す。

fukuda@digoc04:~% sudo cp /etc/mailman/apache.conf \
    /etc/apache2/sites-available/mailman.conf 

として、VH conf (mailman.conf) のデフォルトをコピーしてくる。 ただ、これには大幅な変更が必要。

<VirtualHost *:80>                                          #AP-1)
ServerName lists.otacky.jp                                  #AP-2)
DocumentRoot /var/www/lists                                 #AP-3)
ErrorLog /var/log/apache2/lists-error.log
CustomLog /var/log/apache2/lists-access.log combined
#
<Directory /var/lib/mailman/archives/>
    Options FollowSymLinks
    AllowOverride None
</Directory>
<Directory /usr/lib/cgi-bin/mailman/>
    AllowOverride None
    Options ExecCGI
    AddHandler cgi-script .cgi
    Require all granted
</Directory>
<Directory /var/lib/mailman/archives/public/>
    Options FollowSymlinks
    AllowOverride None
    Require all granted
</Directory>
<Directory /usr/share/images/mailman/>
    AllowOverride None
    Require all granted
</Directory>
#
Alias /pipermail/ /var/lib/mailman/archives/public/
Alias /images/mailman/ /usr/share/images/mailman/
ScriptAlias /cgi-bin/mailman/ /usr/lib/cgi-bin/mailman/     #AP-4)

# ScriptAlias /admin /usr/lib/cgi-bin/mailman/admin         #AP-5)
# ScriptAlias /admindb /usr/lib/cgi-bin/mailman/admindb
.....
# ScriptAlias /subscribe /usr/lib/cgi-bin/mailman/subscribe
# ScriptAlias /mailman/ /usr/lib/cgi-bin/mailman/

# ScriptAlias / /usr/lib/cgi-bin/mailman/listinfo  
ScriptAliasMatch /list.* /usr/lib/cgi-bin/mailman/listinfo  #AP-6)

</VirtualHost>
	  

ここに、

  1. #AP-1) <VirtualHost ...> と </VirtualHost> の間に全ての記述を入れる。
  2. #AP-2) これは必須。lists.... でなくても良いが、letsencrypt の認証取得に使うならば、実際に作製して www-data から書き込み可能にしておく必要がある。
  3. #AP-3) Mailman の中核である Python scripts への ScriptAlias.
  4. #AP-4) 上記の ScriptAlias にもかかわらず、URL として http://lists.otacky.jp/admin 等と書くための記述だが、ここでは全て comment out したままにしておく。(実際にこのような URL でアクセスする事は滅多にない。)
  5. #AP-5) ここを ScriptAlias / /usr/lib/cgi-bin/... のままにしておくと、/var/www/lists へアクセスする方法が無くなってしまう。Letsencrypt の certificates の取得・更新の際にそれでは困る。(HTTPS にしないなら、元のままで良い。)

ここまでで、

fukuda@digoc04:~% sudo systemctl reload apache2
fukuda@digoc04:~% sudo systemctl reload mailman

とやったあと、http://lists.otacky.jp/list へアクセスすれば、 Mailman のトップページが見える。

Postfix の設定

Mailman との結合は、alias_maps のみで行くと決めたので、変更すべき箇所は多くない。
fukuda@digoc04:~% postconf -n
alias_database = hash:/etc/aliases
alias_maps = hash:/etc/aliases hash:/var/lib/mailman/data/aliases     #PF-1)
....
smtpd_use_tls = yes
postconf: warning: /etc/postfix/main.cf: unused parameter: \          #PF-2)
    mailman_destination_recipient_limit=1

のように、alias_maps に mailman が作って更新する aliases を付け加えるだけ。 (#PF-1)

蛇足だが、Document の多くは、mailman transport を使う事を前提にしているので、 mailman_destination_recipient_limit=1 を付け加えろとしている。しかし、master.cf の最後の 3行を下のようにコメントアウトすると、

# mailman   unix  -       n       n       -       -       pipe                        
#  flags=FR user=list argv=/usr/lib/mailman/bin/postfix-to-mailman.py                 
#  ${nexthop} ${user}   

上の #PF-2 のように「この parameter は使ってないよ」という warning が出る。 mailman transport を使わないと決心しているなら、無視して良いが、 気になるなら、main.cf から、同パラメータを削除するか、 postfix-to-mailman.py のコメントアウトを止めれば良い。 (これが呼ばれる事はないので、何ら問題ない。)

パラメータ間の相互依存

ここまでの「設定」で、問題なく使える筈であるが、実は ScriptAlias がらみで、Web にログインしてからの操作がうまく行かない事があった。 またもや、mailman transport のためのデフォルトパラメータが邪魔をしていたのだった。 解決策は単純で、(mailman transport のための default 設定もしくはその勧めを全部無視して)

のように、

  1. 作製される MailList インスタンスのデフォルトの URL、
  2. URL として期待される ScriptAlias,
  3. MailList インスタンスの実際の URL

が一致していないといけない。 1. と 3. が一致しているのがあたり前のように思えるが、 既存の Archive から copy するような場合は違っている事もあるので注意が必要。

動作確認

以上までのインストール・設定を済ませると

fukuda@digoc04:~% sudo systemctl reload apache2

としてから、 http://lists.waremo.mine.nu にアクセスする事で、 以下のような top page が表示される。

Top Page of the Blank Mailman 2
できたばかりの Mailman 2 トップページ
(Mailman2 を新たに作った状態)

本当に最初の画面は、勿論 最初に newlist コマンドで作製した Mailman リストだけが表示される。もし、これも表示されなければ、 上の「パラメータの相互依存」の項の設定を確認する必要がある。 旨く表示された、さらに、まず、新規にリストが作れるかどうかを確認。上の図は、 うまく Mailman2 リストが作られている事を示している。

次に、リストにダミー会員 (他のホストにある自分のアドレス) を設定する。 (トップページから、[リスト管理一覧ページ] へ行き、そこで Mailman を選択、 さらに [会員管理] → [まとめて入会登録] で登録する。)

念のために、

fukuda@digoc04:~% sudo systemctl reload postfix
fukuda@digoc04:~% sudo systemctl reload mailman

としておいて、 mailman@waremo.mine.nu 宛に test message を送付、 各アドレスにメッセージが届いているか、また、「リストの保存書庫」に、 ちゃんと保存されているかを確認する。


2019-02-13 (Wed): 宅外サーバ-2 (2: Postfix + Dovecot)

Postfix の設定には hostname が陽に (陰にも?) 入ってくるので、 後々頭をかかえなくて良いように今のうちに hostname を変更しておく。
fukuda@digoc02b:~% sudo hostnamectl set-hostname digoc04
fukuda@digoc02b:~% zsh
fukuda@digoc04:~% sudo emacs /etc/hosts
fukuda@digoc04:~% cat /etc/hosts
# Your system has configured 'manage_etc_hosts' as True.
.....
# *1)
127.0.1.1 digoc04.waremo.mine.nu digoc04
127.0.0.1 localhost

# The following lines are desirable for IPv6 capable hosts
.....
  1. *1) この部分は手で編集する必要がある。あと、FQDN も必須ではないが、apache の起動の際の warning を押えてくれる。

テストの都合を考えて、今回は IMAP4 サーバ (Dovecot) の方からインストールする。

Dovecot

まず Maildir を作り、dovecot をインストール

fukuda@digoc04:~% mkdir Maildir
fukuda@digoc04:~% chmod 700 Maildir
fukuda@digoc04:~% sudo apt install dovecot-core dovecot-imapd
fukuda@digoc04:~% sudo ufw allow "Dovecot Secure IMAP" 

以上までできた、/etc/dovecot/conf.d/10-{auth,mail,master,ssl}.conf を変更して、結果として次のような設定パラメータとする。 (各箇所に、変更すべき conf ファイルを示す。)

fukuda@digoc04:~% doveconf -n 
# 2.2.33.2 (d6601f4ec): /etc/dovecot/dovecot.conf
# Pigeonhole version 0.4.21 (92477967)
# OS: Linux 4.15.0-45-generic x86_64 Ubuntu 18.04.1 LTS 
auth_mechanisms = plain login
#1) 10-mail.conf で変更
mail_location = maildir:~/Maildir
mail_privileged_group = mail
namespace inbox {
  inbox = yes
  location = 
  mailbox Drafts {
    special_use = \Drafts
  }
  mailbox Junk {
    special_use = \Junk
  }
  mailbox Sent {
    special_use = \Sent
  }
  mailbox "Sent Messages" {
    special_use = \Sent
  }
  mailbox Trash {
    special_use = \Trash
  }
  prefix = 
}
passdb {
  driver = pam
}
protocols = " imap"
#2) 10-master.conf で変更 (block 全体) 
service auth {
  unix_listener /var/spool/postfix/private/auth {
    group = postfix
    mode = 0666
    user = postfix
  }
}
#3) 10-ssl.conf で変更 (2 行)
ssl_cert = </etc/letsencrypt/live/waremo.mine.nu/fullchain.pem
ssl_key = </etc/letsencrypt/live/www.waremo.mine.nu/privkey.pem 
userdb {
driver = passwd
} 
fukuda@digoc04: sudo systemctl reload dovecot
	      

ここに

  1. #1) (mbox でなく) ~/Maildir 以下に、Maildir 形式でメッセージをセーブする。
  2. #2) Postfix に authentication 機能を供給する。Postfix 側では /etc/postfix/main.cf
       # /etc/postfix/main.cf
    smtpd_sasl_auth_enable = yes
    smtpd_sasl_path = private/auth
    smtpd_sasl_type = dovecot
    等として対応する。
  3. #3) 新たに取った certificate と private key でデフォルトのモノを置き換える。 (実際には doveconf -n では、private key へのパスは表示されない。)

macOS (falcon.otacky.us) からアクセスしてみて、手短に単体チェック:

fukuda@falcon:~% gnutls-cli -p 993 imap.waremo.mine.nu
Processed 135 CA certificate(s).
Resolving 'imap.waremo.mine.nu:993'...
Connecting to '128.199.161.24:993'...
- Certificate type: X.509
- Got a certificate list of 2 certificates.
- Certificate[0] info:
 - subject `CN=www.waremo.mine.nu', \
    issuer `CN=Let's Encrypt Authority X3,O=Let's Encrypt,C=US', ....., \
    activated `2019-01-01 00:55:49 UTC', expires `2019-04-01 00:55:49 UTC', .....
	Public Key ID:
		sha1:50d585e793caeab497404b1ee298503a989aed16
		sha256:e567cf7c9a4e35f6c3008b1f228acb4a0eaf7a37f59e00d61.....
	Public Key PIN:
		pin-sha256:5WfPfJpONfbDAIsfIorLSg6vejf1ngDWFKYjkYmu3Nw=
	Public key's random art:
		+--[ RSA 2048]----+
		|        .... o.  |
		|      ..    o .  |
		|   o o.      o . |
		|  o +  .. +   +  |
		| +   o +S= + . . |
		|o E   o . + o    |
		| . .      .o .   |
		|  o      ...o    |
		| .       .o.     |
		+-----------------+

- Certificate[1] info:
 - subject `CN=Let's Encrypt Authority X3,O=Let's Encrypt,C=US', \
    issuer `CN=DST Root CA X3,O=Digital Signature Trust Co.', ....., \
    activated `2016-03-17 16:40:46 UTC', expires `2021-03-17 16:40:46 UTC', 
- Status: The certificate is trusted. 
- Description: (TLS1.2)-(ECDHE-RSA-SECP384R1)-(AES-256-GCM)
- Session ID: 6A:E1:C5:26:25:26:2F:92:67:90:D1:75:D2:01:33:C0:74:95:04:.....
- Ephemeral EC Diffie-Hellman parameters
 - Using curve: SECP384R1
 - Curve size: 384 bits
- Version: TLS1.2
- Key Exchange: ECDHE-RSA
- Server Signature: RSA-SHA256
- Cipher: AES-256-GCM
- MAC: AEAD
- Compression: NULL
- Options: extended master secret, safe renegotiation,
- Handshake was completed

- Simple Client Mode:

* OK [CAPABILITY IMAP4rev1 LITERAL+ SASL-IR LOGIN-REFERRALS ID ENABLE \
    IDLE AUTH=PLAIN AUTH=LOGIN] \
    Dovecot (Ubuntu) ready.
a002 login fukuda password
a002 OK [CAPABILITY IMAP4rev1 LITERAL+ SASL-IR LOGIN-REFERRALS ID ENABLE \
     IDLE SORT .....] Logged in
a003 select inbox
* FLAGS (\Answered \Flagged \Deleted \Seen \Draft unknown-0 $Forwarded .....)
.....
	      

とりあえず、port 993 への、IMAPS アクセスに成功している。

また同 falcon 上の EmacsMac.app の Wanderlust からも、~/.folders に:

# ~/.folders
%inbox:fukuda@imap.waremo.mine.nu

として、~/.wl に:

(setq elmo-imap4-default-authenticate-type 'clear
       elmo-imap4-default-stream-type 'ssl
       elmo-imap4-default-port '993)

として、EmacsMac.app の Wanderlust から imap.waremo.mine.nu:~/Maildir にアクセスできた。

Postfix

次いで、postfix をインストール

fukuda@digoc04:~% apt install postfix procmail

で、次のような package configration pane が開くので、general type としては 'Internet Site', 次ページの System Mail Name は、'waremo.mine.nu' を入力する。(後者は説明がよく解らないし、 与えられるデフォルトが hostname で FQDN になってないけど、 ここは、ちゃんと digoc04.waremo.mine.nu とした方が良い。

Postfix Config Pane
Postfix インストール時の config pane

この結果として設定される main.cf は殆んど触るところがないくらい。 以下にその一部を加えた改変部分へのノート ('#*n)')と一緒に示す。

fukuda@digoc04:~% postconf -n
alias_database = hash:/etc/aliases
alias_maps = hash:/etc/aliases
append_dot_mydomain = no
biff = no
compatibility_level = 2
inet_interfaces = all
inet_protocols = all
mailbox_command = procmail -a "$EXTENSION"   #1)
mailbox_size_limit = 0
mydestination = $myhostname, beaverr.otacky.us, beaver, localhost.localdomain, localhost
myhostname = digoc04.waremo.mine.nu          #2)
mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128
myorigin = /etc/mailname
readme_directory = no
recipient_delimiter = +
relayhost =
#3)
smtp_tls_CAfile = /etc/ssl/certs/ca-certificates.crt
smtp_tls_loglevel = 1
smtp_tls_security_level = may
smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache
smtpd_banner = $myhostname ESMTP $mail_name (Ubuntu)
smtpd_relay_restrictions = permit_mynetworks permit_sasl_authenticated \
    defer_unauth_destination    #4)
#5)
smtpd_sasl_auth_enable = yes
smtpd_sasl_path = private/auth
smtpd_sasl_type = dovecot
#6)
smtpd_tls_cert_file = /etc/letsencrypt/live/www.otacky.jp/fullchain.pem
smtpd_tls_key_file = /etc/letsencrypt/live/www.otacky.jp/privkey.pem
smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache
smtpd_use_tls = yes

ここに、

  1. #1) procmail を一緒にインストールすれば、 これがデフォルトとなるように見えるが、確かではない。いずれにせよ、 このように設定しておく。
  2. #2) 上記の '# dpkg-reconfigure postfix' で設定した値がここ (と /etc/mailname) に入る。 これから他のパラメータが作られるので、厳密に hostname を含む FQDN になっている必要がある。
  3. #3) ここからの 3 行が、Postfix の smtp ブロック (つまりは送信部) の TLS 関連の振舞を決める。
  4. #4) 入力されたメッセージを、 (relayhost へではなく) 一般の SMTP サーバへリレーする際の制限を記述。 'permit_sasl_authentication' が重要
  5. #5) 以下の 3 行で、上の sasl_authentication のやり方を既定。 dovecot の SASL を使う。(Cyrus SASL は難し過ぎる……)
  6. #6) _cert_file, _key_file には snakeoil 等がデフォルトが 入っているが、先に要れた letsencrypt の cert と private-key を指定する。
Procmail を設定する。その rc file ~/.procmailrc は digoc02b では既にかなり長大なものになっているが、 試験のためには適切ではないので、振り分けとか、spam filter 関連のところは無視して、以下のようなものを作る:
# ~/.procmailrc
MAILDIR=$HOME/Maildir/
DEFAULT=$HOME/Maildir/
LOGFILE=$HOME/procmail.log
DELIVER="/usr/lib/dovecot/deliver"

以上までで、メール受信、送信、配送の全てが TLS を用いてできる筈なので、 簡単に試験してみる。 (以降の試験結果は、hostname を digoc04.otacky.jp と変更してからのもので置き換えた。)

Dovecot + Postfix の動作確認

Local 送受信

fukuda@digoc04:~% sendmail fukuda@localhost    
From: fukuda@localhost
To: fukuda@localhost
Subject: local delivery
test
test
.
fukuda@digoc04:~% sudo tail /var/log/mail.log
.....
Feb 14 15:35:53 digoc04 postfix/pickup[19021]: 4AF5D17B493: uid=1000 from=<fukuda>
Feb 14 15:35:53 digoc04 postfix/cleanup[19825]: 4AF5D17B493: 
    message-id=<20190214063553.4AF5D17B493@digoc04.otacky.jp>
Feb 14 15:35:53 digoc04 postfix/qmgr[21193]: 4AF5D17B493: 
    from=<fukuda@otacky.jp>, size=306, nrcpt=1 (queue active)
Feb 14 15:35:53 digoc04 postfix/local[19827]: 4AF5D17B493: 
    to=<fukuda@localhost>, relay=local, delay=29, delays=29/0.01/0/0.01, 
    dsn=2.0.0, status=sent (delivered to command: procmail -a "$EXTENSION")

Postfix の内部で、pickup -> cleanup -> qmgr -> local と転送されて、 最後に procmail に渡されている。

fukuda@digoc04:~% lv procmail.log
From fukuda@otacky.jp  Thu Feb 14 15:35:53 2019
 Subject: local delivery
  Folder: /home/fukuda/Maildir/new/1550126153.19829_0.digoc04               391

fukuda@digoc04:~% ls Maildir/new -lt
total 2360
-rw------- 1 fukuda fukuda    391 Feb 14 15:35 1550126153.19829_0.digoc04
		

Procmail は message を ~/Maildir/new/ にセーブした。

Mail System, path 1 & 2
Fig-1, メールシステム内の転送経路概念図 (1)
(Path-1: Local to Local, Path-2: Local to Cloud)

Local から Mail Server (gmail.com)へ

同様に message を作り、今度は外部の mail server へ送信。

fukuda@digoc04:~% sendmail fukudataka@gmail.com
From: fukuda@otacky.jp
To: fukudataka@gmail.com
Subject: test from otacky.jp to gmail.com
test
test
.
fukuda@digoc04:~% sudo tail /var/log/mail.log  
Feb 14 15:42:09 digoc04 postfix/pickup[19021]: 9E9F517B493: uid=1000 from=<fukuda>

Feb 14 15:42:09 digoc04 postfix/cleanup[19884]: 9E9F517B493: 
    message-id=<20190214064209.9E9F517B493@digoc04.otacky.jp>

Feb 14 15:42:09 digoc04 postfix/qmgr[21193]: 9E9F517B493: 
    from=<fukuda@otacky.jp>, size=328, nrcpt=1 (queue active)

Feb 14 15:42:10 digoc04 postfix/smtp[19892]:  Trusted TLS connection
    established to gmail-smtp-in.l.google.com [74.125.200.27]:25:  
		  TLSv1.2 with cipher ECDHE-RSA-CHACHA20-POLY1305 (256/256 bits)

Feb 14 15:42:11 digoc04 postfix/smtp[19892]: 9E9F517B493: 
    to=<fukudataka@gmail.com>, relay=gmail-smtp-in.l.google.com[74.125.200.27]:25, 
    delay=86, delays=84/0.02/0.69/1.2, dsn=2.0.0, status=sent 
    (250 2.0.0 OK  1550126531 k62si1614897pfc.208 - gsmtp)

Feb 14 15:42:11 digoc04 postfix/qmgr[21193]: 9E9F517B493: removed
		
pickup -> qmgr までは上記と同じだが、外部へは smtp を使う。 (Fig-1 の Path-2 にあたる。) この時、Trusted TLS connection を張る。これは、相手方の 25 ポートに アクセスして STARTTLS で、TLS-1.2 で接続を確立し、 しかも、相手先の certificate を自分の CAfile で認証している、という事 (?)

外部サーバからのメッセージを受信

外部サーバとして、自宅サーバ (beaver.otacky.us) を使い、 otacky.jp へメッセージを送る。このサーバの Postfix を smtp_tls_security_level = may (相手が対応していれば、 STARTTLS を使う) と設定しておくと
fukuda@beaver:~% postconf -n | grep smtp_tls
smtp_tls_CAfile = /etc/ssl/certs/ca-certificates.crt
smtp_tls_loglevel = 1
smtp_tls_security_level = may
smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache
fukuda@beaver:~% sendmail fukuda@otacky.jp
From: fukuda@beaver.otacky.us
To: fukuda@otacky.jp
Subject: Second Trial 
.....
fukuda@beaver:~% tail -f /var/log/mail.log
Feb 16 07:15:56 beaver postfix/pickup[14495]: D472A4569A: uid=1000 from=<fukuda>

Feb 16 07:15:56 beaver postfix/cleanup[14712]: D472A4569A: 
    message-id=<20190215221556.D472A4569A@beaver.otacky.us>

Feb 16 07:15:56 beaver postfix/qmgr[1259]: D472A4569A: 
    from=<fukuda@beaverr.otacky.us>, size=342, nrcpt=1 (queue active)

Feb 16 07:15:57 beaver postfix/smtp[14714]: 
    Anonymous TLS connection established to otacky.jp[128.199.161.24]:25: 
    TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)

Feb 16 07:15:58 beaver postfix/smtp[14714]: D472A4569A: 
    to=<fukuda@otacky.jp>, relay=otacky.jp[128.199.161.24]:25, 
    delay=70, delays=69/0.02/1.2/0.17, dsn=2.0.0, status=sent 
    (250 2.0.0 Ok: queued as 1B50817B492) 

この時、digoc04 の Postfix の smtpd は次のように応答・対応する。 (STARTTLS に応じている。)

fukuda@digoc04:~% sudo tail /var/log/mail.log  
Feb 16 07:15:57 digoc04 postfix/smtpd[20457]: connect from ... [116.58.186.101]

Feb 16 07:15:57 digoc04 postfix/smtpd[20457]: 
    Anonymous TLS connection established from ....[116.58.186.101]: 
    TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)

Feb 16 07:15:58 digoc04 postfix/smtpd[20457]: 1B50817B492: client=...[116.58.186.101]

Feb 16 07:15:58 digoc04 postfix/cleanup[20467]: 1B50817B492: message-id=<....@beaver.otacky.us>

Feb 16 07:15:58 digoc04 postfix/qmgr[20725]: 1B50817B492: 
    from=<fukuda@beaverr.otacky.us>, size=548, nrcpt=1 (queue active)

Feb 16 07:15:58 digoc04 postfix/local[20468]: 1B50817B492: to=<fukuda@otacky.jp>, 
    relay=local, delay=0.1, delays=0.09/0.01/0/0.01, dsn=2.0.0, 
    status=sent (delivered to comm and: procmail -a "$EXTENSION")

Feb 16 07:15:58 digoc04 postfix/qmgr[20725]: 1B50817B492: removed

Feb 16 07:15:58 digoc04 postfix/smtpd[20457]: disconnect from ...[116.58.186.101] 
    ehlo=2 starttls=1 mail=1 rcpt=1 data=1 quit=1 commands=7F
....
		

この時、sender (beaver) の側で、 smtp_tls_security_level = (none)(STARTTLS を disable) としておくと、つまり

fukuda@beaver:~% postconf -n | grep smtp_tls           
smtp_tls_CAfile = /etc/ssl/certs/ca-certificates.crt
smtp_tls_loglevel = 1
smtp_tls_security_level =
smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache

となっていれば、sender のログは

fukuda@beaver:~% sendmail fukuda@otacky.jp             
From: fukuda@beaver.otacky.us
To: fukuda@otacky.jp
Subject: test with smtp_tls_security_level = (blank)
.....
fukuda@beaver:~% tail -f /var/log/mail.log
.....
Feb 16 07:49:39 beaver postfix/pickup[14848]: A07724569A: 
    uid=1000 from=<fukuda>

Feb 16 07:49:39 beaver postfix/cleanup[14853]: A07724569A: 
    message-id=<20190215224939.A07724569A@beaver.otacky.us>

Feb 16 07:49:39 beaver postfix/qmgr[14847]: A07724569A: 
    from=<fukuda@beaverr.otacky.us>, size=344, nrcpt=1 (queue active)

Feb 16 07:49:40 beaver postfix/smtp[14855]: A07724569A: 
    to=<fukuda@otacky.jp>, relay=otacky.jp[128.199.161.24]:25, 
    delay=64, delays=63/0.01/0.56/0.18, dsn=2.0.0, 
    status=sent (250 2.0.0 Ok: queued as 4ADDC17B492)
.....
		

のように、Port 25 に通常の SMTP で転送される。受信側の Postfix も

fukuda@digoc04:~% sudo tail /var/log/mail.log
.....
Feb 14 16:20:17 digoc04 postfix/smtpd[20238]: connect from .....[116.58.186.101]

Feb 14 16:20:18 digoc04 postfix/smtpd[20238]: 5ED9517A95A: .....[116.58.186.101]

Feb 14 16:20:18 digoc04 postfix/cleanup[20243]: 5ED9517A95A: 
    message-id=<20190214072015.A017E4569B@beaver.otacky.us>
.....

のように報告されている (TLS は使っていない。) この両方の場合、次の図に Path-3 で示される経路を転送される。

Mail System, path 3 & 4
Fig-2, メールシステム内の転送経路概念図 (2)
(Path-3: Internet to Local, Path-4: SMTP Posting Server)

SMTP Posting Server として

自分が Cloud の任意のサーバにメールを送る時、digoc04 を Posting Server として使う訳だが、その時最も重要な「仕様」は、「スパマーの踏み台にされない」事。 要は、自分のホスト以外からの relay は一切拒否する、という事。これを実現するため、 「Submission Port (587) から TLS connection を確立し SASL login に成功したユーザからのみ、転送を受け付ける」を実現する。

Postfix の smtpd 関連の設定パラメータ

fukuda@digoc04:~% postconf -n | grep smtpd_   
smtpd_banner = $myhostname ESMTP $mail_name (Ubuntu)
smtpd_relay_restrictions = permit_mynetworks permit_sasl_authenticated defer_unauth_destination
smtpd_sasl_auth_enable = yes
smtpd_sasl_path = private/auth
smtpd_sasl_type = dovecot
smtpd_tls_cert_file = /etc/letsencrypt/live/www.otacky.jp/fullchain.pem
smtpd_tls_key_file = /etc/letsencrypt/live/www.otacky.jp/privkey.pem
smtpd_tls_loglevel = 1
smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache
smtpd_use_tls = yes

のうち、特に smtpd_relay_restrictions = permit_mynetworks permit_sasl_authenticated defer_unauth_destination が重要であるように見える。

このように設定された digoc04 の Postfix に対して、gnutlis-cli を使って、メールを fukudataka@gmail.com への relay を試みる。 (青い字で書かれているのが、入力文字列。)

fukuda@falcon:~% gnutls-cli --starttls -p 587 smtp.otacky.jp 
Processed 135 CA certificate(s).
Resolving 'smtp.otacky.jp:587'...
Connecting to '128.199.161.24:587'...

- Simple Client Mode:

220 digoc04.otacky.jp ESMTP Postfix (Ubuntu)
		  ehlo smtp.otacky.jp
250-digoc04.otacky.jp
250-PIPELINING
250-SIZE 10240000
250-VRFY
250-ETRN
250-STARTTLS
250-AUTH PLAIN LOGIN
250-AUTH=PLAIN LOGIN
250-ENHANCEDSTATUSCODES
250-8BITMIME
250-DSN
250 SMTPUTF8
		  starttls
220 2.0.0 Ready to start TLS
		  Ctrl-D
*** Starting TLS handshake
- Certificate type: X.509
- Got a certificate list of 2 certificates.
- Certificate[0] info:
 - subject `CN=www.otacky.jp', \
           issuer `CN=Let's Encrypt Authority X3,O=Let's Encrypt,C=US', .....
	Public Key ID:
		sha1:b617fd6ab597a34f197345074955fc0c4d0b269e
		sha256:bed0d5fa1a3612609badcc3701e3d9d23a0733d82ebe.....
	Public Key PIN:
		pin-sha256:vtDV+ho2EmCbrcw3AePZ0joHM9guvhnj1N1SqjcVl74=
- Certificate[1] info:
 - subject `CN=Let's Encrypt Authority X3,O=Let's Encrypt,C=US', 
    issuer `CN=DST Root CA X3,O=Digital Signature Trust Co.', .....
- Status: The certificate is trusted. 
- Description: (TLS1.2)-(ECDHE-SECP256R1)-(RSA-SHA256)-(AES-256-GCM)
- Session ID: F5:C7:42:70:49:3D:C2:05:FA:77:AF:50:F6:8E:B9:B3:F2:.....
- Options: extended master secret, safe renegotiation,
		  auth plain AGZ1a3VkYxxxxxxxSZIYQ==
235 2.7.0 Authentication successful
		  mail from: fukuda@beaver.otacky.us
250 2.1.0 Ok
		  rcpt to: fukudataka@gmail.com
250 2.1.5 Ok
		  data
354 End data with <CR><LF>.<CR><LF>
		  From: fukuda@beaver.otacky.us
		    To: fukudataka@gmail.com
		    OK, go and hit the server!
		    .
250 2.0.0 Ok: queued as 19CF317B492
		  quit
221 2.0.0 Bye
- Peer has closed the GnuTLS connection

この間の、digoc04 側の log は以下のようになっている。

fukuda@digoc04:~% sudo lv /var/log/mail.log
Feb 16 11:59:08 digoc04 postfix/smtpd[23805]: connect from .....[116.58.186.101]

Feb 16 12:02:04 digoc04 postfix/smtpd[23805]: Anonymous TLS connection established 
    from .....[116.58.186.101]: TLSv1.2 with cipher 
    ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)

Feb 16 12:07:57 digoc04 postfix/smtpd[23805]: 19CF317B492: client= .....[116.58.186.101], 
    sasl_method=plain, sasl_username=fukuda

Feb 16 12:09:19 digoc04 postfix/cleanup[23914]: 19CF317B492: message-id=<>

Feb 16 12:09:19 digoc04 postfix/qmgr[20725]: 19CF317B492: from=<fukuda@beaver.otacky.us>, 
    size=311, nrcpt=1 (queue active)

Feb 16 12:09:19 digoc04 postfix/smtp[23929]: Trusted TLS connection established 
    to gmail-smtp-in.l.google.com[74.125.24.27]:25: TLSv1.2 
    with cipher ECDHE-RSA-CHACHA20-POLY1305 (256/256 bits)

Feb 16 12:09:20 digoc04 postfix/smtp[23929]: 19CF317B492: 
    to=<fukudataka@gmail.com>, relay=gmail-smtp-in.l.google.com[74.125.24.27]:25,
    delay=99, delays=97/0.02/0.67/0.88, dsn=2.0.0, status=sent 
    (250 2.0.0 OK  1550286560 f21si6714164pgb.371 - gsmtp)

Feb 16 12:09:20 digoc04 postfix/qmgr[20725]: 19CF317B492: removed

つまり、

という動作をしている。(Fig-2 の Path-4 に対応。)


2019-02-06 (Wed): 宅外サーバ-2 (1: Ubuntu-18.04 + Cetificates)

去年の 11 月に DigitalOcean の新 droplet (digoc03) に、waremo.com を domain name として持つサービス ( <http://dms.waremo.com>, <http://www.waremo.com>) を移した。その後順調に動いているようだ。

その後、{www,lists,imap,smtp}.otacky.jp 等のサービスも digoc03 へ順次移して行く予定だったが、ちょっと気が変わった。 やってみたら「一つのサイトに一つの FQDN」というのが、 なかなか心地良いので、態々「統合」する事もないかな、というのが一つ。 もう一つは、Ubuntu-18.04 LTS のサポート期間が 5 年から 10 年に述びた事。 otacky.jp には、比較的「静的」なウェブサイトと、mail system が主なので (どちらも、この先ドラスティックな発展・変更はないだろうと踏んで)、 後 10 年はさほど手間暇を掛けずに使い続けてやろうという魂胆。

基本構成

waremo.com 関連のサービスは、既に digoc03 に移したので、 digoc02b には、otacky.jp 関連のウェブサイト (http://www.otacky.jp 他) のための HTTP サーバ と、メールサーバ (SMTP サーバ、IMAP サーバ、ML サーバ) を乗せる。

これらのサーバは、相互に強く依存しているため、 要求定義を再確認する事から始める。

Mail System Configuration
宅外サーバ 2 のメールシステムの概要
(click で拡大)

作業手順概要

概略の手順は以下の通り。最初の目論見というより、四苦八苦の結果に近いかも。

  1. 新 droplet を digoc02b として立ち上げる。 その FQDN を waremo.mine.nu とする。すなわち、与えられた IP address を DynDNS の waremo.mine.nu の A record に設定。
  2. 上述のサーバ達をインストール
  3. インストールした apache を使って letsencrypt から certificates を取得
  4. apache2 を設定し、var/www 以下を仮に rsync して動作確認。
  5. postfix, dovecot 等を順次設定し、~/Maildir を rsync して動作確認
  6. Mailman を設定、仮の ML mailman を作って動作確認
  7. digoc02: otacky.jp, digoc02b: waremo.mine.nu の certificates を revoke
  8. DynDNS の設定を変更して、digoc02: waremo.mine.nu, digoc02b: otacky.jp とし、それぞれで、certificates を取得
  9. 再度 ~/Maildir, /var/www/ を sync
  10. FQDN の変更に合わせて、apache2, postfix, dovecot, mailman の設定を変更
  11. それぞれの動作を確認

上記の 7. までは、digoc02 が otacky.jp として動作しているので、digoc02b での作業はノンビリで良いが、8. 以降は、otacky.jp の動作を一旦停止させている事になるので、そうは行かない……。

DigitalOcean で新サーバ (droplet) を立ち上げる

Digoc03 と全く同じ仕様 (4 GB / 80 GB, /SGP1, Ubuntu-18.04) の新 droplet に digoc02b と名前をつけて立ち上げる。

詳細は、2018-10-31 のオタク日記 (「宅外サーバ (その 1)」) を参照の事。

digoc02b on DigitalOcean
新 droplet, digoc02b

但し、

CPU/Network 性能比較
Droplet linalg.inv()
(ms)
fft.fft2()
(ms)
Transfer Rate
(Mbps)
Turnaround Time
(ms)
digoc02145 8231179.6 ± 1.5
digoc0392.7 60.3 113979.5 ± 2.0
digoc04146 61.3115279.7 ± 2.4
digoc02b142 83105676.1 ± 0.3

digoc02 からdigoc04 については先の日記の table のものを流用しているが、 digoc02b については、今回新たに作った droplet で実測したもの。 何故か、digoc03 だけが格段に速かったようで、 ちょっとがっかり。(digoc02b は何度かリブートして再測定しても、 似たような結果だった——たまたま、ショボイ H/W を掴んだ、 という事でも無さそうだ。ちょっと悲しい。)

Apache とそれによる Certificate 取得

これについても、digoc03 の時の記録 ( 宅外サーバ (その 1), 宅外サーバ (その 2), 宅外サーバ (その 3)) を殆んどそのまま実行した。Certificate 取得の部分だけ再掲すると……

fukuda@digoc02b:~% cat /etc/apache2/sites-available/000-default.conf
<VirtualHost *:80>
  # .....
  ServerAlias www.waremo.mine.nu
  ServerAlias imap.waremo.mine.nu
  ServerAlias smtp.waremo.mine.nu

  ServerAdmin webmaster@localhost
  DocumentRoot /var/www/html
  #.....
  ErrorLog ${APACHE_LOG_DIR}/error.log
  CustomLog ${APACHE_LOG_DIR}/access.log combined
  #.....
</VirtualHost>
fukuda@digoc02b:~% sudo a2ensite 000-default
fukuda@digoc02b:~% sudo systemctl reload apache2
fukuda@digoc02b:~% sudo add-apt-repository ppa:certbot/certbot
fukuda@digoc02b:~% sudo apt install python3-certbot-apache
fukuda@digoc02b:~% certbot --version                          
 certbot 0.28.0
fukuda@digoc02b:~% sudo certbot --apache -d www.waremo.mine.nu \
    -d imap.waremo.mine.nu -d smtp.waremo.mine.nu 

ここまでで、private (certificate) key と certificate が取得できている。 --apache option をつけているので、000-default.conf の SSL sites も以下のように作製されており、これから、作製された private key や certificate の在処も解る。

fukuda@digoc02b:~% cat /etc/apache2/sites-available/000-default-le-ssl.conf 
<IfModule mod_ssl.c>
  <VirtualHost *:443>
    # .....
    ServerAlias www.waremo.mine.nu
    ServerAlias imap.waremo.mine.nu
    ServerAlias smtp.waremo.mine.nu

    ServerAdmin webmaster@localhost
    DocumentRoot /var/www/html

    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined

    Include /etc/letsencrypt/options-ssl-apache.conf
    SSLCertificateFile /etc/letsencrypt/live/www.waremo.mine.nu/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/www.waremo.mine.nu/privkey.pem
  </VirtualHost>
</IfModule>
		

ここまでで、仮の URL (xxxx.waremo.mine.nu) の certificate が設定できて、https://www.waremo.mine.nu へのアクセスが可能になった。 しかし、これは既に waremo.com で実現済みなので、本当の狙いは SMTP サーバや、IMAP サーバの SSL/TLS 接続に certificate を適用する設定をして動作確認をする事。

その後、otacky.jp に変更する。


149/1,729,048 Valid CSS! Valid HTML 5.0
Taka Fukuda
Last modified: 2019-03-26 (Tue) 15:14:34 JST