概要
タイトルのまんまです。
レンタルサーバを借りて WordPress を動かしていますが、開発環境も欲しくて、なんとか楽に開発したり、開発したものを本番に持ってったりできないか、グローバルIPアドレスを追加するのもお金かかってやだな、と考える、とにかく楽をしたい怠惰な私が、とりあえず運用している方法を晒してみます。
何か思い出したら加筆するかもしれません。
概略
これだけ読めばいいのかも。1
- 同じサーバに WordPress を二つ入れるよ。
- バーチャルホストを設定するよ。
- 開発環境にそれっぽいデータを準備するのは面倒なので、cron で daily に本番環境の DB から開発環境の DB にコピーするよ。
- DB のコピーは本番環境から Dropbox ディレクトリに dump、それを perl で書き換えつつ開発環境に restore、なんで自動的に DB のバックアップにもなっているよ。
- どっちもドキュメントルート以下を git で管理するよ。開発環境での開発結果は開発環境で git push して本番環境で git pull するよ。
- git のリモートリポジトリとして Drobox ディレクトリを設定してあるから、たまにそっちにも push しているから、ファイルのバックアップもできているよ。
- 画像データは基本的に Picasa ウェブアルバムに上げちゃうんで、実質ローカルにアップロードデータはない方針だよ。
- バックアップは直近 5 日分をローテーションで取っているみたい。今、スクリプトを見て、過去の私がやっていたことを知りました。
本番環境 | 開発環境 | |
---|---|---|
URL | http://mato.me/ |
http://wp2.mato.me |
WEB認証 | 公開だからもちろんなし | Digest認証でブロック |
ドキュメントルート | /var/web/matome/wp/ | /var/web/maome/wp2/ |
mysql DB 名 | wp_matome | wp2_matome |
mysql ユーザ名 | wp_user | wp_user |
mysql パスワード | 開発環境と同じ | 本番環境と同じ |
/var/web/maome/wp2
というディレクトリは /var/web/maome/wp2.curr
というディレクトリへのシンボリックリンクですが、理由は後述。
バックアップスクリプト
こんな感じです。
#!/bin/bash
script_dir=/home/takeyuki/Dropbox/matome
backup_dir=/home/takeyuki/Dropbox/matome
repo_dir=/home/takeyuki/Dropbox/matome
db_name=wp_matome
db_user=wp_user
db_password=__ないしょ__
dev_db_name=wp2_matome
log_file=${backup_dir}/backup_${db_name}.log
backup_file=${backup_dir}/${db_name}_`date "+%Y-%m-%d"`.dump
mysqldump=/usr/bin/mysqldump
log() {
echo -e `date "+%Y-%m-%d %H:%M:%S"` "\t" $* >> $log_file
}
log start
$mysqldump -u $db_user -p$db_password $db_name > $backup_file
if [ $? -gt 0 ] ; then
log failed to dump : "$db_name -> $backup_file"
exit
fi
log dumped : "$db_name -> $backup_file"
git_repo=${repo_dir}/${db_name}.git
db_size=$(ls -l $backup_file | awk '{print $5}')
repo_size=$(du -sb ${git_repo} | awk '{print $1}')
human_readable() {
byte=$1
echo $byte | awk -f ${script_dir}/human_readable.awk
}
log db_size: $db_size "($(human_readable $db_size))" "\t" repo_size: $repo_size\
"($(human_readable $repo_size))"
count=0
ls -t $backup_dir | grep -E "^${db_name}_[0-9]{4}-[0-9]{2}-[0-9]{2}\.dump\$" | \
while read file ; do
if [ $count -eq 0 ] ; then
# sed -e 's/http:\/\/mato\.me/http:\/\/wp2\.mato\.me/g' $backup_dir/$file |\
mysql -u $db_user -p$db_password $dev_db_name
perl -e '$s="wp2";' -e '$f="http://mato.me";$t="http://$s.mato.me";$d=lengt\
h($t)-length($f);$f="(s:(\\\d+):\\\\\")?".quotemeta($f);while(<>){$_=~s/$f/$2?"\
s:".($2+$d).":\\\"$t":$t/eg;print}' $backup_dir/$file | mysql -u $db_user -p$d\
b_password $dev_db_name
log copy $db_name to $dev_db_name
fi
count=$(($count + 1))
if [ $count -gt 5 ]; then
rm $backup_dir/$file
if [ $? -gt 0 ] ; then
log failed to remove : $file
else
log removed : $file
fi
fi
done
log end
# end of file
ログに残すファイル容量を読みやすくするのに awk 使っているみたい(なにぶん、1 年以上前の私がやったことなんで、今の私はよく知らない)。
{
byte = $1;
}
byte < 1024 {
print byte "B";
next;
}
{
kb = byte / 1024;
}
kb < 1024 {
printf "%4.2fKB\n", kb;
next;
}
{
mb = kb / 1024;
}
mb < 1024 {
printf "%4.2fMB\n", mb;
next;
}
{
gb = mb / 1024;
}
{
printf "%4.2fGB\n", gb;
}
設定ファイルの変更
本番環境と開発環境とで同一のファイルを使いつつ、設定を切り替えるのには、wp-config.php
において $_SERVER['SERVER_NAME']
を見て DB 名を切り替えるだけにしています。
...
if ($_SERVER['SERVER_NAME'] == 'wp2.mato.me') {
$db_name = 'wp2_matome';
} else {
$db_name = 'wp_matome';
}
define('DB_NAME', $db_name);"
...
普段の開発
プラグインやらテーマなんかは開発環境のディレクトリで直接ファイルをいじって、適宜 git commit や git push。本番環境にも適用していいと判断したら本番環境側で git pull。
外部のプラグインを導入する場合などで場合によっては本番環境に直接入れちゃうこともあります。そういう場合はプラグインのインストール&設定後、本番環境で git commit & git push して、開発環境で git pull します。
WordPress のアップデート
これがわりと難関でした。
が、step by step で半自動的にアップデートできるスクリプト upgwp
を導入してからだいぶ楽になりました。
今、久々に upgwp
の中身を見てみたら、もう少しこうした方がいいかな、とか、現在の WordPress のバージョンにあっていないな、という箇所もいくつかありました。そのうち対応したいです。
何か問題があったらすぐに元の環境に戻せるよう、wp.next
という環境に新しいバージョンを構築、完了後 wp.curr
を wp.back
に、wp.next
を wp.curr
にリネームし、シンボリックリンクを張り直します2。
すなわち、何か問題があったら wp2
のシンボリックリンクを wp.back
に張り直せば、以前のバージョンで動作する、ということです3。
#!/bin/bash
self=upgwp
matome_dir=/var/web/matome
work_dir=$matome_dir/$self
next_cmd_file=$work_dir/next.cmd
ope_file=$work_dir/next.ope
first_cmd=pleaseCheckWorkTrees
set_next_cmd() {
echo $1
echo $1 > $next_cmd_file
}
get_next_cmd() {
if [ -f "$next_cmd_file" ]; then
cat $next_cmd_file
else
echo $first_cmd
fi
}
exe() {
cmd=${1}
ope=`cat $ope_file`
echo -e "\t=== $cmd ===" 1>&2
case "$cmd" in
pleaseCheckWorkTrees)
cd $matome_dir
curr_diff=$work_dir/curr.gitdiff
prod_diff=$work_dir/prod.gitdiff
cd $matome_dir
(cd wp2.curr; git diff > $curr_diff)
(cd wp; git diff > $prod_diff)
if [ -s $curr_diff -o -s $prod_diff ]; then
echo "未コミットの変更を処理してください。終了したら再び upgwp してください" 1>&2
else
set_next_cmd clean
fi
;;
clean)
cd $work_dir
rm -fr wordpress/ "*.zip"
cd $matome_dir
rm -fr wp2.next/ wp2.back/
set_next_cmd downloadAndUnzip
;;
downloadAndUnzip)
echo "zip ファイルの URL を入力してください" 1>&2
read url
cd $work_dir
wget $url
zipfile=${url##*/}
unzip $zipfile 1>&2
set_next_cmd copyToNext
;;
copyToNext)
cd $matome_dir
rsync -a upgwp/wordpress/ wp2.next
mv wp2.curr/.git wp2.curr/.gitignore wp2.curr/tmp/ wp2.next/
find wp2.curr/ -name ".gitignore" | while read file; do
mv -v wp2.curr/$file wp2.next/$file
done
rm -fr wp2.next/wp-content/plugins/akismet/
rm -fr wp2.next/wp-content/plugins/hello.php
ls -1 wp2.curr/wp-content/plugins/ | while read p; do
cp -r wp2.curr/wp-content/plugins/$p wp2.next/wp-content/plugins/
done
cp wp2.curr/favicon.ico wp2.next/
rm wp2.next/{license.txt,readme.html,readme-ja.html}
mv wp2.next/wp-config-sample.php wp2.next/wp-config.php
rm -fr wp2.next/wp-content/themes/{twentyeleven/,twentyten/,twentyfourteen/,twelve/twnty/}
cp -r wp2.curr/wp-content/themes/twentytwelve.matome/ wp2.next/wp-content/themes/
set_next_cmd pleaseConfigureOnNexttree
;;
pleaseConfigureOnNexttree)
cd $matome_dir
if [ "$ope" == 'next' ]; then
set_next_cmd pleaseGitStatusOnNexttree
else
tmp=$work_dir/tmp.$$
mv wp2.next/wp-config.php $tmp
tr -d \\r < $tmp | awk -f bin/upgwp_config.awk | sed -e 's/$/\r/' > wp2.next/wp-config.php
rm $tmp
echo "wp2.next の wp-config.php を設定してください。終了したら upgwp next を実行してください。" 1>&2
diff wp2.curr/wp-config.php wp2.next/wp-config.php 1>&2
fi
;;
pleaseGitStatusOnNexttree)
if [ "$ope" == 'next' ]; then
set_next_cmd mksymlinkForNextTree
else
echo "wp2.next で git status して変更を確認してください。終了したら upgwp next を実行してください。" 1>&2
fi
;;
mksymlinkForNextTree)
cd $matome_dir
rm wp2; ln -s wp2.next wp2
set_next_cmd pleaseAccessToNexttreeByBrowser
;;
pleaseAccessToNexttreeByBrowser)
if [ "$ope" == 'next' ]; then
set_next_cmd activateNexttree
else
echo "ブラウザから wp2.mato.me にアクセスして表示を確認してください。" 1>&2
echo "管理画面のダッシュボードから必要に応じて DB の更新をしてください。" 1>&2
echo "終了したら upgwp next を実行してください。" 1>&2
fi
;;
activateNexttree)
cd $matome_dir
mv wp2.curr wp2.back
mv wp2.next wp2.curr
rm wp2
ln -s wp2.curr wp2
set_next_cmd pleaseGitCommitOnNewtree
;;
pleaseGitCommitOnNewtree)
if [ "$ope" == 'next' ]; then
set_next_cmd finish
else
echo "wp2.curr で git commit, git push を実行してください。" 1>&2
echo "終了したら upgwp next を実行してください。" 1>&2
fi
;;
finish)
;;
*)
echo "unknown cmd 「$cmd」" 1>&2
exit -1
;;
esac
echo > $ope_file
}
ope=${1}
echo $ope > $ope_file
cmd=`get_next_cmd`
while [ -n "$cmd" ]; do
cmd=`exe $cmd`
done
# end of file
設定ファイルはかなりの力技で書き換えているようです。
BEGIN {
r["define('DB_NAME', 'database_name_here');"] = \
"if ($_SERVER['SERVER_NAME'] == 'wp2.mato.me') {\n" \
" $db_name = 'wp2_matome';\n" \
"} else {\n" \
" $db_name = 'wp_matome';\n" \
"}\n" \
"define('DB_NAME', $db_name);";
r["define('DB_USER', 'username_here');"] = "define('DB_USER', 'wp_user');";
r["define('DB_PASSWORD', 'password_here');"] = "define('DB_PASSWORD', '__ないしょ__');";
r["define('AUTH_KEY', 'put your unique phrase here');"] = "define('AUTH_KEY', '__ないしょ__');";
r["define('SECURE_AUTH_KEY', 'put your unique phrase here');"] = "define('SECURE_AUTH_KEY', '__ないしょ__');";
r["define('LOGGED_IN_KEY', 'put your unique phrase here');"] = "define('LOGGED_IN_KEY', '__ないしょ__');";
r["define('NONCE_KEY', 'put your unique phrase here');"] = "define('NONCE_KEY', '__ないしょ__');";
r["define('AUTH_SALT', 'put your unique phrase here');"] = "define('AUTH_SALT', '__ないしょ__');";
r["define('SECURE_AUTH_SALT', 'put your unique phrase here');"] = "define('SECURE_AUTH_SALT', '__ないしょ__');";
r["define('LOGGED_IN_SALT', 'put your unique phrase here');"] = "define('LOGGED_IN_SALT', '__ないしょ__');";
r["define('NONCE_SALT', 'put your unique phrase here');"] = "define('NONCE_SALT', '__ないしょ__');";
}
{
if (r[$0] != "") {
print r[$0];
} else {
print;
}
}
END {
print "\ndefine('FS_METHOD', 'direct');";
}
# end of file