もしもに備えて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を配置する。
- 下記を実行する。123$ 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に暗号化のためのパスワードを指定します。(暗号化したくない場合、このファイルは削除してください。)
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 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 | #!/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 base_name=<code>basename $0 .sh base_datetime=<code>date "+%Y%m%d-%H%M%S" ## バックアップ対象サイトのディレクトリ 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 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 # 当該行からIDを取得する。(当該行がない場合は空) # もしIDを取得できた場合はそのファイルを削除する。 gd_del_file_id=<code>echo "$gd_del_file_line" | awk '{print $1}' gd_del_file_name=<code>echo "$gd_del_file_line" | awk '{print $2}' 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 |
1 2 3 | [mysqldump] user=cccccccccc password=dddddddddd |
1 | eeeeeeeeee |
使い方
バックアップする場合、次のようにbackup2gd_wp.shを実行します。
初回実行時は意図しない設定でデータが消されないよう、スクリプト先頭を”#!/bin/sh -x”にして、デバッグ出力を行いながらパスが正しいかを確認することをお勧めします。この際、スクリプトの最後の方にある削除系コマンドは”#$gd_cmd delete $gd_del_file_id”, “#rm -rf $work_dir”としてコメントアウトした方が安全です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | $ ./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を設定します。
1 2 3 | # 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には出力先となる任意にファイル名を指定してください。
1 2 | $ openssl enc -d -aes-256-cbc -salt -pass file:somefile -in file.tar.gz.aes -out file.tar.gz $ tar xvfz file.tar.gz |