makoto_fujimotoのblog

株式会社進角
代表 藤本信のブログです
どうぞよろしくお願いします

カテゴリ: WordPress

ステージングと本番系に分けた構成のWordpressサイトの同期手段としてwordmoveを使用していますが、しばらく運用していたところ、Webアクセスとは無関係にサーバ負荷が異常上昇する現象が発生しました。wordmoveの設定についてはこちらを参照。

accsess_logやtopコマンドで確認したところ、同期を実行してから間もなくしてサーバ自身からのHEADメソッドによるローカルリクエスト起きていることが判明し、その数なんと23万件以上ありました。ロードアベレージも20を超えサーバがパンクする事態となりまして、原因が分かるまでは対処療法として負荷を監視してhttpdを自動的に再起動するなどの応急処置でしのいでいました。

現象がpingバック機能に似ていたことからWP Total Hacksを始めいくつかのプラグインを試して禁止するように設定しましたが効果はありませんでした。

お手上げです。。

そこで、一時的にすべてのクエリーログを吐き出すように設定して調査したところ、負荷上昇時に気になるSQLが発行されていることが分かりました。それが以下のSQLです。
SELECT ID, post_content, meta_id FROM wp_posts, wp_postmeta WHERE wp_posts.ID = wp_postmeta.post_id AND wp_postmeta.meta_key = '_pingme' LIMIT 1
SELECT * FROM wp_postmeta WHERE meta_id = 22663
DELETE FROM `wp_postmeta` WHERE `meta_id` = 22663
SELECT pinged FROM wp_posts WHERE ID = 874
SELECT   wp_posts.* FROM wp_posts  WHERE 1=1  AND wp_posts.post_name = 'gaobijo-title_fuku-png' AND wp_posts.post_type = 'post'  ORDER BY wp_posts.post_date DESC
SELECT   wp_posts.* FROM wp_posts  WHERE 1=1  AND wp_posts.post_name = 'gaobijo-title_fuku-png' AND wp_posts.post_type = 'post'  ORDER BY wp_posts.post_date DESC
SELECT   wp_posts.* FROM wp_posts  WHERE 1=1  AND wp_posts.post_name = 'kumaayaka04-png' AND wp_posts.post_type = 'post'  ORDER BY wp_posts.post_date DESC

詳しくは分析していませんが、pingバックを禁止しているにも関わらずページ内のリンクをすべてパースして何か処理を行っているようです。そしてついにこの処理を行っていると思われるコードを発見しました。それがdo_all_pings()という関数です。この関数はwp-cron.phpという疑似バッチのトリガーから呼び出されるwp-include/default-filters.phpにてadd_actionでフックされています。同期の実行からしばらく経過してから異常が発生する現象ともつじつまが合います。
add_action( 'do_pings',    'do_all_pings',    10, 1 );

この部分をコメントアウトすることでやっと不可解な自ホストに対してのHEAD呼出し現象が止まりました。なおdefault-filters.phpはパッケージのアップデートなどにより更新されてしまうので、add_actionを無効化するスクリプトをプラグイン化して設置する方が良いそうです。以下サンプルphpです。

<?php
/*
Plugin Name: No Do Pings
Plugin URI:
Description: Remove Actions and Filters
Author: Makoto Fujimoto
Version: 1.00
Author URI:
*/
remove_action( 'do_pings', 'do_all_pings' );
?>
この様なPHPプログラムをwp-content/plugins/以下に設置して管理画面で有効化してください。

RewriteEngine On
RewriteBase /
RewriteCond %{QUERY_STRING} (author=\d+) [NC]
RewriteRule .* - [F,L]

みんな大好きな()WordPressのインストールですが、非エンジニアやセキュリティに詳しくない人が設定することが多い傾向にあり、ファイルのパーミションやオーナー・グループが不適切な状態になっていることがよくあります。特にWebから更新するファイルやフォルダ設定が777になっていたり、1つのアカウントを複数人で共有して運用していることも多いようです。

以下は不必要なパーミションを与えず、複数人がそれぞれのアカウントで共同作業ができるようにWordPressをインストールする例です。ユーザーをすべて同じグループに所属させ、新規でファイルをアップロードする際には自動的にグループとパーミション(664)が設定されます。そうすることで別のメンバーが作成したファイルを共同編集することが可能になります。

■サブドメインのパーミション設定
$ su
# mkdir /var/www/vhosts
# mkdir /var/www/vhosts/hoge.jp
# mkdir /var/www/vhosts/hoge.jp/html
# cd /var/www/vhosts/hoge.jp
# chmod 2775 .
# chmod 2775 html
# groupadd hoge-dev
# chgrp hoge-dev .
# chgrp hoge-dev html
# vi /etc/group
 関係者をhoge-devに追加(apacheユーザも)
# vi /home/User/.bashrc
 umask 002を追加 (各ユーザに)
FTPを使用する場合もumaskが002になるようにしておきます。

ここらでApacheの設定をしておきましょう

■Wordpressのインストール
/var/www/vhosts/hoge.jp/html直下に展開する方法
$ cd
$ mkdir wp
$ cd wp
 最新パッケージをダウンロード http://ja.wordpress.org/
$ gzip -d *.gz
$ tar xvf *.tar
$ cd wordpress
$ chgrp -R hoge-dev *
$ chmod -R g+w .
$ cp -pr * /var/www/vhosts/hoge.jp/html

■その他
/wp-adminには無慈悲なくらいアクセス制限を掛けましょう!

みんな大好き()Wordpressですが、Webサイトのエンタープライズ運用で必須とされているステージング(テスト)環境から本番環境へ正確にコンテンツ同期するスマートな方法があまり存在しないようです。

え!?公開予約機能を使って購読者アカウントでクライアントに事前確認させればいいって?
でも全体的なデザインやレイアウト改修を事前確認してもらうにはどうしたらいいんですかね?みなさんどうやって運用しているんでしょうか?

いろいろ調べていたらwordmoveというツールを見つけたので検証してみたところ、まあまあ問題なく使えそうなことがわかりましたので設定メモを残しておきます。wordmoveをざっと説明するとWordpress関連ファイルの物理コピーとデータベースのダンプ、変換、リストアを行ってくれるコマンドベースのユーティリティで、サーバの引っ越しにも用いられているようです。ちなみにrubyで作られています。

通常であればステージングサーバと本番サーバは別々の構成になると思いますが、このケースでは同一サーバ内でステージング用のサブドメインを同居させる方法としました。Wordpressはドキュメントルート直下にすでにインストール済みの状態を想定しています。

OS:CentOS 6.7
本番サイト
 www.test-wordmove.jp  /var/www/vhosts/www.test-wordmove.jp/html
 DB:www_wordmove
ステージングサイト
 stg.test-wordmove.jp  /var/www/vhosts/stg.test-wordmove.jp/html
 DB:stg_wordmove

以下設定手順

# yum install openssl-devel
# yum install rdoc

rubyの構築
CentOS6.xに標準のRubyはバージョンが古いようなのでソースから構築します。
$ cd
$ mkdir ruby
$ cd ruby
$ wget http://ftp.ruby-lang.org/pub/ruby/2.3/ruby-2.3.0.tar.gz
$ gzip -d ruby-2.3.0.tar.gz
$ tar xvf ruby-2.3.0.tar
$ cd ruby-2.3.0
$ ./configure
$ make

rubyの動作確認
$ ./ruby -v
ruby 2.3.0p0 (2015-12-25 revision 53290) [x86_64-linux]

rubyのインストール
$ su
# make install

wordmoveのインストール
# gem install wordmove
動作確認
# wordmove --help

環境変数LANG=ja_JP.UTF-8を設定
# vi /etc/sysconfig/i18n

wordmoveの設定
$ cd
$ mkdir wordmove
$ cd wordmove/
$ wordmove init
  Movefileが生成されます。

Movefileの編集
$ vi Movefile
インシデントがとてもデリケートなので編集注意
-------------------------------------------------
local:  #こちらがステージングサイト
  vhost: "http://stg.test-wordmove.jp"
  wordpress_path: "/var/www/vhosts/stg.test-wordmove.jp/html" # use an absolute path here

  database:
    name: "stg_wordmove"
    user: "DBユーザー名"
    password: "DBパスワード"
    host: "127.0.0.1"

staging:  #こちらが本番サイト
  vhost: "http://www.test-wordmove.jp"
  wordpress_path: "/var/www/vhosts/www.test-wordmove.jp/html" # use an absolute path here

  database:
    name: "www_wordmove"
    user: "DBユーザー名"
    password: "DBパスワード"
    host: "127.0.0.1"
    # port: "3308" # Use just in case you have exotic server config

  exclude: #同期しないリスト
    - ".git/"
    - ".gitignore"
    - ".sass-cache/"
    - "node_modules/"
    - "bin/"
    - "tmp/*"
    - "Gemfile*"
    - "Movefile"
    - "wp-config.php"
    - "wp-content/*.sql"
    - ".htaccess"

  # paths: # you can customize wordpress internal paths
  #   wp_content: "wp-content"
  #   uploads: "wp-content/uploads"
  #   plugins: "wp-content/plugins"
  #   themes: "wp-content/themes"
  #   languages: "wp-content/languages"
  #   themes: "wp-content/themes"

  ssh:  #本番側のアカウント
    host: "localhost"
    user: "wordmoveを実行するユーザー"
  #   password: "password" # password is optional, will use public keys if available.
  #   port: 22 # Port is optional
    rsync_options: "--verbose" # Additional rsync options, optional
  #   gateway: # Gateway is optional
  #     host: "host"
  #     user: "user"
  #     password: "password" # password is optional, will use public keys if available.

  # ftp:
  #   user: "user"
  #   password: "password"
  #   host: "host"
  #   passive: true

# production: # multiple environments can be specified
#   [...]
-------------------------------------------------
この例ではlocalhostからlocalhostへsshのパスワード問合せが無いように設定されていることを前提としています。

実行テスト
ステージング側のWordpressに何らかの記事を更新
$ wordmove push --all -s (シミュレーションモード)
$ wordmove push --all
本番サイトで更新が反映されていれば成功です。

注意点
ステージング側のhtml/wp-content/にsqlのダンプファイルが残存してしまうので、セキュリティ的には消すような運用をしたほうがよさそうです。

運用課題
wordmoveはあくまでコマンドベースのユーティリティですので、cronで定期実行したりワンショットでスケジューリング行う必要があります。また同期したいタイミングで手動にて実行する必要があります。

↑このページのトップヘ