もしもに備えてwordpressを単純にバックアップしたい。
バックアップ先としてローカルのPCが考えられるが、自宅PCで起動しないといけないので却下。
クラウドの無料ストレージ時に定期的にバックアップしようと思う。
wordpressをバックアップするプラグインがいくつかあるが、細かい使いたい機能を使おうとすると、有料オプションになる…
ちょっと勉強もかねてシェルスクリプトで実装した。
概要
前提
- OSはCentOS Linux release 7.5(x86_64)を使用
- gdrive-linux-x64(2.1)を使用
- DBとしてmariadbの5系を使用
- googleアカウントを登録済み
仕様
WordPress のバックアップに記載されているように、サイト全体とDBのバックアップを取得し、googleの所定のフォルダにアップロードします。
- 一時的な作業ディレクトリを/tmpの下に作成する。
- サイトはcp, dbはmysqldumpでバックアップファイルを取得する。
- 取得したファイル群は、tar/gzipで圧縮してバックアップファイルを作成する。
- キーファイルが存在する場合は、バックアップファイルをAES256で暗号化する。
- バックアップファイルの名前は、backup_wp_yyyymmdd-HHMMSS.tar.gzとする。暗号化している場合は、backup_wp_yyyymmdd-HHMMSS.tar.gz.aesとする。
- 作成したバックアップファイルをgoogleドライブにアップロードする。
- バックアップファイルは10世代を残す。(アップロードした結果、11世代分になったら最古のバックアップファイルを削除する。)
なお、このシェルを実現するために、linuxからgoogleドライブにアップロードする方法を調査しています。
シェルスクリプト
配置方法
- 下記の3ファイルを任意のディレクトリに保存する。
以降では/root/opetools/binに配置する前提で説明します。 - 同じディレクトリにgdriveを配置する。
- 下記を実行する。
$ chmod 755 backup2gd_wp.sh $ chmod 600 backup2gd_wp_db.conf $ chmod 600 backup2gd_wp_aes.pass - backup2gd_wp.shを下記のように編集します。
aaaaaaaaaaにwordpressのディレクトリを指定します。(例: /var/www/test)
bbbbbbbbbbにgoogleドライブのアップロード先フォルダIDを定義します。 - backup2gd_wp_db.confのccccccccccにDB接続ユーザ名、ddddddddddにパスワードを指定します。
- backup2gd_wp_aes.passのeeeeeeeeeeに暗号化のためのパスワードを指定します。(暗号化したくない場合、このファイルは削除してください。)
#!/bin/sh
#
# backup2gd_wp.sh - backup to google drive for wordpress
#
# TIPS:
# - デバッグ時は先頭を"#!/bin/sh -x"にしてください。
# - バックアップデータを暗号化した場合、次のように復号できます。
# openssl enc -d -aes-256-cbc -salt -pass file:somefile -in file.tar.gz.aes -out file.tar.gz
# tar xvfz file.tar.gz
# ================================================================================
# 実行環境
# ================================================================================
## 処理のベースとする変数
base_dir=<code>dirname $0</code>
base_name=<code>basename $0 .sh</code>
base_datetime=<code>date "+%Y%m%d-%H%M%S"</code>
## バックアップ対象サイトのディレクトリ
site_dir=aaaaaaaaaa
## DB関連 ※mariadbを前提
db_name=wordpress
db_config_file=$base_dir/${base_name}_db.conf
dump_cmd=/usr/bin/mysqldump
## 作業ディレクトリ
work_base_dir=/tmp
work_dir_name=<code>mktemp -u ${base_name}.XXXXXXXX</code>
work_dir=$work_base_dir/$work_dir_name
## データ圧縮するためのディレクトリ(作業ディレクトリの下で)
arc_base_name=backup_wp_
arc_dir_name=${arc_base_name}${base_datetime}
arc_dir=${work_dir}/${arc_dir_name}
arc_file=${arc_dir}.tar.gz
arc_site_dir=$arc_dir
arc_db_dir=$arc_dir
## 暗号化(暗号化時のみ使用)
# 暗号化キーを格納するファイル名
enc_pass_file=$base_dir/${base_name}_aes.pass
# 暗号化ファイル名
enc_file=${arc_file}.aes
## バックアップデータのアップロード先googleドライブ
# gdriveツールのパス
gd_cmd=${base_dir}/gdrive
# アップロード先フォルダのID
gd_dest_dir_id=bbbbbbbbbb
# バックアップファイルの保持世代
gd_keep_gen=10
let "gd_list_max=gd_keep_gen + 1"
# 既存のバックアップファイルのリストを作成するクエリ
gd_list_query="'$gd_dest_dir_id' in parents"
gd_list_query="$gd_list_query and trashed = false"
gd_list_query="$gd_list_query and name contains '$arc_base_name'"
gd_list_query="$gd_list_query and mimeType != 'application/vnd.google-apps.folder'"
## 関数
function show_dt(){
echo -n "[<code>date '+%Y-%m-%d %H:%M:%S.%3N'</code>]"
}
function info(){
show_dt; echo "(情報): $1"
}
function warn(){
show_dt; echo "(警告): $1" >&2
}
function error(){
show_dt; echo "(エラー): $1" >&2
exit 1
}
# ================================================================================
# メイン処理
# ================================================================================
info "* バックアップを開始します。"
# --------------------------------------------------------------------------------
# バックアップ
# --------------------------------------------------------------------------------
info "* 作業ディレクトリを作成します。: $work_dir"
mkdir -p $work_dir
chmod 700 $work_dir
if [ $? -ne 0 ] ; then
error "作業ディレクトリを作成できません。"
fi
info "* サイトのバックアップデータを作成します..."
mkdir -p $arc_site_dir
cp -rf $site_dir $arc_site_dir
if [ $? -ne 0 ]; then
error "サイトのバックアップに失敗しました。: $site_dir"
fi
info "* DBのバックアップデータを作成します..."
$dump_cmd --defaults-file=$db_config_file $db_name > $arc_db_dir/recovery.sql
if [ $? -ne 0 ]; then
error "DBのバックアップに失敗しました。"
fi
info "* バックアップデータを圧縮します..."
tar cfz $arc_file -C $work_dir $arc_dir_name
if [ $? -ne 0 ]; then
error "バックアップデータの圧縮に失敗しました。"
fi
info "* バックアップデータを暗号化します。: $arc_file"
if [ -f $enc_pass_file ]; then
openssl enc -e -aes-256-cbc -salt -pass file:$enc_pass_file -in $arc_file -out $enc_file
if [ $? -ne 0 ]; then
error "バックアップデータの暗号化に失敗しました。"
fi
out_file=$enc_file
else
info "パスワードファイルが存在しないため暗号化をスキップします。($enc_pass_file)"
out_file=$arc_file
fi
info "* バックアップデータが作成されました。: $out_file"
# --------------------------------------------------------------------------------
# googleドライブへ転送
# --------------------------------------------------------------------------------
info "* バックアップデータをアップロードします。: $out_file"
$gd_cmd upload -p $gd_dest_dir_id $out_file
if [ $? -ne 0 ]; then
error "アップロードに失敗しました。"
fi
# 管理対象世代+1個までのファイルリストを取得、新しいものが上にくるようにソート。
# 一番最後の行のファイルが世代管理対象外のファイルとなるので、その行を取得。
gd_del_file_line=<code>$gd_cmd list --query "$gd_list_query" --order "$gd_list_order" -m $gd_list_max --name-width 0 --no-header | sed -n ${gd_list_max}p</code>
# 当該行からIDを取得する。(当該行がない場合は空)
# もしIDを取得できた場合はそのファイルを削除する。
gd_del_file_id=<code>echo "$gd_del_file_line" | awk '{print $1}' </code>
gd_del_file_name=<code>echo "$gd_del_file_line" | awk '{print $2}' </code>
if [ -n "$gd_del_file_id" ]; then
info "古いバックアップを削除します。: $gd_del_file_name($gd_del_file_id)"
$gd_cmd delete $gd_del_file_id
if [ $? -ne 0 ]; then
warn "古いバックアップの削除に失敗しました。"
fi
fi
# ================================================================================
# 後処理
# ================================================================================
info "* 作業ディレクトリを削除します。: $work_dir"
rm -rf $work_dir
info "* バックアップが正常に完了しました。"
exit 0
# EOF[mysqldump]
user=cccccccccc
password=ddddddddddeeeeeeeeee使い方
バックアップする場合、次のようにbackup2gd_wp.shを実行します。
初回実行時は意図しない設定でデータが消されないよう、スクリプト先頭を”#!/bin/sh -x”にして、デバッグ出力を行いながらパスが正しいかを確認することをお勧めします。この際、スクリプトの最後の方にある削除系コマンドは”#$gd_cmd delete $gd_del_file_id”, “#rm -rf $work_dir”としてコメントアウトした方が安全です。
$ ./backup2gd_wp.sh
[2018-06-17 23:22:06.987](情報): * バックアップを開始します。
[2018-06-17 23:22:06.988](情報): * 作業ディレクトリを作成します。: /tmp/backup2gd_wp.jCg5MhXG
[2018-06-17 23:22:06.992](情報): * サイトのバックアップデータを作成します...
[2018-06-17 23:22:07.319](情報): * DBのバックアップデータを作成します...
[2018-06-17 23:22:07.510](情報): * バックアップデータを圧縮します...
[2018-06-17 23:22:10.896](情報): * バックアップデータを暗号化します。: /tmp/backup2gd_wp.jCg5MhXG/backup_wp_20180617-232206.tar.gz
[2018-06-17 23:22:10.898](情報): パスワードファイルが存在しないため暗号化をスキップします。(./backup2gd_wp_aes.pass)
[2018-06-17 23:22:10.899](情報): * バックアップデータが作成されました。: /tmp/backup2gd_wp.jCg5MhXG/backup_wp_20180617-232206.tar.gz
[2018-06-17 23:22:10.900](情報): * バックアップデータをアップロードします。: /tmp/backup2gd_wp.jCg5MhXG/backup_wp_20180617-232206.tar.gz
Uploading /tmp/backup2gd_wp.jCg5MhXG/backup_wp_20180617-232206.tar.gz
Uploaded xxxxxxxxxxxxxxxxxxx at 7.7 MB/s, total 24.8 MB
[2018-06-17 23:22:15.175](情報): 古いバックアップを削除します。: backup_wp_20180610-045227.tar.gz.aes(xxxxxxxxxxxxxxxxxxxxxxxx)
Deleted 'backup_wp_20180610-045227.tar.gz.aes'
[2018-06-17 23:22:16.009](情報): * 作業ディレクトリを削除します。: /tmp/backup2gd_wp.jCg5MhXG
[2018-06-17 23:22:16.103](情報): * バックアップが正常に完了しました。スクリプトの実行結果を保存できるようlogディレクトリを作成します。
月曜日の朝1時に実行できるよう、次のようにcrontabを設定します。
# mkdir -p /root/opetools/log/
# crontab -e
0 1 * * 1 /root/opetools/bin/backup2gd_wp.sh >> /root/opetools/log/backup2gd_wp.log 2>&1なお、バックアップデータを展開したい場合、次の通りです。
somefileにはパスワードを格納したファイル、file.tar.gz.aesにはバックアップファイル、file.tar.gzには出力先となる任意にファイル名を指定してください。
$ openssl enc -d -aes-256-cbc -salt -pass file:somefile -in file.tar.gz.aes -out file.tar.gz
$ tar xvfz file.tar.gz