WordPress Archive

OCT
11

サーバー移転しました。

Published:2010-10-11 13:10:33 UTC

このBlogで利用しているサーバーを、これまでのXREAからさくらのVPSに変更しました。さくらのVPSは、KVMによって完全仮想化されたVMを借りられるサービスで、先日ubuntu serverのサポートも始まったことから借りてみました。XREAはどうも調子が悪いことが多かったので。。

やっぱり、気兼ねなしに使える固定IPがあるというのはいいものです。サーバー料金は、月額980円と、これまで利用していたのに比べると高いですが、まぁrootとれて自由に遊べること考えたら安いですね。Wordpress動かすだけでなく、自宅のESXi&Hyper-Vと連携させて、色々遊んでみたいと思います。

みんな大好きWordPress。だからこそ、データが飛んでしまうのはなんとしても避けたいもの。そのためには、常日頃からデータのバックアップを取っておくのが重要なのですが、いちいち手動でバックアップするのは手間なので、なるべく自動化しておきたいものです。バックアップしたいのは次の二つ:アップロードしたファイルとMySQLのダンプ。そこで、UNIX環境の勉強がてら、今このブログが設置されているXREAのサーバーから、ローカルに立てたサーバへ自動的にバックアップする体制を整えてみることにしました。今回のエントリではその方法をまとめてみました。

処理の流れ

今回XREAのサーバーに設置したWordPressのデータをバックアップするにあたっては、まず、XREAのサーバー側で、MySQLのデータをダンプし、圧縮をかけてファイルとして保存する、という処理を行います。その上で、ローカル側に設置したサーバーで、ryncという差分コピー可能なコマンドをつかい、SSHを通じてサーバーからMySQLのダンプしたデータや、アップロードした画像、WordPressの本体やプラグイン、テーマをひっくるめて同期します(Pull)。そして同期したディレクトリを元に、pdumpfsを使い世代別バックアップを作成します。この処理をcronで毎日実行してやるという流れです。

このように今回はcronやrsyncを使うために、ローカル側に、毎日その時間に起きているUNIXなマシンが必要になります。そのため今回のエントリは、ファイルサーバーにするなどで自宅サーバーを運用している人以外にはハードルが高いかも知れません。ただ、起きっぱなしのサーバーが家に一台あれば、前述のようにファイルサーバーに出来るなど何かと便利ですので、これを機に、自宅サーバー構築に手を出してみるのもおススメです:D 遊んでいるマシンがあるなら、それにLinuxを入れてしまうとか、遊んでいなくても常時起こしておけるWindowsマシンがあれば、VirtualBoxを入れてその中でLinuxを動かすとか、色々方法はあります。

バックアップ手順

まずは下ごしらえ。ローカルのサーバーからリモートのサーバー(XREA)に対して操作を行うわけですが、そのためにはSSHで接続できるようにしなければなりません。XREAへのSSHでの接続については、こちらのhiromasaさんの記事を参照。但し、今回は、バックアップの自動化が目的なので、そのプロセスで手動でのパスワードの入力を求められるのは困るので、パスフレーズを空にした鍵による公開鍵認証を使います。ssh-keygenを使ってローカルのサーバーで鍵ペアを作り、公開鍵をリモートのサーバー(XREA)に配置しましょう。鍵ペアの作り方についてはssh にてパスワードを使用しないでログインする方法を参照。

次にMySQLのダンプと圧縮。と言っても、難しいことは何もありません。これについてもhiromasaさんが既にサーバー側のcronで定期的にMySQLをダンプする方法についての記事を書かれています。これを使わせてもらいましょう。今回は、pdumpfsで世代別バックアップを取っているので、日付別に保存しないように改変したものを以下に示します。

#!/bin/sh
 
# 設定(ここを自分に合わせる)
DATABASE=
DBUSERNAME=
PASSWORD=
XREAUSERNAME=
BACKUPDIR=
KEEPDAY=14
 
# 初期化(XREA/CORESERVER用)
PREFIX=mysql
SERVER=localhost
NOWDATE=`date +%Y%m%d`
DESTDIR=/virtual/$XREAUSERNAME/$BACKUPDIR
# DUMPFILE=$PREFIX.$NOWDATE.dump
DUMPFILE=$PREFIX.dump
# TARFILE=$PREFIX.$NOWDATE.tar.gz
TARFILE=$PREFIX.tar.gz
OLDDATE=`date "-d$KEEPDAY days ago" +%Y%m%d`
 
# MySQLダンプ/圧縮
cd $DESTDIR
/usr/local/mysql/bin/mysqldump $DATABASE --host=$SERVER -u $DBUSERNAME --password=$PASSWORD > $DUMPFILE
tar zcvf $TARFILE $DUMPFILE
 
# 処理判定
if [ $? != 0 -o ! -e $TARFILE ]; then
    echo "backup faild -- ($DUMPFILE)"
    exit 1
fi
 
# 圧縮前ファイル削除
rm -f $DUMPFILE
 
# n日ローテートを削除
#rmfile=$DESTDIR/$PREFIX.$OLDDATE.tar.gz
#if [ -e $rmfile ]; then
#    rm -f $rmfile
#fi

cronの設定をしない以外は、記事の通りにXREAのサーバーに配置し、設定を書き換えてやれば大丈夫です。では、試しにSSHを通じてコマンドを発行し動かしてみましょう。ローカルのサーバーで以下のコマンドを実行してみましょう。

ssh -i <秘密鍵へのパス> <XREAのユーザー名>@<サーバ名> <hiromasaさん製スクリプトへのパス>

#ウチの環境だと以下のようになります。
ssh -i ./nopass sharplab@s333.xrea.com /virtual/sharplab/backup-mysql/mysqlbackup.sh

動きましたか?動かない?SSHの接続が拒否された?それはもしかすると、XREAのサーバーにホスト情報を登録し忘れているせいかもしれません。hiromasaさんの先ほどの記事を参考に登録を行ってみましょう。

さて、とりあえず手動で登録すればよいことは分かりましたが、登録の有効期限は30日間だけに限られています。また、出先でSSHで繋ぐために別のIPアドレスを登録した場合、上書きされてしまい、再度登録しないと繋がらなくなってしまいます。そのため、ホスト情報の登録も自動化する必要があります。そこでこんなスクリプトをPythonで書いてみました。

#!/usr/bin/env python
# vim:fileencoding=utf_8
import sys
import urllib
import re

#ここを書き換えてください
server = ''
username = ''
password = ''
ipaddressResponder = ''#'http://scripts.sharplab.net/ipaddress.php'//←ウチの場合

adminURL = 'http://%s/jp/admin.cgi' % server

try:
	ipRes = urllib.urlopen(ipaddressResponder)
	ipaddress = ipRes.read()
except:
	print u'Failed'
	sys.exit()

pattern = re.compile('\d+\.\d+\.\d+\.\d+')
if pattern.match(ipaddress) == None:
	print u'Failed'
	sys.exit();

values = {'id':username, 'pass':password,'remote_host':ipaddress,'ssh2':'SSH登録'}
data = urllib.urlencode(values)
print u'Registing ipaddress(%s)...'  % ipaddress 
response = urllib.urlopen(adminURL,data)
try:
	response.read().decode('shift_jis').index(u'データベースに追加しました。反映には5〜10分程度掛かります。')
	print u'Complete!'
except ValueError:
	print u'Failed.'

まず、前もって接続してきたホストのIPを返すPHPのページをサーバーに設置し(ipaddressResponder)、そこにアクセスすることでホストのIPアドレスを調べています。PHPのページのソースはこう。

<?php
echo getenv("REMOTE_ADDR");
?>

その上で、調べたホストのIPとユーザー名、パスワードをホストの登録ページにPOSTするだけの簡単なお仕事です。Cookieとか憶えないといけないかなと思ってPython Mechanize使おうとしたのですが、必要なかったです(笑)

さて、ここまでで、SSHを通してサーバー側でMySQLをダンプする処理と、SSHのためにホストを自動登録するスクリプトの準備が出来ました。では次はいよいよ本題、rsyncによるファイルのバックアップです。rsyncによるリモートバックアップは、リモートとSSHで繋げ、リモートにもrsyncが入っていれば使えると記憶していますが、XREAはどちらも満たしています。他のレンタルサーバーでも、SSHで繋げるところなら使えるところはあるかと思います。

ではrsyncのコマンドを。

<rsyncへのパス> -avz --delete -e 'ssh -i <秘密鍵へのパス>' <XREAのユーザー名>@<サーバー名>.xrea.com:<バックアップしたいディレクトリへのパス> <同期先へのパス>

#ウチの環境だと以下のようになります
./rsync/rsync -avz --delete -e 'ssh -i ./nopass' sharplab@s333.xrea.com:/virtual/sharplab/ ./sharplab/workspace

これでXREAのサーバーとローカルのサーバーの中身を同期させられます。rsyncは更新のあった差分のみをやり取りするので二度目以降は効率が上がるのが嬉しいですね!

そしてpdumpfs。同期したフォルダをソースに、世代別バックアップを作ってやります。pdumpfsはハードリンクを活用しているので、毎日世代別バックアップを取っても、更新がかかったファイル分位しか必要とする領域が増えないので使うのに気が楽ですね。

pdumpfs <ソースディレクトリ> <バックアップ先ディレクトリ>

//ウチの環境だと以下のようになります
pdumpfs ./sharplab/workspace/ ./sharplab/backup/

ではこれらをまとめた上でcronに登録してみましょう。

まずバックアップ処理手順をまとめたスクリプトを作成します。

#サーバーに配置したMySQLのダンプ&圧縮スクリプトを起動
ssh -i <秘密鍵へのパス> <XREAのユーザー名>@<XREAのサーバー名>.xrea.com <hiromasaさん作のスクリプトへのパス>
#サーバー全体をworkspaceディレクトリと同期
<rsyncへのパス>/rsync -avz --delete -e 'ssh -i <秘密鍵へのパス>' <XREAのユーザー名>@<XREAのサーバー名>.xrea.com:<バックアップ対象としたいディレクトリへのパス> <一時保存先のディレクトリへのパス>
#pdumpfsで世代別バックアップ
pdumpfs <一時保存先のディレクトリ> <バックアップ先>

そしてこれを毎日呼び出すようにcronを設定します。

HOME=<registHost.pyやbackup.shを配置したディレクトリ>
#毎日午前四時 SSHを使うにあたり、ホスト情報をXREAに登録
0 4 * * * <registHost.pyやbackup.shを配置したディレクトリ>/registHost.py

#毎日午前四時十分 XREAのバックアップの本処理
10 4 * * * <registHost.pyやbackup.shを配置したディレクトリ>/backup.sh

さて、最後に忘れちゃいけない作業があります。

それはバックアップのリストア作業のテスト。バックアップをとったは良いけど、実はうまく取れていなくて、いざ必要になった時に使い物になりませんでしたでは悲しすぎます。忘れずにリストア出来るか確認しておきましょう。お疲れ様でした!

DEC
16

WordPress 2.7の新XML-RPC API

Published:2008-12-16 01:17:08 UTC

おくればせながらWordPress2.7、自分も導入してみました。2.7に合わせてのテーマの改造は行っていないので、このサイトの見てくれ自体は全く変わっていないのですが、管理画面は大きく変わり、中々小奇麗なスタイルになっています。せっかくなので、ページのデザイン自体も、この機会にちょっといじってみようかなと考えています。例えば、今やたらと肥え太ってしまっているカテゴリ分けを整理して、タグベースの管理に移行させたりとか、色々思うところがありますので…。

さて、XML-RPC API。WordPress2.7でもXML-RPC APIの拡張は着々と行われています。一番のポイントは、やはりコメントの投稿、編集、削除、リストの取得がXML-RPC通じて出来るようになったことでしょうか。

現在WordPress2.7では、以上のメソッドが利用できるようになっており、WordPress iPhone Appの新版ではこれらを使い、コメントのモデレートが出来るようになったとのことです。また、このほかにもwp.getTagsメソッドが追加され、タグの一覧の取得が出来るようになったり、wp.getPagesメソッドに四番目の引数が追加され、返されるページリストの最大数を指定できるようになった他、wp.getUsersBlogsメソッド、metaWeblog.getPostメソッド、metaWeblog.getCategoriesメソッドについてのバグ修正が行われたようです。(via WordPress 2.7 Released – XML-RPC and AtomPub Changes || Joseph Scott

個人的には、次はメディアライブラリ関係を扱うためのXML-RPCメソッドが欲しかったり。今のXML-RPC APIには、ファイルをアップするためのAPIはあるのですが、不要になったファイルを削除するためのメソッドがありません。そのため、Windows Live Writerで画像をリサイズさせながら投稿を繰り返すと、結構不要なゴミファイルが溜まってしまっていたりします。ここらへんは、まだまだWordPressの進化を期待したいですね。

 

P.S.

前に公開したWP-XML-RPCLib & WP-XML-RPCCLibというWordPress2.7のAPIを扱うための.NET言語向けライブラリですが、近いうちに修正版を出したいと思っています。今のバージョンに明確なバグがあるわけではないのですが、書くべきparamsキーワードがなかったりして、呼び出しがやたらと書きにくくなってしまっているので…。

DEC
8

WordPressのセキュリティ

Published:2008-12-08 02:01:06 UTC

高木浩光@自宅の日記 – 公衆無線LANで使うと危ないiPod touchアプリに注意

こういう記事を見るたびに不安になるのだけれど、WordPressでセキュリティを確保するのってどうすりゃいいんでしょう?自分はセキュリティについて殆ど知識がないんですが、HTML Form経由でもXML-RPC経由でもパスワードは平文で送信された筈ですが、これは相当ヤバいんでしょうか。Atom-Pub経由なら長めのパスワードを設定しておけば安全と考えていいのかな?

突然ですが、ここで問題です。以下の二つの文の結果は、同じものであると考えてよいでしょうか?

the_search_query();
echo(get_search_query());

これ、同じと考えては駄目なんですね。異なると考えた人も、ちゃんと異なる結果が返されうる理由を説明できましたでしょうか?これを勘違いしたままWordPressのテーマを書いていると、クリティカルな脆弱性の元になるので、結構重要な問題です。

実は、get_search_query関数の戻り値は、the_search_query関数の出力と異なり、サニタイズがかかっていません。そのため、<?php echo(get_search_query()); ?>というコードがテーマ中に存在すると、script injection攻撃を仕掛けられる危険性があります。攻撃を受けた場合、投稿データなどの全削除すらされ得るでしょう。

パッと思いつく攻撃方法としては、Javascript呼び出しを含むタグを仕込んだ攻撃用検索クエリURLをエンコードしたtinyURLをそれっぽい誘導文とともにコメントとして攻撃対象のBlogに貼り付け、といった具合でしょうか。上手いこと管理権限を保持したままBlogの管理人がそのリンクを踏んでくれれば、管理人に対し任意のスクリプトを埋め込んだ状態で対象サイトを表示させることが出来ます。WordPressで作られたサイトは、普通一般に見せる部分と管理画面とで、ドメインが異なるということがないので、スクリプト実行時のクロスドメイン制約に悩まされることなく、iframeなどを使ってやりたい放題出来るんじゃないでしょうか。

昨日大学の研究会のD1の先輩に、「一般論としてセキュアなコーディングをする上で心掛けることってなんでしょう?」と訊いたところ、「とにかくプログラムの入力に渡されうる値を把握すること」と言われましたが、これもまさに同じことで、WordPressの関数であっても、the_search_query()とget_search_query()は出し方が違うだけで返すデータは一緒だろ―と安易に考えず、ちゃんとサニタイズされているかを確認する必要がありますよ、というお話でした。

ちなみにこの落とし穴、自分でこのサイトのテーマを弄っているときにうまくサニタイズされていないことに気づいたのがきっかけで知ったのですが、WP2.5の時点ではデフォルトテーマでさえ引っかかっていたようです。((;゜Д゜))))