サイトの中で、サーバー上にあるものが正になってるコンテンツが怖いので、バックアップをDropboxに上げるスクリプトを書いてみました。


要件は以下の通りです。

  • バックアップ対象のファイルを、現在日時をファイル名にしたzipで固める。
  • Dropboxの所定のディレクトリにそのzipをアップロードする。
  • cronで毎日実行できるような作りにする。

Dropboxにアップロードするところは、今回は練習のためにNode.jsで作りました。

なお、Dropbox APIを使うためには、あらかじめDropboxアプリを用意しておく必要があります。今回はこれ専用にアプリ登録してきました。好きなところにファイルをアップロードしたいので、Permission typeは『Full Dropbox』を選択します。アプリ管理画面の『Generated access token』からアクセストークンを発行すれば準備完了です。

Dropboxの準備ができたら、シェルを書きます。

backup.sh
#!/bin/sh
cd `dirname $0`

# 日次でファイル名作成
today=$(date "+%Y%m%d%H%M%S")
zipname=${today}.zip

# 日次のフォルダにバックアップ対象のファイルをコピー
sudo mkdir ${today}
sudo cp /path/to/file1 ${today}/file1
sudo cp -r /path/to/dir1 ${today}/dir1

# zipでまとめる (mオプションで元のファイルは消える)
sudo zip -rm ${zipname} ${today}

# Dropboxにアップロード
sudo node upload_to_dropbox.js ${zipname}
ret=$?
if [ ${ret} -eq 0 ]; then
	exit ${ret};  # リターンコードが0 (正常終了) 以外なら抜ける
fi

# 送信完了したらzip削除
sudo rm ${zipname}

あんまりシェル書いたことないからわからないんですけど、こんなに sudo って書くもんなんでしょうか?

次に、シェル中で実行してる upload_to_dropbox.js を作ります。これは引数でファイル名 (ここでは固めたzipファイル名) を受け取って、当該のファイルをDropboxの所定のディレクトリにアップロードするスクリプトです。

今回はDropboxの /kiriukun.com/backup/ ディレクトリ以下にバックアップファイルを上げるように作りました。詳しいことは、Dropbox APIのリファレンスを見てください。前に触ったきりだから忘れちゃった😞

upload_to_dropbox.js
const fs = require('fs');
const path = require('path');
const request = require('request');

const token = 'Dropboxのアプリ管理画面で発行したアクセストークン';
const remoteDir = '/kiriukun.com/backup/';

const abort = () => {
	console.error.apply(console, arguments);
	process.exit(1);
};

// 引数でファイル名指定されてるか確認
if (process.argv.length < 3) {
	abort('ファイル名が指定されていません。');
}

// ローカルファイルパス取得
const filename = process.argv[2];
const localPath = path.join(process.cwd(), filename);
if (!fs.existsSync(localPath)) {
	abort('ファイルが見つかりませんでした。', localPath);
}

// ローカルファイル読み込み
fs.readFile(localPath, (error, data) => {
	if (error) {
		abort('ファイル読み込み中にエラー!', error);
	}
	
	// Dropboxにアップロード
	request({
		url: 'https://content.dropboxapi.com/2/files/upload',
		method: 'POST',
		headers: {
			'Authorization': 'Bearer '+ token,
			'Content-type': 'application/octet-stream',
			'Dropbox-API-Arg': JSON.stringify({
				path: remoteDir + filename,
				mode: 'overwrite',
			}),
		},
		encoding: null, // バイナリデータの場合はencodingにnullを指定
		body: data,
	}, (error, response, body) => {
		if (error) {
			abort('POST中にエラー!', error);
		}
		
		// ステータスコードが200以外なら失敗
		if (response.statusCode != 200) {
			// encodingがnullだとレスポンスがBufferなので文字列にする
			abort('Dropbox APIでエラー!', body.toString('utf8'));
		}
	});
});

初心者なので色々不安ですが、とりあえず動きました。あとは、最初に作ったシェルをcronで毎日実行すればOKです。

でもこれ、エラー時にzipファイルが溜まっていくところとか微妙だな🤔どうしようかな。

参考にさせていただいた記事