このブログの公開期限切れの投稿を非表示にするのに、crontabのスクリプトでWordPressの機能を実行しているのだが、 なぜか、今月の頭辺りから以下のようなエラーが出るようになった。
AIOS_Helper::request_remote exception - cURL error 28: Operation timed out after 4001 milliseconds with 0 bytes received
どこから出るのかも原因も分からないので様子を見ていたら、エラーは次のものに変わった。※
AIOS_Helper::request_remote exception - cURL error 28: Failed to connect to api.ipify.org port 80: Connection timed out
※下に参照したフォーラムによれば、問い合わせを受けて修正したためにメッセージが変わったようだ。
(「あくしろ」手っ取り早く解決方法を知りたい方は、下の「解決方法」へ)
検索すると、エラーメッセージの"AIOS"というのはWPのプラグイン"All In One WP Security"のことで、それがapi.ipify.orgというサイトにアクセスして(自分(=サーバ)の)IPアドレスを取得しているのだが、その接続に失敗しているようだ。 (参照: WPのフォーラムの同様の問題の問い合わせ: cron job error)
この時は、「(前科者の)"All In One"が またやっちゃったかあ・・・」と溜息をついて居た。ただ、証拠はないものの、エラーが出るようになったのがAIOSの更新後だったかも知れず、であれば「前科者」は正しい。 (← 調べたら、「更新後にエラーが出る」という問い合わせがあるので正しい。)
どうしてIPアドレスを取得するのかというと、webサーバでなく スクリプトからWPを実行する場合、PHPの変数$_SERVER[REMOTE_ADDR]にIPアドレスが設定されていないためだ。
それらの変数は、webサーバが$REMOTE_ADDRなどの環境変数に設定したものをPHPが$_SERVERに格納する。
この辺りはPHPのドキュメントのコメントにあるように、なかなかセキュリティ面が危うい気がするが、今はヨシとする(どうにも しようがない)。。。
どうしてIPアドレスが要るかというと、AIOSがアクセス元を調べるからのようだ。それでブラックリストの判定をしていると想像していたけど、この場合は無意味だ。というのは、サーバからapi.ipify.orgなどにアクセスして分かるのはサーバのIPアドレスで、アクセス元のではないからだ。
きっと、AIOSの更新の時に思い付いて追加したのだろうけど、全く無駄だ。JavaScriptなどでクライアント(ブラウザ)にやらせても詐称されるから無駄だ。環境変数にアクセス元のIPアドレスが設定されていないなら、全部エラーにするかサーバとみなすかのどちらかにすべきなのだ。
百歩譲ってサーバの本当のアドレス(グローバルアドレス)を取るとすれば、外部サイトに依存しない方法にすべきなのだ。
それは環境変数$REMOTE_ADDRで設定されるようなので(この時には上に書いたことは分かっておらず、直感や誤解で そう思った)、試しに、スクリプトを起動する前にlocalhostのアドレス(127.0.0.1)を設定したのだが※、効果は なかった(エラーが出ないこともあったが、出ることもあった)。
実は、上のフォーラムの回答には、アドレスが127.0.0.1の場合にも外部サイト(例: api.ipify.org)でIPアドレスを取得するとあるのだが、最初は読み飛ばしていたために無意味なことをした。
※なぜlocalhostにしたかというと、変わりようがないから安定かつ安全だと思ったためだ。それで却って失敗した・・・
それで、実行する時間帯をずらしたり、実行前にapi.ipify.orgにpingするなどの試行錯誤したあとで(うまく行ったりそうでなかったりした)、$REMOTE_ADDRにサーバの本当のアドレスを設定したら、うまく行っているようだった。
その理由を知るためにプラグインのプログラムを調べたら、上に書いたように、IPアドレスが空または127.0.0.1の場合には外部サイトからアドレスを取得することが分かった。
毎回エラーになる訳でないのも不思議だったが、いくつかのサイトをランダムな順で使っているようなので、api.ipify.orgが使われた時だけエラーになったのではないか。
ただ、そもそもapi.ipify.orgへのアクセスがエラーになった原因は分からないが、たまたまNWやサーバが重かったとかだろうか。
書いたあとで調べたら、他の方でも起こっているようなので、(このサーバでなく、)api.ipify.orgにアクセスが集中して接続できない場合があるのではないか。だとすれば、正しい修正は、IPアドレス取得に使うサーバを選択できるようにすることだ。
だから、
(解決方法) 環境変数$REMOTE_ADDRにサーバの本当のアドレス(例: hostname -i や hostname -ihost -t A ホスト名 で取れる※)を設定すれば、エラーは起こらなくなることが分かった。
※今試して分かったが、hostname -iだと/etc/hostsの設定によっては127.0.0.1が返って来るので、host -t A ホスト名 などがいいかも知れない。
実際には以下のようにしている(the-WP-progがWPの処理を実行するスクリプト)。
export REMOTE_ADDR="`hostname -i`"; the-WP-prog
が、上述のようにhostname -iは今一つなので、(なんか冗長だけど)以下が良さそうだ(未確認)。
export REMOTE_ADDR="`host -t A \`hostname\`| cut -d " " -f 4`"; the-WP-prog
とりあえずエラーは出なくなったが、そもそも、スクリプトからWPを実行する場合はAIOSを無効にするほうが良さそうな気はする。が、それは結構大変(wp-load.phpなどの改造が必要で、逆に問題が起こる可能性が大きい)なので、これで良しとした。
まあ、問題は(サーバでない)スクリプトからWPを呼び出す場合だけで起こり、通常の使い方では起こらない。そのために手間を掛け・リスクを増やすこともないだろう。
PS. 本文で参照したフォーラムのやり取りを見ると、例によって「埒が明かない」感がある。: 質問の題"cron job error"が示すとおり、(webサーバからでない)スクリプトでIPアドレスが設定されないのが問題なのに、回答者が問題の原因を把握できず、適切な回答も修正もしていないので(2番目以降の質問者は)解決できていない。
当然ながら、$REMOTE_ADDRに本当のIPアドレスを設定してスクリプトを実行すれば良いことも書いてない。
不思議なのは、最初の質問者が「解決済み」にしているらしいことで、(しょうもない回答に呆れて)自力で解決できたのだろうか。あるいは 本当に解決していて、僕が曲解しているだけ??
本文に書いた内容や そういったことを投稿しようかと思ったが、ユーザー登録が必要なのと、この感じでは無駄になりそう(無視されそう)なので していない。
PS2. これを書き、そのあとで調べたりしたら、AIOSのアラが出て来て なんか信用ならない感じになって来た。が、以前調べたところでは これが一番良かったので、当面は頼るしかない。が、セキュリティのプラグインが そんなことでいいのか??