このブログはさくらのVPS上に自前で構築したWordpressで稼働していて、同じVPS内にもうひとつのWordpressも稼働しています。この状況でデータベース・プラグイン・テーマ・画像といった全コンテンツの定期バックアップをとりかったのですが、お金がかからないこと(※Dropbox代はのぞく)も含めると、意外と適切な既存のソリューションがなかったため、自前で作ってしまいました。
似た状況の中では使えるかもしれないのでMITライセンスでOSS化します。
-
状況
-
VPS上の自前構築のwordpress
- MySQLを使用
- root権限がとれる
-
/var/www/にwordpressインスタンスがある(複数可)
- 複数の場合、マルチサイトではない。単に別のWordpressインスタンスが同居しているだけ
- cronなどの設定ができる
-
VPS上の自前構築のwordpress
-
前提
-
Dropbox個人アカウント
- 法人だとquotaを使い潰すのであんまりお勧めしないです
- サーバにシェルで入ってメンテナンスできる程度には技術がちゃんとある人
- 今回紹介するコードを読んで何してるかわかる程度には技術がちゃんとある人
- 必要な技術がない人は、この方法には絶対に手を出さないほうがいいです
-
Dropbox個人アカウント
目次
なおサービスとオペレーションの行き届いたホスティングサービスとかでなく野良Wordpressでやってる理由については聞かないお約束です。
これまでに試したソリューション
Borg
BorgBackup – Deduplicating archiver with compression and authenticated encryption
ファイル群の効率的な差分バックアップを実現するツールです。
WordPressプラグインではありません。Cronで(1)データベース(のダンプ)・plugins・uploads・themesを$HOMEにコピーし、(2)その変更をBorgにトラックさせ差分バックアップをとる、という処理を行います。
Borgは非常によくできたツールで信頼でき、用途によってはとても便利です。ただしVPS上で動く野良のwordpressをバックアップする用途では、次のような問題がありました。
-
バックアップデータの置き場所をどうする問題
- 同じサーバ上に置いていてもバックアップの意味がない
- BorgはPOSIXファイルシステムのみサポートなので、VPSの場合はNFSを別途借りるなどする必要があった
-
/var/www内のインスタンス・それを$HOMEにコピーしたバックアップ対象データ・バックアップの3つ分の容量を食う
- 特にサイトのデータ量が多い(写真が多いなど)場合はサーバの少ないSSDを食いつぶす
UpdraftPlus
The World's Most Trusted WordPress Backup Plugin – UpdraftPlus
使いやすいUI、画面上でバックアップから復元まで完結できる使いやすさが最大のメリットです。Dropbox以外もサポートされています。ほとんどの場合はこのプラグインで十分だと思いますし明確で強い理由がなければこういったツールを使うべきだと思います。
しかし自分の場合は
- 処理がやたらと遅いこと(このブログで実装した手法より数倍時間がかかる)
- 複数のWordpressインスタンスのバックアップがDropboxの同じ場所にとっ散らかってって識別できる情報がない。復元時に事故る気しかしないので使えない
一部は無料版の制約なので、有料化すれば回避できる点もあります。
Dropboxクライアントをサーバに導入しマウント
DropboxではLinuxで使えるCLIなクライアントが提供されています。
[Linux で Dropbox を利用する:ソース、コマンド、リポジトリからのインストール | Dropbox ヘルプ:title=https://help.dropbox.com/ja-jp/installs-integrations/desktop/linux-commands]
これを使えば、cronで行うのは単にDBのダンプ・plugins・themes・uploadsを同期対象ディレクトリに退避するだけですみます。それをtarで固めたものをlogrotateすれば同期は全部Dropboxクライアントに任せられます。
一方で、
- そもそもあまり余計なツールをWebサーバに入れたくない
-
Dropboxのローカルコピーによるデータ消費
- Dropbox全体が同期されてしまうことは選択型同期によって回避できるが、バックアップ対象データによるローカルディスク消費自体は避けられない
-
Dropboxのファイルサイズ制限
- まぁ、splitコマンドでおk
- ただsplitとlogrotateの併用はかなり複雑で事故りそう
要求
これまでWordpressを10年ぐらい運用&バックアップしてきた経験全体を踏まえて整理すると、自分の場合は次のようなバックアップ方法が欲しいとわかってきました。
- Dropboxを使えること(Premiumアカウントを持っていて空き容量が豊富なため)
- 複数のWordpressインスタンスのバックアップがDropbox上でちゃんと別れて保存されること
- バックアップやその処理のためにサーバのローカルディスクを追加で消費しないこと
- ログローテート(古いバックアップが自動で消えること)
一方、一般によく言われる次のような要件は特にありませんでした。
- プラグインとして動作し、復元からバックアップまで全て画面上で完結すること
今回開発したwp-backup-dropbox
今回開発したCLI専用のWordpress to Dropboxバックアップscriptがこちらです。
https://github.com/belltailjp/wp-backup-dropbox
WordPressが稼働するサーバにSSHで入って次のようなコマンドを実行することでバックアップがとれます。
# バックアップ実行方法 $ export DROPBOX_TOKEN=aaaaaa SLACK_TOKEN=bbbbbb SLACK_CHANNEL=cccccc DATABASE_USER=dddddd DATABASE_PASSWORD=eeeeee $ bash wp_backup.sh site-xxx /site-xxx # 復元実行方法 $ export DROPBOX_TOKEN=aaaaaa DATABASE_USER=dddddd DATABASE_PASSWORD=eeeeee $ sudo bash restore_wp_backup.sh site-xxxx /site-xxxx/backup-20200507-1950
バックアップ処理の実行中には、Slackに進捗状況が細かく報告されます。
たぶんよく訓練されたエンジニアなら自分専用のSlackワークスペースぐらいもっていると思うので(煽り)、そこにチャンネルを作ってログを流すとよいでしょう。
機能
バックアップに関しては次の機能を持っています:
- /var/www/site-xxxにあるWordpressインスタンスのデータベース・uploads・themes・pluginsを1つのtar.gzファイルに固めて、Dropbox内にbackup-yyyymmdd-hhmmというフォルダ名でアップロード
- Dropboxの単一ファイルサイズ制限(10GB)を越えそうな場合は自動で分割して保存
- 復元方法がわかるようにDropbox内のバックアップディレクトリに簡単な説明書きを残す
- Dropbox上でバックアップ数が一定の数(デフォルト5)を超えると古いものを削除
- 作業の進捗状況をSlackに通知
なおSlackのログが不要であれば、この部分を単純に削除すればOKです。
また復元に関しては次の機能を持っています:
- Dropbox上に作られたバックアップディレクトリを指定すると、アーカイブをダウンロード(分割された場合は自動で連結)・展開し、適切な場所に配置する
- あるいは、同じ要領で作られたバックアップアーカイブファイル(tar.gz)からの復元(Dropbox経由でない復元をしたいとき)
- データベースをバックアップから復元する
復元時はSlack通知はありません。
バックアップおよび復元の処理においては、次のような点に留意して実装されています
-
データの収集・圧縮・Dropboxへの転送の全てにわたって、パイプ処理を使用することでローカルディスク上に作業領域を一切消費しない(データベースのダンプファイル分だけ使います)
- なのでコンテンツが膨大でサーバのディスク使用率が95%とかになっていてもバックアップ処理は問題なく進みます
- 復元時もダウンロードしたデータを端から順に展開し配置することで、追加ディスク消費なし
- Dropbox API呼び出しの結果を精査する(ハッシュのチェックなど)ことで十分な信頼性を確保
このコードを動かすためには、下記の準備が必要です。
- 復元時はroot(sudo)が必要
- サーバにbash、Python3が入っており、pipでrequestsとtqdmがインストールされていること
- Dropboxの開発者ツールでappを作成、APIトークンをDROPBOX_TOKEN環境変数にセット
- Slackの開発者ツールでappを作成、APIトークンをSLACK_TOKEN環境変数にセット
- Slackの投稿先チャネルのIDをSLACK_CHANNEL環境変数にセット
- データベースのユーザ名をDATABASE_USER、パスワードをDATABASE_PASSWORD環境変数にセット
技術リファレンス
- Dropbox API: https://www.dropbox.com/developers/documentation/http/documentation
- Slack API: https://api.slack.com/methods