WordPressのバックアップのために、よく利用されている「BackWPup」プラグインがあります。
簡単な設定で利用できますので大変便利なのですが、ファイル容量やDB容量が増えてくると時々止まることがあることと、wp-cronで実行しますので、サーバ負荷が心配になってきます。
wp-cronを止めてサーバのcronで動作させれば良いのですが、プラグインだと中身がよくわかっておらず、やはり動作が気になりますので、シェルスクリプト(bash)で実現してみました。
事前作業:SSH認証用の鍵を作成
バックアップ用サーバにはSSH接続することを想定しています。鍵認証であればパスワードを入力する必要はありませんので、まず事前にSSH認証用の鍵を作成します。
鍵作成
ssh-keygenコマンドを実行すると、.sshディレクトリの下に秘密鍵(id_rsa)と公開鍵(id_rsa.pub)のペアが作成されます。
秘密鍵(id_rsa)は機密情報ですので、ファイルパーミッションは最初から600になっています。
$ cd ~ $ ssh-keygen Generating public/private rsa key pair. Enter file in which to save the key (/home/user/.ssh/id_rsa): Enter passphrase (empty for no passphrase):何も入力せずリターン Enter same passphrase again:何も入力せずリターン Your identification has been saved in /home/user/.ssh/id_rsa. Your public key has been saved in /home/user/.ssh/id_rsa.pub. The key fingerprint is: 2b:46:fb:9f:d9:ec:3d:84:c8:54:8d:5a:34:ca:xx:xx user@hostname The key's randomart image is:
$ ls -l .ssh -rw------- 1 user user 1675 Sep 2 19:03 id_rsa -rw-r--r-- 1 user user 412 Sep 2 19:03 id_rsa.pub
バックアップサーバに公開鍵を配置
バックアップ先サーバの「.ssh/authorized_keys」ファイルに「id_rsa.pub」の内容を追加します。
バックアップサーバにSSH接続
初めてSSH接続する際には、プロンプト画面が出ますので、一回だけ手動でSSH接続します。
そうすると、「.ssh/known_hosts」に、バックアップサーバの情報が書かれますので、次回からは自動的にアクセスできるようになります。
$ ssh -i ~/.ssh/id_rsa backupuser@bkup.domain The authenticity of host 'bkup.domain (xxx.xxx.xxx.xxx)' can't be established. RSA key fingerprint is 74:36:0f:2b:4f:e0:2b:1b:96:c5:54:9a:e8:b4:30:9e. Are you sure you want to continue connecting (yes/no)? yes Warning: Permanently added 'bkup.domain,xxx.xxx.xxx.xxx' (RSA) to the list of known hosts.
バックアップスクリプト作成
設定
まずは、スクリプト中で利用する変数の設定です。
#!/bin/bash # settings wordpress_name=my_wordpress # バックアップファイルの名前の先頭文字列 wordpress_dir=/var/www/html/wordpress # WordPressが置かれているディレクトリ dest_user=backupuser # バックアップ先のログインユーザー名 dest_ip=xxx.xxx.xxx.xxx # バックアップ先のIPアドレス dest_dir=./backup_dir/ # バックアップ先のディレクトリ名 mairaddr=mailaddress@domain # エラー送信用メールアドレス number_of_file_to_keep=15 # 残しておく過去のファイル数 keep_in_local=FALSE # ローカルに保存するか datestr=`date +%Y%m%d-%H%M%S` # バックアップファイルの名前に付与する時刻 STATUS=0 # エラーステータス(0:エラーなし、1:エラーあり)
それぞれの環境に合わせてください。「dest_ip」はホスト名でも設定可能です。
WordPressファイルのコピー
作業用に、「workdir_{日付}」というディレクトリを作成します。さらに、その下に「wordpress」というディレクトリを作成します。
WordPressのファイル一式をコピーします。
普通にコピーするとファイルの属性を引き継げなかったため、「shopt -s dotglob」を実行しています。
コピーしたファイルのうち、バックアップ不要なファイル/ディレクトリは削除します。
# copy wordpress files and remove unnecessary files mkdir workdir_${datestr} cd workdir_${datestr} mkdir wordpress shopt -s dotglob cp -pr ${wordpress_dir}/* wordpress/ cd wordpress rm -rf ./wp-content/cache/* rm -rf ./wp-content/upgrade/* rm -rf ./wp-content/uploads/backwpup* cd ..
データベースのエクスポート
WordPressのデータベースをエクスポートし圧縮します。
データベースのホスト、名前、ユーザー名、パスワードは、wp-config.phpファイルを参照しています。
# export database wordpress_config=${wordpress_dir}/wp-config.php wordpress_db_name=`grep 'DB_NAME' ${wordpress_config} | cut -d "'" -f4` wordpress_db_user=`grep 'DB_USER' ${wordpress_config} | cut -d "'" -f4` wordpress_db_password=`grep 'DB_PASSWORD' ${wordpress_config} | cut -d "'" -f4` eval "mysqldump -u ${wordpress_db_user} -p${wordpress_db_password} ${wordpress_db_name} | gzip -c > wordpress_${datestr}.sql.gz" if [ $? -ne 0 ] then echo "[ERROR]mysqldump error." STATUS=1 fi
ファイルとデーターベースを一まとめにする
WordPressファイル一式とデータベースを一まとめにして、backupディレクトリに、.tar.gz形式で出力します。
# create wordpress file cd .. if [ ! -e backup ] then mkdir backup fi source_filename=./backup/${wordpress_name}_${datestr}.tar.gz eval "tar czf ${source_filename} workdir_${datestr}/*" if [ $? -ne 0 ] then echo "[ERROR]tar error." STATUS=1 fi
バックアップサーバにコピー
バックアップサーバに接続してコピーします。他でも使いまわせるように、関数化しています。
事前に準備しておいた鍵を利用して、鍵認証でSSH接続しますので、パスワード入力は必要ありません。
# copy backup file to backup server scpfile ${source_filename} ${dest_dir}/ # function : execute scp # $1 copy source file name # $2 copy destination file name function scpfile(){ eval "scp -i ~/.ssh/id_rsa $1 ${dest_user}@${dest_ip}:$2" if [ $? -ne 0 ] then echo "[ERROR]scp error. file=$1" STATUS=1 fi return }
作業用ディレクトリの削除
作業用ディレクトリを削除します。
ローカルにバックアップファイルを残さない場合は、そのファイルも削除します。
# delete backup file if [ ${keep_in_local} = FALSE ] then rm -f ${source_filename} fi # remove work directory rm -rf workdir_${datestr}
ローカルの過去のファイルを削除
ローカルにバックアップファイルを残す設定をしている場合、残すファイル数を超えた分は日付が古いものから削除します。他でも使いまわせるように、関数化しています。
# delete old files if [ ${keep_in_local} = TRUE ] then deletefile "backup/${wordpress_name}_" fi # function : delete old files # $1: file path to delete function deletefile(){ CNT=0 for file in `ls -1t ${1}*` # make file list by date order do CNT=$((CNT+1)) if [ ${CNT} -le ${number_of_file_to_keep} ] # delete files which older than 10 generations then continue fi eval "rm ${file}" done return }
リモートの過去のバックアップファイルを削除
バックアップサーバにSSH接続して、ローカルと同様に、残すファイル数を超えた分は日付が古いものから削除します。
リモートサーバで実行するスクリプトを、いったん「delete_remote_files.sh」というファイルに出力したうえで、そのスクリプトをSSH接続にインプットしています。
# delete remote old files echo ' cd backup_dir CNT=0 for file in `ls -1t '${wordpress_name}'_*` # 日付順にファイルリスト作成 do CNT=$((CNT+1)) if [ ${CNT} -le '${number_of_file_to_keep}' ] # 指定された数より古いファイルを削除 then continue fi eval "rm ${file}" done ' > delete_remote_files.sh ssh ${dest_user}@${dest_ip} 'bash -s' < delete_remote_files.sh
エラーメールを送信
処理途中でエラーが発生した場合は、指定されたメールアドレスにエラーメールを送信します。
# send result if [ ${STATUS} -ne 0 ] then SUBJECT="[ERROR]wordpress backup report" echo "" | mail -s "${SUBJECT}" "${mailaddr}" else SUBJECT="[SUCCESS]wordpress backup report" fi exit ${STATUS}
全体
スクリプト全体です。
「/home/user/scripts」ディレクトリに、「wordpress_backup.sh」というファイル名で作成しました。
#!/bin/bash # settings wordpress_name=my_wordpress wordpress_dir=/var/www/html/wordpress dest_user=backupuser dest_ip=xxx.xxx.xxx.xxx dest_dir=./backup_dir/ mairaddr=mailaddress@domain number_of_file_to_keep=15 keep_in_local=FALSE datestr=`date +%Y%m%d-%H%M%S` STATUS=0 # function : execute scp # $1 copy source file name # $2 copy destination file name function scpfile(){ eval "scp -i ~/.ssh/id_rsa $1 ${dest_user}@${dest_ip}:$2" if [ $? -ne 0 ] then echo "[ERROR]scp error. file=$1" STATUS=1 fi return } # function : delete old files # $1: file path to delete function deletefile(){ CNT=0 for file in `ls -1t ${1}*` # make file list by date order do CNT=$((CNT+1)) if [ ${CNT} -le ${number_of_file_to_keep} ] # delete files which older than 10 generations then continue fi eval "rm ${file}" done return } # MAIN # copy wordpress files and remove unnecessary files mkdir workdir_${datestr} cd workdir_${datestr} mkdir wordpress shopt -s dotglob cp -pr ${wordpress_dir}/* wordpress/ cd wordpress rm -rf ./wp-content/cache/* rm -rf ./wp-content/upgrade/* rm -rf ./wp-content/uploads/backwpup* cd .. # export database wordpress_config=${wordpress_dir}/wp-config.php wordpress_db_name=`grep 'DB_NAME' ${wordpress_config} | cut -d "'" -f4` wordpress_db_user=`grep 'DB_USER' ${wordpress_config} | cut -d "'" -f4` wordpress_db_password=`grep 'DB_PASSWORD' ${wordpress_config} | cut -d "'" -f4` eval "mysqldump -u ${wordpress_db_user} -p${wordpress_db_password} ${wordpress_db_name} | gzip -c > wordpress_${datestr}.sql.gz" if [ $? -ne 0 ] then echo "[ERROR]mysqldump error." STATUS=1 fi # create wordpress file cd .. if [ ! -e backup ] then mkdir backup fi source_filename=./backup/${wordpress_name}_${datestr}.tar.gz eval "tar czf ${source_filename} workdir_${datestr}/*" if [ $? -ne 0 ] then echo "[ERROR]tar error." STATUS=1 fi # copy backup file to backup server scpfile ${source_filename} ${dest_dir}/ # delete backup file if [ ${keep_in_local} = FALSE ] then rm -f ${source_filename} fi # remove work directory rm -rf workdir_${datestr} # delete old files if [ ${keep_in_local} = TRUE ] then deletefile "backup/${wordpress_name}_" fi # delete remote old files echo ' cd WEB/effata CNT=0 for file in `ls -1t '${wordpress_name}'_*` do CNT=$((CNT+1)) if [ ${CNT} -le '${number_of_file_to_keep}' ] then continue fi eval "rm ${file}" done ' > delete_remote_files.sh ssh ${dest_user}@${dest_ip} 'bash -s' < delete_remote_files.sh # send result if [ ${STATUS} -ne 0 ] then SUBJECT="[ERROR]wordpress backup report" echo "" | mail -s "${SUBJECT}" "${mailaddr}" else SUBJECT="[SUCCESS]wordpress backup report" fi exit ${STATUS}
cron設定
最後に、cronで自動起動する設定をします。
$ crontab -e
毎週日曜日の午前3時にバックアップする設定です。
また、wp-cron.phpを完全に止めてしまうと、悪影響がある可能性がありますので、10分おきに動かすようにしておきます。
0 3 * * 0 cd /home/user/scripts; ./wordpress_backup.sh > /dev/null 2>&1 */10 * * * * /usr/bin/php /var/www/html/wordpress/wp-cron.php > /dev/null 2>&1
wp-config.phpファイルを編集して、wp-cronを止めておきます。
「define(‘DB_COLLATE’, ”);」の下あたりに記述すると良いでしょう。
... /** データベースの照合順序 (ほとんどの場合変更する必要はありません) */ define('DB_COLLATE', ''); define('DISABLE_WP_CRON', 'true'); ...