



WithCodeMedia-1-pc
WithCodeMedia-2-pc
WithCodeMedia-3-pc
WithCodeMedia-4-pc




WithCodeMedia-1-sp
WithCodeMedia-2-sp
WithCodeMedia-3-sp
WithCodeMedia-4-sp









生徒先月、サーバーがクラッシュしてクライアントのWebサイトのデータが全部消えちゃって…。バックアップ取ってなかったんです…



それは大変じゃったな…。Web制作者にとって、バックアップは命綱なんじゃ。今日は「3-2-1-1-0ルール」という、世界標準のバックアップ戦略を詳しく教えるぞい!
結論:Web制作者が実践すべきバックアップは「3-2-1-1-0ルール」です。データを3つコピーし、2種類のメディアに保存、1つをオフサイトに置き、1つをイミュータブル(削除不可)にし、0エラーで定期検証する——この5原則を守ることで、ランサムウェア攻撃やサーバー障害からも完全復旧が可能になります。
米国国土安全保障省(CISA)やストレージ業界が推奨するこのルールを、Web制作の現場に特化した形で解説します。今日からすぐ実践できる自動化スクリプト・ツール・コスト最適化まで網羅しています。


実例: 納品前日にMacBookが起動しなくなり、3週間分のデザインデータが消失。Time Machineバックアップもなく、クライアントへの納期が1ヶ月延期に。
rm -rfコマンドの実行ミスで本番データを削除DELETE FROM users;(WHERE句なし)で全データ削除git push --forceで重要なコミット履歴を削除実例: データベースの管理画面で顧客テーブルを削除するつもりが、本番環境に接続していて5,000件の顧客データが消失。バックアップなしで復旧不可能に。
実例: WordPressサイトがランサムウェアに感染。バックアップもネットワーク上にあったため同時に暗号化され、復旧に100万円以上のコストがかかった。
| 損失の種類 | 具体例 | 金額的影響 |
|---|---|---|
| 直接的損失 | 制作データの再作成、復旧作業費用 | 50万〜500万円 |
| 機会損失 | 納期遅延によるペナルティ、新規案件の受注不可 | 100万〜1,000万円 |
| 信用損失 | クライアントからの信頼喪失、悪評拡散 | 測定不能(致命的) |
米国の調査によると、データを完全に失った企業の60%は2年以内に廃業しています。Web制作者にとって、バックアップは単なる「念のため」ではなく、ビジネス継続の生命線です。





3-2-1ルールって、何の数字なんですか?



いい質問じゃ!3-2-1は、バックアップの「3つの黄金ルール」を数字で表したものなんじゃ。一つずつ詳しく見ていくぞい!
意味: 本番データ1つ + バックアップ2つ = 合計3つのコピー
# 実際のディレクトリ構成例
/var/www/html/ # 本番データ
/backup/daily/website/ # バックアップ1(同サーバー)
s3://my-backup/website/ # バックアップ2(AWS S3)意味: 異なる種類のストレージデバイスを使用する
| メディアタイプ | 具体例 | 特徴 |
|---|---|---|
| HDD(ハードディスク) | 内蔵HDD、外付けHDD | 大容量、低コスト、機械的故障リスクあり |
| SSD | 内蔵SSD、外付けSSD | 高速、耐衝撃性高い、高コスト |
| クラウドストレージ | AWS S3、Google Cloud Storage、Azure Blob | 遠隔地保管、高可用性、月額課金 |
| NAS | Synology、QNAP | ネットワーク経由でアクセス、RAID構成可 |
| テープストレージ | LTO(Linear Tape-Open) | 大容量、長期保存、アクセス速度遅い |
同じ種類のメディアだと、同じ原因で同時に故障するリスクがあります:
意味: 物理的に離れた場所にバックアップを保管する
| 保管場所 | バックアップの種類 | 頻度 |
|---|---|---|
| オンサイト(本番サーバー) | 日次バックアップ | 毎日 |
| オンサイト(NAS) | 週次バックアップ | 毎週 |
| オフサイト(AWS S3 東京) | 月次バックアップ | 毎月 |
| オフサイト(AWS S3 大阪) | 四半期バックアップ | 3ヶ月ごと |
3-2-1ルールはランサムウェアの普及に対応するため、2つの要素が追加され「3-2-1-1-0ルール」に進化しました。
| 要素 | 内容 | 目的 |
|---|---|---|
| 3 | データのコピーを3つ持つ | 冗長性確保 |
| 2 | 2種類の異なるメディアに保存 | 同時故障リスク回避 |
| 1 | 1つをオフサイトに保管 | 災害対策 |
| 1(追加) | 1つをイミュータブル/オフラインに保管 | ランサムウェア対策 |
| 0(追加) | 0エラー:定期的に復元テストを実施 | 復元確実性の担保 |
イミュータブルバックアップとは、一定期間内は削除・変更が物理的に不可能なバックアップです。ランサムウェアに感染しても改ざんされません。
バックアップの約30%は何らかの理由で復元に失敗します。「0エラー」とは、バックアップが確実に復元できることを定期的に検証する仕組みです。
まず何をバックアップするかを明確にします。Web制作で必要なバックアップ対象は以下の通りです。
| バックアップ対象 | 場所 | 優先度 | 更新頻度 |
|---|---|---|---|
| Webサイトファイル | /var/www/html/ | 最高 | 随時 |
| データベース(MySQL/MariaDB) | DBサーバー | 最高 | 随時 |
| サーバー設定ファイル | /etc/nginx/, /etc/apache2/ | 高 | 変更時 |
| SSL証明書 | /etc/letsencrypt/ | 高 | 更新時 |
| Cronジョブ設定 | /etc/cron.d/ | 中 | 変更時 |
| ローカル開発ファイル | Mac/Windows | 高 | 随時 |
サーバー内に毎日自動でバックアップを作成するスクリプトです。
#!/bin/bash
# /usr/local/bin/daily-backup.sh
# Web制作用日次バックアップスクリプト
# ========== 設定 ==========
BACKUP_ROOT="/backup/daily"
WEB_DIR="/var/www/html"
DB_HOST="localhost"
DB_USER="backup_user"
DB_PASS="your-password" # 本番では環境変数または.my.cnfから読む
DATABASES=("wordpress_db" "client1_db" "client2_db")
RETENTION_DAYS=30
SLACK_WEBHOOK="https://hooks.slack.com/services/YOUR/WEBHOOK/URL"
LOG_FILE="/var/log/backup.log"
# ========== 関数 ==========
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a ${LOG_FILE}
}
notify_slack() {
local status=$1
local message=$2
curl -s -X POST -H 'Content-type: application/json' \
--data "{\"text\": \"${status} ${message}\"}" \
${SLACK_WEBHOOK}
}
# ========== メイン処理 ==========
BACKUP_DATE=$(date +%Y%m%d-%H%M%S)
BACKUP_DIR="${BACKUP_ROOT}/${BACKUP_DATE}"
log "=== バックアップ開始: ${BACKUP_DATE} ==="
mkdir -p ${BACKUP_DIR}
# 1. Webファイルのバックアップ
log "Webファイルをバックアップ中..."
tar -czf ${BACKUP_DIR}/website-files.tar.gz \
--exclude="${WEB_DIR}/wp-content/cache/*" \
--exclude="${WEB_DIR}/node_modules/*" \
${WEB_DIR}
if [ $? -eq 0 ]; then
log "✅ Webファイル: 完了"
else
log "❌ Webファイル: 失敗"
notify_slack "❌ エラー" "日次バックアップ失敗(Webファイル)"
exit 1
fi
# 2. データベースのバックアップ
log "データベースをバックアップ中..."
for DB in "${DATABASES[@]}"; do
mysqldump \
--single-transaction \
--quick \
--lock-tables=false \
-h ${DB_HOST} \
-u ${DB_USER} \
-p${DB_PASS} \
${DB} | gzip > ${BACKUP_DIR}/${DB}.sql.gz
if [ $? -eq 0 ]; then
log "✅ データベース ${DB}: 完了"
else
log "❌ データベース ${DB}: 失敗"
notify_slack "❌ エラー" "日次バックアップ失敗(DB: ${DB})"
exit 1
fi
done
# 3. サーバー設定のバックアップ
log "サーバー設定をバックアップ中..."
tar -czf ${BACKUP_DIR}/server-config.tar.gz \
/etc/nginx \
/etc/apache2 \
/etc/letsencrypt \
/etc/cron.d \
2>/dev/null
# 4. チェックサム生成
log "チェックサムを生成中..."
cd ${BACKUP_DIR}
sha256sum *.tar.gz *.sql.gz > checksums.txt 2>/dev/null
# 5. 古いバックアップを削除
log "古いバックアップを削除中..."
find ${BACKUP_ROOT} -maxdepth 1 -type d -mtime +${RETENTION_DAYS} -exec rm -rf {} \;
BACKUP_SIZE=$(du -sh ${BACKUP_DIR} | cut -f1)
log "=== バックアップ完了: ${BACKUP_SIZE} ==="
notify_slack "✅ 完了" "日次バックアップ完了(${BACKUP_SIZE})"# /etc/cron.d/daily-backup
0 3 * * * root nice -n 19 ionice -c 3 /usr/local/bin/daily-backup.shAWS S3にバックアップをアップロードし、オフサイト保管を実現します。
#!/bin/bash
# /usr/local/bin/backup-to-s3.sh
# S3へのバックアップアップロード
S3_BUCKET="s3://my-website-backup"
BACKUP_ROOT="/backup/daily"
RETENTION_DAYS=90
# 最新のバックアップをS3にアップロード
LATEST_BACKUP=$(ls -td ${BACKUP_ROOT}/*/ | head -1)
BACKUP_NAME=$(basename ${LATEST_BACKUP})
log "S3にアップロード中: ${BACKUP_NAME}"
aws s3 sync ${LATEST_BACKUP} ${S3_BUCKET}/${BACKUP_NAME}/ \
--storage-class STANDARD_IA \
--sse AES256
if [ $? -eq 0 ]; then
log "✅ S3アップロード: 完了"
else
log "❌ S3アップロード: 失敗"
exit 1
fi事前準備:
ポイント: S3のストレージクラスを適切に設定することで、バックアップコストを最大90%削減できます。
ランサムウェア対策として、削除・変更不可能なバックアップを作成します。
#!/bin/bash
# S3イミュータブルバックアップの設定
BUCKET_NAME="my-immutable-backup"
REGION="ap-northeast-1"
RETENTION_DAYS=90
# 1. オブジェクトロック有効化でバケット作成
aws s3api create-bucket \
--bucket ${BUCKET_NAME} \
--region ${REGION} \
--create-bucket-configuration LocationConstraint=${REGION} \
--object-lock-enabled-for-bucket
# 2. バケットのオブジェクトロック設定
aws s3api put-object-lock-configuration \
--bucket ${BUCKET_NAME} \
--object-lock-configuration '{
"ObjectLockEnabled": "Enabled",
"Rule": {
"DefaultRetention": {
"Mode": "COMPLIANCE",
"Days": '$RETENTION_DAYS'
}
}
}'
# 3. バケットポリシーで削除を禁止
cat > bucket-policy.json << EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Deny",
"Principal": "*",
"Action": [
"s3:DeleteBucket",
"s3:DeleteObject",
"s3:DeleteObjectVersion"
],
"Resource": [
"arn:aws:s3:::${BUCKET_NAME}",
"arn:aws:s3:::${BUCKET_NAME}/*"
]
}
]
}
EOF
aws s3api put-bucket-policy \
--bucket ${BUCKET_NAME} \
--policy file://bucket-policy.json
echo "✅ イミュータブルバックアップバケット作成完了"#!/bin/bash
# エアギャップバックアップ(週次実行)
BACKUP_DATE=$(date +%Y%m%d)
SOURCE_DIR="/backup/daily"
EXTERNAL_HDD="/mnt/external-hdd"
BACKUP_NAME="weekly-backup-${BACKUP_DATE}"
# 1. 外付けHDDを検出
echo "外付けHDDを接続してください..."
while [ ! -b /dev/sdb1 ]; do
sleep 5
done
# 2. マウント
mount /dev/sdb1 ${EXTERNAL_HDD}
echo "✅ 外付けHDD マウント完了"
# 3. 最新の週次バックアップを作成
LATEST_BACKUP=$(ls -td ${SOURCE_DIR}/*/ | head -1)
tar -czf ${EXTERNAL_HDD}/${BACKUP_NAME}.tar.gz ${LATEST_BACKUP}
# 4. チェックサム生成
cd ${EXTERNAL_HDD}
sha256sum ${BACKUP_NAME}.tar.gz > ${BACKUP_NAME}.sha256
# 5. バックアップログ更新
echo "${BACKUP_DATE}: ${BACKUP_NAME}.tar.gz" >> ${EXTERNAL_HDD}/backup-log.txt
# 6. アンマウント
umount ${EXTERNAL_HDD}
# 7. 通知
echo "✅ エアギャップバックアップ完了"
echo "外付けHDDを取り外して、金庫に保管してください。"
# Slack通知
curl -X POST -H 'Content-type: application/json' \
--data "{
\"text\": \"✅ 週次エアギャップバックアップ完了\",
\"attachments\": [{
\"color\": \"good\",
\"text\": \"外付けHDDを取り外して、金庫に保管してください。\"
}]
}" \
https://hooks.slack.com/services/YOUR/WEBHOOK/URLポイント: エアギャップバックアップは、ランサムウェアが100%アクセスできないバックアップです。コストはかかりますが、最後の砦として非常に有効です。
バックアップが正常に復元できることを定期的に検証します。
#!/bin/bash
# /usr/local/bin/restore-test.sh
# 毎週実行される自動リストアテスト
# ========== 設定 ==========
BACKUP_ROOT="/backup/daily"
TEST_ROOT="/tmp/restore-test"
DB_TEST_USER="test_user"
DB_TEST_PASS="test_password"
TEST_DB_NAME="restore_test_db"
# ログ
LOG_FILE="/var/log/restore-test.log"
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a ${LOG_FILE}
}
# ========== テスト開始 ==========
log "=== リストアテスト開始 ==="
# 1. 最新バックアップを取得
LATEST_BACKUP=$(ls -td ${BACKUP_ROOT}/*/ | head -1)
BACKUP_NAME=$(basename ${LATEST_BACKUP})
log "テスト対象: ${BACKUP_NAME}"
# 2. テスト環境をクリーンアップ
rm -rf ${TEST_ROOT}
mkdir -p ${TEST_ROOT}
# 3. Webファイルの復元テスト
log "Webファイルの復元テスト中..."
tar -xzf ${LATEST_BACKUP}/website-files.tar.gz -C ${TEST_ROOT}
if [ $? -eq 0 ]; then
log "✅ Webファイル展開: 成功"
else
log "❌ Webファイル展開: 失敗"
exit 1
fi
# 4. 重要ファイルの存在確認
REQUIRED_FILES=(
"var/www/html/index.php"
"var/www/html/wp-config.php"
"var/www/html/wp-content/themes"
"var/www/html/wp-content/plugins"
)
for file in "${REQUIRED_FILES[@]}"; do
if [ -e "${TEST_ROOT}/${file}" ]; then
log "✅ ${file}: 存在確認OK"
else
log "❌ ${file}: 見つかりません"
exit 1
fi
done
# 5. データベースの復元テスト
log "データベースの復元テスト中..."
# テスト用データベースを作成
mysql -u root -e "DROP DATABASE IF EXISTS ${TEST_DB_NAME};"
mysql -u root -e "CREATE DATABASE ${TEST_DB_NAME};"
# SQLダンプを復元
gunzip < ${LATEST_BACKUP}/database.sql.gz | \
mysql -u root ${TEST_DB_NAME}
if [ ${PIPESTATUS[1]} -eq 0 ]; then
log "✅ データベース復元: 成功"
else
log "❌ データベース復元: 失敗"
exit 1
fi
# 6. データベースの整合性チェック
log "データベースの整合性チェック中..."
TABLES=$(mysql -u root -N -e "SHOW TABLES FROM ${TEST_DB_NAME}" | wc -l)
POSTS=$(mysql -u root -N -e "SELECT COUNT(*) FROM ${TEST_DB_NAME}.wp_posts" 2>/dev/null)
log "テーブル数: ${TABLES}"
log "投稿数: ${POSTS}"
if [ ${TABLES} -gt 0 ]; then
log "✅ データベース整合性: OK"
else
log "❌ データベース整合性: NG"
exit 1
fi
# 7. Webサーバー起動テスト
log "Webサーバー起動テスト中..."
cd ${TEST_ROOT}/var/www/html
php -S localhost:8888 > /dev/null 2>&1 &
PHP_PID=$!
sleep 3
# 8. HTTPレスポンステスト
HTTP_STATUS=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:8888)
log "HTTPステータスコード: ${HTTP_STATUS}"
if [ "${HTTP_STATUS}" -eq "200" ]; then
log "✅ Webサーバー起動: 成功"
else
log "❌ Webサーバー起動: 失敗"
kill ${PHP_PID}
exit 1
fi
# 9. チェックサム検証
log "チェックサム検証中..."
cd ${LATEST_BACKUP}
sha256sum -c checksums.txt > /dev/null 2>&1
if [ $? -eq 0 ]; then
log "✅ チェックサム検証: 成功"
else
log "❌ チェックサム検証: 失敗"
fi
# 10. クリーンアップ
kill ${PHP_PID} 2>/dev/null
mysql -u root -e "DROP DATABASE IF EXISTS ${TEST_DB_NAME};"
rm -rf ${TEST_ROOT}
# 11. 結果通知
log "=== リストアテスト完了: すべて正常 ==="
curl -X POST -H 'Content-type: application/json' \
--data "{
\"text\": \"✅ 週次リストアテスト完了\",
\"attachments\": [{
\"color\": \"good\",
\"fields\": [
{\"title\": \"バックアップ\", \"value\": \"${BACKUP_NAME}\", \"short\": true},
{\"title\": \"テーブル数\", \"value\": \"${TABLES}\", \"short\": true},
{\"title\": \"投稿数\", \"value\": \"${POSTS}\", \"short\": true},
{\"title\": \"HTTPステータス\", \"value\": \"${HTTP_STATUS}\", \"short\": true}
]
}]
}" \
https://hooks.slack.com/services/YOUR/WEBHOOK/URL
exit 0# /etc/cron.d/restore-test
0 2 * * 0 root /usr/local/bin/restore-test.shバックアップの成功・失敗を監視し、問題があれば即座に通知します。
#!/bin/bash
# /usr/local/bin/backup-monitor.sh
# バックアップの健全性を監視
BACKUP_ROOT="/backup/daily"
MAX_AGE_HOURS=26 # 26時間以内にバックアップがあるはず
S3_BUCKET="s3://my-website-backup"
# 1. ローカルバックアップの最終実行時間をチェック
LATEST_BACKUP=$(ls -td ${BACKUP_ROOT}/*/ | head -1)
if [ -z "${LATEST_BACKUP}" ]; then
curl -X POST -H 'Content-type: application/json' \
--data '{"text": "❌ アラート: ローカルバックアップが見つかりません"}' \
https://hooks.slack.com/services/YOUR/WEBHOOK/URL
exit 1
fi
BACKUP_AGE=$(( ( $(date +%s) - $(stat -c %Y ${LATEST_BACKUP}) ) / 3600 ))
if [ ${BACKUP_AGE} -gt ${MAX_AGE_HOURS} ]; then
curl -X POST -H 'Content-type: application/json' \
--data "{\"text\": \"⚠️ 警告: ローカルバックアップが${BACKUP_AGE}時間前です\"}" \
https://hooks.slack.com/services/YOUR/WEBHOOK/URL
fi
# 2. S3バックアップの最終実行時間をチェック
LATEST_S3=$(aws s3 ls ${S3_BUCKET}/ | tail -1 | awk '{print $2}')
# (省略)
# 3. ディスク容量チェック
DISK_USAGE=$(df /backup | tail -1 | awk '{print $5}' | sed 's/%//')
if [ ${DISK_USAGE} -gt 80 ]; then
curl -X POST -H 'Content-type: application/json' \
--data "{\"text\": \"⚠️ 警告: バックアップディスクが${DISK_USAGE}%使用中\"}" \
https://hooks.slack.com/services/YOUR/WEBHOOK/URL
fi
echo "✅ バックアップ監視: 正常"チーム全員がバックアップを理解し、緊急時に対応できるよう、運用ドキュメントを作成します。
# バックアップ運用マニュアル
最終更新: 2024-01-15
## 1. バックアップ構成の概要
### 3-2-1-1-0ルール実装状況
✓ 3つのコピー
- 本番サーバー(/var/www/html)
- ローカルバックアップ(/backup/daily)
- S3バックアップ(s3://my-website-backup)
✓ 2種類のメディア
- HDD(本番サーバー内蔵)
- クラウドストレージ(AWS S3)
✓ 1つのオフサイト
- AWS S3(東京リージョン)
✓ 1つのイミュータブル/オフライン
- S3 Object Lock(90日間削除不可)
- 外付けHDD(週次、エアギャップ)
✓ 0エラー検証
- 毎週日曜日午前2時に自動リストアテスト
## 2. バックアップスケジュール
| 種類 | 頻度 | 実行時刻 | 保持期間 | スクリプト |
|------|------|----------|----------|-----------|
| ローカル | 毎日 | 03:00 | 30日 | /usr/local/bin/daily-backup.sh |
| S3アップロード | 毎日 | 04:00 | 90日 | /usr/local/bin/backup-to-s3.sh |
| エアギャップ | 毎週日曜 | 02:00 | 4週間 | /usr/local/bin/airgap-backup.sh |
| リストアテスト | 毎週日曜 | 02:30 | - | /usr/local/bin/restore-test.sh |
## 3. 緊急時の復元手順
### 3.1 Webサイトファイルの復元
```bash
# 1. 最新バックアップを確認
ls -lh /backup/daily/
# 2. バックアップを展開
cd /var/www
tar -xzf /backup/daily/20240115-030001/website-files.tar.gz
# 3. 権限を修正
chown -R www-data:www-data /var/www/html
chmod -R 755 /var/www/html
# 4. Nginxを再起動
systemctl restart nginx
```
### 3.2 データベースの復元
```bash
# 1. データベースを削除(必要な場合)
mysql -u root -e "DROP DATABASE IF EXISTS wordpress_db;"
mysql -u root -e "CREATE DATABASE wordpress_db;"
# 2. バックアップから復元
gunzip < /backup/daily/20240115-030001/database.sql.gz | \
mysql -u root wordpress_db
# 3. 確認
mysql -u root -e "USE wordpress_db; SHOW TABLES;"
```
### 3.3 S3からの復元(ローカルバックアップが使用不可の場合)
```bash
# 1. S3から最新バックアップをダウンロード
aws s3 sync s3://my-website-backup/20240115-030001/ /tmp/restore/
# 2. 以降は上記と同じ手順
```
## 4. 監視とアラート
### 4.1 日次チェック項目
- [ ] Slackに「✅ 日次バックアップ完了」通知が届いている
- [ ] Slackに「✅ S3バックアップ完了」通知が届いている
### 4.2 週次チェック項目
- [ ] Slackに「✅ 週次リストアテスト完了」通知が届いている
- [ ] エアギャップバックアップの外付けHDDを金庫に保管した
### 4.3 月次チェック項目
- [ ] バックアップログを確認(/var/log/backup.log)
- [ ] S3のコストを確認(AWS Billing Dashboard)
- [ ] ディスク容量を確認(df -h /backup)
## 5. トラブルシューティング
### Q1: バックアップが失敗した場合
1. ログファイルを確認: `tail -100 /var/log/backup.log`
2. ディスク容量を確認: `df -h`
3. エラー内容をSlackで報告
4. 手動でバックアップを実行: `/usr/local/bin/daily-backup.sh`
### Q2: リストアテストが失敗した場合
1. テストログを確認: `cat /var/log/restore-test.log`
2. バックアップファイルの整合性確認: `sha256sum -c checksums.txt`
3. 別の日付のバックアップでテスト
4. 問題が続く場合は、バックアップスクリプトを見直す
### Q3: S3アップロードが失敗した場合
1. AWS認証情報を確認: `aws configure list`
2. S3バケットへのアクセス権限確認
3. ネットワーク接続を確認
4. 手動でアップロード: `/usr/local/bin/backup-to-s3.sh`
## 6. 連絡先
### 緊急連絡先
- サーバー管理者: 山田太郎 (090-XXXX-XXXX)
- バックアップ責任者: 佐藤花子 (080-XXXX-XXXX)
### ベンダー連絡先
- AWS サポート: https://console.aws.amazon.com/support/
- サーバーホスティング: support@example.com




スクリプトを書くのが難しい場合、専用のバックアップツールを使うのもアリですか?



もちろんじゃ!予算とスキルに応じて、最適なツールを選ぶのも賢い選択じゃぞ。主要なツールを比較してみるんじゃ!
| ツール名 | 料金 | 3-2-1-1-0対応 | 主な機能 | おすすめ度 |
|---|---|---|---|---|
| UpdraftPlus(WordPress) | 無料〜$70/年 | ○ | WordPressプラグイン、S3対応、自動スケジュール | ★★★★☆ |
| Duplicator Pro | $49.50/年 | △ | WordPressサイトの完全バックアップ、移行機能 | ★★★★☆ |
| rsync | 無料 | △ | Linuxの標準ツール、差分バックアップ | ★★★★★ |
| Synology ActiveProtect | 買い切り型 | ◎ | イミュータブル標準装備、GUI管理 | ★★★★★ |
| AWS Backup | 従量課金 | ◎ | AWS環境の統合バックアップ、自動化 | ★★★★☆ |
| Veeam | 有料(高額) | ◎ | エンタープライズ向け、高機能 | ★★★☆☆ |
設定手順:
GUIで簡単に3-2-1-1-0を実現できる点が魅力で、スクリプトに不慣れなチームに特に向いています。



実際に運用していると、いろいろな問題が出てきそうですね…



そうじゃな。ここでは、よくある課題と具体的な解決策を紹介するぞい!
解決策1:増分バックアップの導入
# rsyncで差分バックアップ
rsync -avz --delete \
/var/www/html/ \
/backup/incremental/$(date +%Y%m%d)/
# 前日との差分のみバックアップされるため、容量削減解決策2:不要なファイルを除外
# .gitignoreのようなexcludeリストを作成
# /etc/backup-exclude.txt
*.log
*.tmp
/var/www/html/wp-content/cache/*
/var/www/html/node_modules/*
/var/www/html/.git/*
# tarコマンドで除外
tar -czf backup.tar.gz \
--exclude-from=/etc/backup-exclude.txt \
/var/www/html/解決策3:S3のストレージクラスを最適化
この設定で、バックアップコストを約85%削減できます。
解決策:nice/ioniceで優先度を下げる
# CPUとディスクI/Oの優先度を下げて実行
nice -n 19 ionice -c 3 /usr/local/bin/daily-backup.shエックスサーバーにはサーバーパネルに自動バックアップ機能がありますが、同じサーバー内に保存されるため3-2-1ルールを満たしません。必ず追加のオフサイトバックアップを設定してください。
#!/bin/bash
# エックスサーバーからS3へのバックアップ
# SSH接続後に実行
XSERVER_HOME="/home/ユーザー名"
DOMAIN="example.com"
PUBLIC_HTML="${XSERVER_HOME}/${DOMAIN}/public_html"
# Webファイルをtar圧縮
tar -czf /tmp/backup-$(date +%Y%m%d).tar.gz ${PUBLIC_HTML}
# S3にアップロード
aws s3 cp /tmp/backup-$(date +%Y%m%d).tar.gz \
s3://my-backup-bucket/xserver/
# 一時ファイルを削除
rm /tmp/backup-$(date +%Y%m%d).tar.gz#!/bin/bash
# さくらインターネット向けバックアップ
# データベースはコントロールパネルでホスト名・ユーザー名を確認
DB_HOST="mysqlXX.db.sakura.ne.jp"
DB_USER="さくらのユーザー名"
DB_PASS="データベースパスワード"
DB_NAME="データベース名"
mysqldump \
-h ${DB_HOST} \
-u ${DB_USER} \
-p${DB_PASS} \
--single-transaction \
${DB_NAME} | gzip > sakura-db-$(date +%Y%m%d).sql.gz#!/bin/bash
# ConoHa VPS向け完全バックアップスクリプト
# 1. Webファイル
tar -czf /backup/web-$(date +%Y%m%d).tar.gz /var/www/html
# 2. MySQL全データベース
mysqldump --all-databases \
--single-transaction \
| gzip > /backup/mysql-all-$(date +%Y%m%d).sql.gz
# 3. Nginx設定
tar -czf /backup/nginx-conf-$(date +%Y%m%d).tar.gz /etc/nginx
# 4. Let's Encrypt証明書
tar -czf /backup/ssl-$(date +%Y%m%d).tar.gz /etc/letsencrypt
# 5. S3アップロード
aws s3 sync /backup/ s3://my-vps-backup/$(hostname)/# OpenSSLでバックアップを暗号化
openssl enc -aes-256-cbc -salt \
-in backup.tar.gz \
-out backup.tar.gz.enc \
-pass pass:${ENCRYPTION_PASSWORD}
# 復号化
openssl enc -d -aes-256-cbc \
-in backup.tar.gz.enc \
-out backup.tar.gz \
-pass pass:${ENCRYPTION_PASSWORD}# S3バケットのパブリックアクセスをブロック
aws s3api put-public-access-block \
--bucket your-backup-bucket \
--public-access-block-configuration \
"BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true"| 鉄則 | 内容 | 実装方法 |
|---|---|---|
| 3. 最小権限の原則 | バックアップ専用のIAMユーザーを作成 | AWS IAMポリシーで対象バケットのみ許可 |
| 4. パスワード管理 | DBパスワードをコードに直書きしない | AWS Secrets Manager / .env ファイル |
| 5. 転送時の暗号化 | S3へのアップロードはHTTPS/TLSで行う | aws s3 cp はデフォルトでHTTPS |
| 6. アクセスログの記録 | 誰がいつバックアップにアクセスしたか記録 | AWS CloudTrail / S3サーバーアクセスログ |
| 7. バックアップへのアクセス制限 | バックアップサーバーへのSSHアクセスを制限 | 鍵認証のみ許可、IPホワイトリスト |
| 8. 定期的な脆弱性スキャン | バックアップツール自体の更新 | UpdraftPlus等のプラグインを常に最新に |
| 9. バックアップへの書き込みを制限 | バックアップは追記のみ(上書き禁止) | S3 Object Lock / ファイルシステムの権限設定 |
| 10. 退職者のアクセス権限を即座に削除 | 退職後のアクセスによるデータ削除を防ぐ | AWS IAMユーザーの即時無効化 |
# AWS Secrets Managerを使用
aws secretsmanager create-secret \
--name prod/backup/db-password \
--secret-string "your-secure-password"
# スクリプトから取得
DB_PASSWORD=$(aws secretsmanager get-secret-value \
--secret-id prod/backup/db-password \
--query SecretString \
--output text)# S3バケットのバージョニング有効化
aws s3api put-bucket-versioning \
--bucket your-backup-bucket \
--versioning-configuration Status=Enabled
# オブジェクトロック設定(削除防止)
aws s3api put-object-lock-configuration \
--bucket your-backup-bucket \
--object-lock-configuration '{
"ObjectLockEnabled": "Enabled",
"Rule": {
"DefaultRetention": {
"Mode": "GOVERNANCE",
"Days": 30
}
}
}'| バックアップ方式 | 月額コスト | 対応リスク | 復元速度 |
|---|---|---|---|
| ローカルのみ | ¥0(電気代除く) | ハードウェア障害のみ | 高速 |
| クラウドのみ(S3) | ¥1,500〜5,000 | ほぼ全て(ランサムウェア除く) | 中速 |
| 3-2-1ルール | ¥3,000〜8,000 | ほぼ全て(ランサムウェア除く) | 高速 |
| 3-2-1-1-0ルール | ¥5,000〜15,000 | 全て(ランサムウェア含む) | 高速 |
ROI = (期待損失削減額 - バックアップコスト) / バックアップコスト × 100
= (¥350,000 - ¥32,400) / ¥32,400 × 100
= 980%
つまり、¥32,400の投資で¥350,000の損失を回避できる
→ 約10倍のリターン| 項目 | 金額 |
|---|---|
| 初期投資 | |
| 外付けHDD(2台) | ¥20,000 |
| S3セットアップ | ¥0(無料枠) |
| スクリプト開発時間(8時間 × ¥5,000/h) | ¥40,000 |
| 初期投資合計 | ¥60,000 |
| 年間ランニングコスト | ¥32,400 |
| 年間期待損失削減額 | ¥350,000 |
| 投資回収期間 | 約2.8ヶ月 |
# ライフサイクルポリシーで自動的に安価なストレージクラスへ移行
aws s3api put-bucket-lifecycle-configuration \
--bucket your-backup-bucket \
--lifecycle-configuration '{
"Rules": [
{
"Id": "MoveToIA",
"Status": "Enabled",
"Transitions": [
{
"Days": 30,
"StorageClass": "STANDARD_IA"
},
{
"Days": 90,
"StorageClass": "GLACIER"
},
{
"Days": 365,
"StorageClass": "DEEP_ARCHIVE"
}
]
},
{
"Id": "DeleteOldBackups",
"Status": "Enabled",
"Expiration": {
"Days": 1095
}
}
]
}'| 保存期間 | ストレージクラス | 100GB/月のコスト | コスト削減率 |
|---|---|---|---|
| 0-30日 | STANDARD_IA | ¥1,500 | 基準 |
| 31-90日 | GLACIER | ¥400 | -73% |
| 91-365日 | DEEP_ARCHIVE | ¥100 | -93% |
# rsyncの増分バックアップで、変更ファイルのみ転送
rsync -avz --link-dest=${YESTERDAY_BACKUP} \
/var/www/html/ \
${TODAY_BACKUP}/
# 結果:初回は100GB転送、2回目以降は1-5GB程度に削減# gzip圧縮(高速、圧縮率60%程度)
tar -czf backup.tar.gz /var/www/html
# xz圧縮(低速、圧縮率70-80%)
tar -cJf backup.tar.xz /var/www/html
# データベースはgzipで十分(SQLは高圧縮率)
mysqldump database_name | gzip > db.sql.gz
# 圧縮率:通常80-90%削減| 年 | 累計投資額 | 累計期待削減額 | 正味効果 |
|---|---|---|---|
| 1年目 | ¥92,400 | ¥350,000 | +¥257,600 |
| 2年目 | ¥124,800 | ¥700,000 | +¥575,200 |
| 3年目 | ¥157,200 | ¥1,050,000 | +¥892,800 |
| 4年目 | ¥189,600 | ¥1,400,000 | +¥1,210,400 |
| 5年目 | ¥222,000 | ¥1,750,000 | +¥1,528,000 |
5年間で約150万円の損失を回避できる一方、投資額は22万円のみ。投資対効果は約7倍。
状況:
実装していたバックアップ:
復旧の流れ:
結果:
A社担当者のコメント:
「3-2-1-1-0ルールを実装していなかったら、会社は確実に潰れていました。バックアップ費用(月額3,000円)が、3,000万円以上の損失を防いでくれた。今では全クライアントにバックアップの重要性を説明しています。」
実装していたバックアップ:UpdraftPlus自動バックアップ(4時間ごと)、Google Drive + Dropboxの2箇所保存
復旧の流れ:12:05エラー発生 → 12:07 UpdraftPlusで4時間前のバックアップを選択 → 12:15 サイト復旧完了(ダウンタイム10分、データ損失ほぼゼロ)
Bさんのコメント:
「UpdraftPlus(年額7,000円)がなかったら、サイトを1から再構築するはめになっていました。バックアップは保険と同じ。いざという時に本当に助かります。」
実装していたバックアップ:毎日深夜にrsyncでローカルNASへバックアップ + AWS S3への週次アーカイブ
結果:新規サーバー(エックスサーバー)へ全30サイトを5日間で移行完了。データ損失ゼロ。
| カテゴリ | チェック項目 | 完了 |
|---|---|---|
| バックアップ設定 | 本番データを含む3つのコピーが存在するか | □ |
| 2種類以上のメディアを使用しているか | □ | |
| オフサイト(クラウドまたは別拠点)にバックアップがあるか | □ | |
| イミュータブルまたはオフラインバックアップがあるか | □ | |
| 自動化 | 日次バックアップが自動実行されているか | □ |
| バックアップ成功/失敗の通知が届くか | □ | |
| 古いバックアップが自動削除されているか | □ | |
| 0エラー検証 | 毎週自動リストアテストが実行されているか | □ |
| チェックサム検証が行われているか | □ | |
| 直近3ヶ月以内に手動復元テストを実施したか | □ | |
| セキュリティ | バックアップデータが暗号化されているか | □ |
| DBパスワードがコードに直書きされていないか | □ | |
| バックアップへのアクセス権限が最小化されているか | □ | |
| ドキュメント | 復元手順書が最新の状態で整備されているか | □ |
| 緊急連絡先がドキュメントに記載されているか | □ |
# CloudWatch Alarmでバックアップの異常を検知
aws cloudwatch put-metric-alarm \
--alarm-name BackupFailureAlert \
--alarm-description "Backup failed or not executed" \
--metric-name BackupSuccessCount \
--namespace CustomMetrics \
--statistic Sum \
--period 86400 \
--threshold 1 \
--comparison-operator LessThanThreshold \
--evaluation-periods 1 \
--alarm-actions arn:aws:sns:ap-northeast-1:123456789:BackupAlertA: 更新頻度に応じて設定します。ECサイトや日次更新のブログは4〜6時間ごと、コーポレートサイトや更新頻度が低いサイトは1日1回が目安です。データベースはWebファイルより更新が多いため、より短い間隔を推奨します。
A: 復元頻度に応じて使い分けます。
A: 削除・変更が一定期間不可能なバックアップです。AWS S3 Object LockのCOMPLIANCEモードを使用すると、設定期間中は管理者でも削除できません。ランサムウェア攻撃から最後の砦となります。
A: はい、不十分です。エックスサーバーの自動バックアップは同じサーバー内に保存されるため、サーバー全体の障害やサーバー会社の問題時には役に立ちません。必ず追加のオフサイトバックアップ(S3やGoogle Driveなど)を設定してください。
A: コード管理としては優秀ですが、完全なバックアップではありません。データベース、アップロードファイル、SSL証明書、環境設定ファイルなどはGitHubに含まれません。Gitは3-2-1ルールの1つのコピーとして活用すべきです。
A: バックアップの約30%は何らかの理由で復元に失敗します。ファイル破損、不完全なバックアップ、ツールのバグなどが原因です。月1回以上のリストアテストで、いざという時に確実に復元できることを事前に確認しておくことが重要です。
A: mysqldump使用時は必ず–single-transactionオプションを付けてトランザクションの一貫性を保ちます。また、データベースとWebファイルのバックアップタイミングを合わせることで、復元時の整合性を確保します。
という3世代管理が一般的です。法的要件がある場合(個人情報保護法等)はそれに従います。
A: 感染前の最後のクリーンなバックアップから復元します。イミュータブルバックアップ(S3 Object Lock等)があれば、それが最も安全です。感染直前のバックアップは避け、少なくとも24〜48時間前のものを選びます。
A: はい、請求すべきです。「保守費用」や「セキュリティ対策費」として月額3,000〜10,000円を設定するのが一般的です。バックアップは保険と同じで、クライアントの資産を守るために必須のサービスです。提案時にデータ消失のリスクを具体的に説明しましょう。
本記事では、Web制作者のための3-2-1-1-0バックアップルールを、実践的なスクリプトやツールを交えながら解説しました。
WithCodeで学んだWeb制作スキルに、プロフェッショナルなバックアップ運用を組み合わせれば、クライアントからの信頼が格段に向上します。
バックアップは「いつかやろう」ではなく、「今日から始める」ことが重要です。クライアントの大切なデータ、そして自分のビジネスを守るために、今すぐ3-2-1-1-0バックアップを実践しましょう。


副業・フリーランスが主流になっている今こそ、自らのスキルで稼げる人材を目指してみませんか?
未経験でも心配することはありません。初級コースを受講される方の大多数はプログラミング未経験です。まずは無料カウンセリングで、悩みや不安をお聞かせください!
WithCodeでは、Web制作の技術だけでなく、サーバー管理やバックアップ戦略といった実務で必要なスキルも学べるカリキュラムを用意しています。プロとして活躍するために必要な、技術力と運用力の両方を身につけましょう。
公式サイト より
今すぐ
無料カウンセリング
を予約!