Z-PushがPHP7に対応したっぽい

Z-Push

Z-Push はオープンソースの Exchange ActiveSync。
個人でメールサーバをやると大抵は POP3 や IMAP4 になるけど POP3/IMAP4 には基本的にはメールサーバにメールが届いた時にそれをメールボックスのオーナーに知らせることができない。 IMAP4 には IMAP_IDLE があるじゃんというのはあるけど、ここではこの記事を成立せさるために口を瞑って欲しい。

個人運営のメールサーバで Push で通知を受ける(送る)方法が欲しいよねってときに意外と選択肢が無い。 ActiveSync というものがあるけどそれを使うのは色んな意味で昔は凄く大変だったというのは話としては聞いている。そんな時(何年も前だが)にひょこっと登場したのが Z-Push 。 IMAP サーバ(他)と PHP が動くウェブサーバがあれば(運が良ければ)簡単に ActiveSync できちゃうというなかなか画期的なもの。

ただし、登場した頃から基本的なインストール自体は簡単なもののまともに動くようになるまでが一苦労。それは8,9年たった現在も全く変わらない。運が良ければというのは自分のサーバー構成とそっくり同じな情報がインターネットのブログ/掲示板で見つけられればということ。そうでないと、そんなに膨大な設定があるわけでもないのに何故かなかなか上手くいかない。

そして、Z-Pushで困っていたのがPHP7登場からこれまで非対応状態が続いていたこと。PHP7対応リクエストはもちろんずっと出ていたし、プロジェクト側もPHP7に対応したいとは言い続けていた。でも、なかなか対応が進まなかったみたい。むしろ、「PHP7では動かないよ」メッセージが出るようにしてお茶を濁してた。一応有志によるパッチのようなものも出てはいたけど、なんかよく解らなくて「これだ!」って感じにはならなかった。
それがようやくVersion 2.3.4でPHP7に対応してきた。ただし、Ver.2.3.4は12月中旬現在ではまだβ1の状態。一応PHP7非対応のエラーが出まくるというのは無いみたいだけど、完全な動作までは期待しない方が良いかも。

インストール & 設定

Z-Pushのアーカイブを展開して /usr/local/www/z-push に置くとする。(この記事でのディレクトリ/ファイルの配置はFreeBSDの流儀なのでLinuxなどはその流儀で読み替える)
ログ用のディレクトリ /var/log/z-push と StateMachines 用のディレクトリ /var/spool/z-push を作成する。
# mkdir /var/log/z-push
# chown www:www /var/log/z-push
# mkdir /var/spool/z-push
# chown www:www /var/spool/z-push

ベースの設定ファイル /usr/local/www/z-push/config.php を編集する。(下は変更行のみ)

1
2
3
4
5
6
7
define('TIMEZONE', 'Asia/Tokyo');             //日本ならこれ
define('STATE_DIR', '/var/spool/z-push/');   //先に作ったディレクトリ
define('LOGLEVEL', LOGLEVEL_DEBUG);           //最初はデバッグログ要るよね
define('LOGAUTHFAIL', true);                  //最初は認証エラーも見るよね
define('PROVISIONING', false);                //クライアントに対して融通するならtrueだが端末がサーバに接続できないことになること多々
define('LOOSE_PROVISIONING', true);           //古いAndroidなどに対応するならtrue
define('BACKEND_PROVIDER', 'BackendIMAP');   //IMAPと連携(この記事の前提)

2017年11月13日修正:
設定例としてPROVISIONINGの値をtrueで書いていたが、端末からサーバへの接続が失敗することが多いようなのでfalseにしておいた。もちろんtrueの方が良い場合もあるはず。

IMAPとの連携用設定ファイル /usr/local/www/z-push/backend/imap/config.php を編集する。(下は変更行のみ)

1
2
3
4
5
6
define('IMAP_SERVER', 'mx.example.com');         //IMAPサーバのIPアドレスかホスト名
define('IMAP_PORT', 993);                        //IMAPサーバのポート番号
define('IMAP_OPTIONS', '/ssl/novalidate-cert');  //IMAPサーバとの接続オプション
define('IMAP_FOLDER_CONFIGURED', true);          //設定したよフラグなので必ずtrueに変更
define('IMAP_SMTP_METHOD', 'smtp');              //メール送信にSMTPサーバを使うなら
$imap_smtp_params = array('host' => 'ssl://localhost', 'port' => 465, 'auth' => true, 'username' => 'imap_username', 'password' => 'imap_password');  //SMTP送信をSSLでやるなら
Nginxの設定
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
server {
  listen 443 default_server ssl http2;
  listen [::]:443 default_server ssl http2;
  server_name mx.example.com;

  ssl_certificate     /usr/local/etc/nginx/ssl/server.crt;
  ssl_certificate_key /usr/local/etc/nginx/ssl/server.key;
  ssl_dhparam         /usr/local/etc/nginx/ssl/dhparams.pem;
  ssl_protocols       TLSv1.2 TLSv1.1 TLSv1;
  ssl_ciphers         EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4;
  ssl_prefer_server_ciphers   on;

  location / {
    root /usr/local/www/mx_example_com;
    index index.html;
  }

  location /Microsoft-Server-ActiveSync {
    root /usr/local/www/z-push/;

    fastcgi_connect_timeout 600;
    fastcgi_send_timeout    600;
    fastcgi_read_timeout    600;
    fastcgi_pass   unix:/var/run/php-fpm.sock;
    include        fastcgi_params;
    fastcgi_param  SCRIPT_FILENAME $document_root/index.php;
    fastcgi_param  SCRIPT_NAME     $fastcgi_script_name;
    fastcgi_param  HTTPS on;
  }
}

設定が済んだらNginxの設定再読込み。

# service nginx reload

確認

ブラウザでZ-Pushが動くサーバのFQDNに /Microsoft-Server-ActiveSync を付けてURL指定。
例: https://mx.example.com/Microsoft-Server-ActiveSync

Z-Push 認証
認証小窓がポップアップで出現するので実在するIMAPユーザーのアカウントとパスワードを入力。
認証小窓がポップアップしないならウェブサーバの設定が不適切かも。
ここで認証が通らなければIMAPサーバとの連携がうまく行っていないと思われる。

Z-Push ウェブ表示
認証後にこの画面が表示されれば取り敢えずは動いているといえる。
あとは ActiveSync 対応のメーラー(MUA)でこのサーバ(mx.example.com)に接続し、アカウントとパスワードは1つ上の画像で認証出来たものを使用してメールの送受信が出来ることを確認。そのメールアドレス宛にメールを送信してメール着信通知が届くか確認。

ただし、1発でサクッと成功することはなかなか無いかと。
Z-Push やウェブサーバの設定だけでなく Z-Push のソースにも手を入れる必要がある場合もある。

取り敢えず「がとらぼ」の中の人の環境では上のような感じでやると Android の Gmail アプリと Exchange(ActiveSync)アカウントで初回の接続は成功してメールを取得し、そのメールを読むこともできるが、次の同期時に同期が終わらなくなってしまう

Androidで同期1
AndroidでExchangeアカウント作成直後はそのアカウントの「カレンダー」と「連絡先」のスイッチがオンになっているので必ず同期失敗になる。「Androidの設定」→「アカウント」→「Exchange」「作成したExchange ActiveSyncのアカウント」をクリックして「カレンダー」と「連絡先」をオフに変更する。

Androidで同期2
メールの同期が失敗したら同期のスイッチをオフにしてもう一度オンに戻す。これで同期できる。
同期異常・メールを読み込み中で停止する状態が発生したら毎回これを行う。

Androidで同期3
「がとらぼ」の中の人の12月19日現在は1つ上の手順で同期をオフ・オンすることで同期に成功するが、その次の同期で異常が発生する。もちろん、もう一度同期のスイッチをオフ・オンすればその時だけ同期に成功する。

以前は Apache2.2 と PHP5.* で Z-Push を使っていたんだけど、現在は Apache を使っておらず Z-Push を Nginx で動かすのは初めて。もしかしたら Nginx の設定が不適切かもしれない。
もう少し情報を集めてトライするつもり。 Z-Push が VerUP で改善されるか若しくは Z-Push or Nginx の設定変更で正常に使えるようになったらこの記事を更新または追記する予定。

2017年5月12日追記:(以下)

/usr/local/www/z-push/backend/imap/config.php

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// Folder prefix is the common part in your names (3, 4)
define('IMAP_FOLDER_PREFIX', '');

// Inbox will have the preffix preppend (3 & 4 to true)
define('IMAP_FOLDER_PREFIX_IN_INBOX', false);

// Inbox folder name (case doesn't matter) - (empty in 4)
define('IMAP_FOLDER_INBOX', 'INBOX');

// Sent folder name (case doesn't matter)
define('IMAP_FOLDER_SENT', 'INBOX.Sent');

// Draft folder name (case doesn't matter)
define('IMAP_FOLDER_DRAFT', 'INBOX.Drafts');

// Trash folder name (case doesn't matter)
define('IMAP_FOLDER_TRASH', 'INBOX.Trash');

// Spam folder name (case doesn't matter). Only showed as special by iOS devices
define('IMAP_FOLDER_SPAM', 'INBOX.Spam');

// Archive folder name (case doesn't matter). Only showed as special by iOS devices
define('IMAP_FOLDER_ARCHIVE', '');

どうも同期が失敗するのはZ-Pushが読み込むためのIMAPサーバのフォルダ名指定の問題だったっぽい。
上はIMAPサーバがCourier-IMAPで正しく動作する指定例となるが、ここの指定がちょっとでも不適切だと同期が失敗するっぽい。
「がとらぼ」の中の人が失敗してたのはIMAP_FOLDER_PREFIXに"INBOX."を指定してIMAP_FOLDER_PREFIX_IN_INBOXを"false" (InboxはINBOX.InboxじゃなくInboxなので)にしていたこと。例えばIMAP_FOLDER_SENTは"INBOX.Sent"でなく"Sent"で大丈夫(設定項目の筋からするとそれで良い筈)と思ったが、どこかがおかしいらしくIMAP_FOLDER_PREFIXを使わずに個別に指定してやらないとダメみたい。
よって他のIMAPサーバでもフォルダ名の部分は十分に注意して指定してやる。当然だが、Courier-IMAP以外で上の指定を真似たらたぶんアウト。

ということで、メールだけなら問題なく使えるみたい。プッシュ通知もOK. (この追記部分の動作確認はZ-Push 2.3.6 final)

2018年8月20日追記:
2.4系について別記事を書いた。(下のリンク)

関連記事: