この記事は約 5 分で読めます。
筆者プロフィール: ソフトウェアエンジニア。「知った気にならない。いつまでも学び続ける」を信条に、業務と個人開発の両輪で技術を磨いています。AI 駆動開発で複数の個人開発アプリを構築・運用中。
👉 ポートフォリオ: 筆者ホームページ
「バックアップが取れていると思っていたが、復元できなかった」 — 業界でよくある事故です。本記事では、運用中の SaaS 「たすきば Knowledge Relay」 で採用している 四半期定期検証 + 臨時検証 の運用を整理します。
サービスの機能紹介・画面イメージ・コンセプトは公式プロダクトページをご覧ください。
👉 たすきば Knowledge Relay — 公式プロダクトページ
なぜバックアップ検証が必要か
バックアップは「取っている」だけでは意味がありません。
| 確認事項 | 内容 |
|---|---|
| ファイルが壊れていないか | 圧縮・暗号化の確認 |
| 復元できるか | 実際に pg_restore できるか |
| 復元後にデータが完全か | 行数・整合性の確認 |
検証して初めて、バックアップが機能 します。
1. 検証頻度
| 種類 | 頻度 |
|---|---|
| 定期検証 | 四半期 (3 ヶ月ごと) |
| 臨時検証 | 重要変更後 (DB migration / インフラ移行等) |
個人開発で 四半期 1 回は現実的な頻度。これより少ないと「取れているか確信が持てない」状態になります。
2. Supabase の自動バックアップを信用する
| プラン | 自動バックアップ |
|---|---|
| Free | 過去 7 日分 |
| Pro | 長期 + Point-in-Time Recovery (PITR) 可 |
たすきばは現状 Free → Pro 移行予定なので:
| 期間 | バックアップ手段 |
|---|---|
| 短期 (1 週間以内) | Supabase の自動バックアップ |
| 長期 (1 ヶ月以上) | 手動 pg_dump をオフサイト保存 |
多層バックアップで、Supabase 障害時にも復元できる状態 を維持。
3. 手動 pg_dump のスケジュール
# 毎週日曜の夜に自動実行 (GitHub Actions schedule)
pg_dump -h $SUPABASE_HOST -U postgres -d postgres \
--format=custom \
--file=backup-$(date +%Y%m%d).dump
バックアップファイルは:
□ GitHub Actions 内で生成
□ AWS S3 (将来) または Google Drive (現状) にアップロード
□ 過去 12 週間分を保持
4. 暗号化の必須化
バックアップファイルには 個人情報が含まれる。必ず暗号化します。
# pg_dump → gpg 暗号化
pg_dump ... | gpg --symmetric --cipher-algo AES256 \
--passphrase "$BACKUP_PASSPHRASE" \
--batch --yes \
--output backup-$(date +%Y%m%d).dump.gpg
復号化に必要なパスフレーズは、1Password 等のパスワードマネージャに保管。パスフレーズを失うとバックアップが使えないため、複数経路でバックアップ。
5. 検証手順
Step 1: バックアップファイルの復号化
gpg --decrypt --passphrase "$BACKUP_PASSPHRASE" \
backup-20260501.dump.gpg > backup-20260501.dump
Step 2: 検証用 DB に復元
docker run -d --name backup-verify-pg \
-e POSTGRES_PASSWORD=verify -p 5433:5432 \
postgres:16
pg_restore -h localhost -p 5433 -U postgres \
-d postgres backup-20260501.dump
Step 3: データ件数確認
psql -h localhost -p 5433 -U postgres -d postgres \
-c "SELECT COUNT(*) FROM tenants"
psql -h localhost -p 5433 -U postgres -d postgres \
-c "SELECT COUNT(*) FROM projects"
各テーブルの件数が、本番と整合するか確認。
Step 4: 主要クエリの動作確認
SELECT id, email, mfa_enabled FROM users LIMIT 5;
SELECT id, name, state FROM projects LIMIT 5;
SELECT tenant_id, SUM(cost_jpy) FROM api_call_logs
WHERE created_at >= '2026-04-01' GROUP BY tenant_id;
業務クリティカルなクエリが正常に動くか検証。
Step 5: 検証レポート作成
# Backup Verification Report
- 検証日時: 2026-04-15 14:00
- バックアップ日時: 2026-04-15 02:00 (12 時間前)
- 検証環境: ローカル Docker PostgreSQL
- 復元時間: 8 分 30 秒
- データ件数:
- tenants: 5 (本番と一致)
- projects: 27 (本番と一致)
- クエリ動作: OK
- 整合性: OK
結論: 復元可能。次回検証は 2026-07-15。
レポートを残すことで、「検証した」が証拠 になります。
6. RTO / RPO の測定
| 指標 | 意味 | たすきばの目標 |
|---|---|---|
| RTO | 障害発生から復元完了までの時間 | 1 時間以内 |
| RPO | データロス時間 (バックアップ取得頻度) | 24 時間以内 |
検証時に、これらが実現できるかを 実測。
2026-04-15 検証結果:
RTO: 復元コマンド開始 → アプリ起動まで 8 分 30 秒
RPO: バックアップ取得から 12 時間 → 24 時間以内 OK
7. 臨時検証のタイミング
定期検証以外に、以下のタイミングで臨時検証:
□ DB migration を実行した後
□ Supabase Pro へのアップグレード後
□ 大きなコードリリースの前
□ インフラ構成変更後
「変更後にバックアップが正しく機能するか」を即座に確認。
8. ストレージファイルのバックアップ
Supabase Storage (添付ファイル) のバックアップも別途必要。
aws s3 sync s3://tasukiba-attachments/ ./backup/attachments-$(date +%Y%m%d)/ \
--endpoint-url=$SUPABASE_S3_ENDPOINT
DB だけでなく、Storage も含めて初めて完全なバックアップ。
9. 失敗ケースを文書化する
過去、たすきばで起きた検証失敗ケースを記録:
| 失敗 | 対応 |
|---|---|
| 復号化のパスフレーズが間違っていた | パスフレーズ管理を 2 重化 |
| 復元に 1 時間以上かかった | バックアップサイズ最適化 |
| Storage ファイルが復元されていなかった | DB + Storage 両方を検証対象に |
失敗パターンを共有することで、次回の検証品質が上がる。
おわりに — 個人開発でここまでやる必要があるか
正直、個人開発で四半期検証は 重い負荷。それでもやる理由:
| 理由 | 内容 |
|---|---|
| ユーザのデータを預かる責任 | 復元責任がある |
| 信頼の維持 | 1 回目の事故で信頼が崩れる |
| 口だけでは不十分 | 「バックアップあります」と言うだけでは |
「取っているが、復元できない」を防ぐために、地道に検証 を続けます。
| 仕組み | 効果 |
|---|---|
| 四半期定期検証 | バックアップの実効性を保証 |
| 臨時検証 (重要変更後) | 変更による影響を確認 |
| 検証レポート | 履歴と証跡 |
| RTO / RPO 測定 | 目標との比較 |
| Storage も検証対象 | 完全なバックアップ |
個人開発でも、バックアップを「取って終わり」にしない仕組み が大切です。
本記事の検証運用は、運用中の SaaS 「たすきば Knowledge Relay」 で実装しています。
👉 たすきば Knowledge Relay — 公式プロダクトページ