WordPressのバックアップのために、よく利用されている「BackWPup」プラグインがあります。
簡単な設定で利用できますので大変便利なのですが、ファイル容量やDB容量が増えてくると時々止まることがあることと、wp-cronで実行しますので、サーバ負荷が心配になってきます。
wp-cronを止めてサーバのcronで動作させれば良いのですが、プラグインだと中身がよくわかっておらず、やはり動作が気になりますので、シェルスクリプト(bash)で実現してみました。
事前作業:SSH認証用の鍵を作成
バックアップ用サーバにはSSH接続することを想定しています。鍵認証であればパスワードを入力する必要はありませんので、まず事前にSSH認証用の鍵を作成します。
鍵作成
ssh-keygenコマンドを実行すると、.sshディレクトリの下に秘密鍵(id_rsa)と公開鍵(id_rsa.pub)のペアが作成されます。
秘密鍵(id_rsa)は機密情報ですので、ファイルパーミッションは最初から600になっています。
1 2 3 4 5 6 7 8 9 10 11 |
$ 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: |
1 2 3 |
$ 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」に、バックアップサーバの情報が書かれますので、次回からは自動的にアクセスできるようになります。
1 2 3 4 5 |
$ 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. |
バックアップスクリプト作成
設定
まずは、スクリプト中で利用する変数の設定です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
#!/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」を実行しています。
コピーしたファイルのうち、バックアップ不要なファイル/ディレクトリは削除します。
1 2 3 4 5 6 7 8 9 10 11 |
# 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ファイルを参照しています。
1 2 3 4 5 6 7 8 9 10 11 |
# 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形式で出力します。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
# 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接続しますので、パスワード入力は必要ありません。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
# 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 } |
作業用ディレクトリの削除
作業用ディレクトリを削除します。
ローカルにバックアップファイルを残さない場合は、そのファイルも削除します。
1 2 3 4 5 6 7 8 |
# delete backup file if [ ${keep_in_local} = FALSE ] then rm -f ${source_filename} fi # remove work directory rm -rf workdir_${datestr} |
ローカルの過去のファイルを削除
ローカルにバックアップファイルを残す設定をしている場合、残すファイル数を超えた分は日付が古いものから削除します。他でも使いまわせるように、関数化しています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
# 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接続にインプットしています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
# 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 |
エラーメールを送信
処理途中でエラーが発生した場合は、指定されたメールアドレスにエラーメールを送信します。
1 2 3 4 5 6 7 8 9 10 |
# 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」というファイル名で作成しました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 |
#!/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で自動起動する設定をします。
1 |
$ crontab -e |
毎週日曜日の午前3時にバックアップする設定です。
また、wp-cron.phpを完全に止めてしまうと、悪影響がある可能性がありますので、10分おきに動かすようにしておきます。
1 2 |
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’, ”);」の下あたりに記述すると良いでしょう。
1 2 3 4 5 6 |
... /** データベースの照合順序 (ほとんどの場合変更する必要はありません) */ define('DB_COLLATE', ''); define('DISABLE_WP_CRON', 'true'); ... |