1768 文字
9 分
Coolify環境のバックアップ戦略:6つのDBを自動ダンプ+復旧手順
概要
- 6つのデータベース(PostgreSQL×2、MySQL×1、MariaDB×3)のダンプを毎日自動実行
- バックアップ先は mergerfs + snapraid で冗長化されたストレージプール(7.2TB、3ドライブ構成)
- Coolifyの設定データ(
/data/coolify)もバージョニング付きで保存 - 復旧手順を文書化して、災害時に「何をすればいいか」を明確にした
第6回でZabbixによるリソース監視を構築した。コンテナが「今どうなっているか」は見えるようになった。次に必要なのは、「壊れたときにどう戻すか」。
バックアップ対象の棚卸し
まず、何をバックアップすべきかを整理した。
データベース一覧
現在のCoolify環境で稼働中のデータベースコンテナ。
| コンテナ | エンジン | サイズ | 用途 |
|---|---|---|---|
| coolify-db | PostgreSQL 15 | 42 MB | Coolify設定データ |
| immich-database | PostgreSQL 14 + pgvector | 1.2 GB | 写真管理(Immich) |
| Zabbix MySQL | MySQL LTS | 6.6 GB | 監視データ(Zabbix) |
| WordPress共有DB | MariaDB 11.7 | 678 MB | WordPress 2サイト |
| AI Moderator DB | MariaDB 11 | 3.1 GB | AI Moderator + LipSync |
| WordPress個別DB | MariaDB 11 | 162 MB | WordPress(teraren.com) |
合計約12GB。毎日のフルダンプでも十分に現実的なサイズ。
その他のバックアップ対象
| 対象 | 場所 | 重要度 |
|---|---|---|
| Coolify設定 | /data/coolify | 最重要 — アプリ定義、環境変数、秘密鍵すべて |
| Docker volumes | /var/lib/docker/volumes/ | 100+ボリューム。DBは個別ダンプするので、それ以外 |
| Zabbix agent設定 | /etc/zabbix/ | 設定ファイル。手動で再現可能だが保存しておく |
| cloudflared設定 | /etc/cloudflared/ | Tunnel設定。トークンが入っている |
| crontab | crontab -l | 定期実行ジョブの定義 |
バックアップ先のストレージ構成
mergerfs + snapraid
バックアップ先として、すでに構築済みの mergerfs + snapraid ストレージプールを使う。
/mnt/data1 (3.6TB HDD) ─┐/mnt/data2 (1.8TB HDD) ─┼─ mergerfs ─→ /mnt/storage (7.2TB pool)/mnt/data3 (1.8TB HDD) ─┘/mnt/parity (parity disk) ─→ snapraid parity| 項目 | 値 |
|---|---|
| 総容量 | 7.2 TB |
| 使用済み | 1.6 TB(22%) |
| 空き容量 | 5.5 TB |
| パリティ | 1ドライブ(1台故障まで復元可能) |
| 作成ポリシー | epmfs(最も空き容量の多いドライブに配置) |
mergerfsの利点:
- 複数ドライブを1つのマウントポイントに統合。アプリからは単一パスに見える
- JBODなので、1台が壊れても他のドライブのデータは無事
snapraidの利点:
- パリティドライブで1台分の冗長性を確保
- 常時同期ではなく定期実行。省電力
- 既存データの保護に特化(追記メインのバックアップに最適)
バックアップスクリプト
設計方針
- データベースはロジカルダンプ(
pg_dump、mysqldump)。バイナリコピーは復元が面倒 - 世代管理は7日分。古いダンプは自動削除
- Coolify設定は rsync。差分コピーで高速
- ログを残す。成功・失敗がわかるように
スクリプト全体
/home/matsu/bin/coolify-backup.sh:
#!/bin/bashset -euo pipefail
# === 設定 ===BACKUP_BASE="/mnt/storage/coolify-backups"DATE=$(date +%Y%m%d_%H%M%S)RETENTION_DAYS=7LOG_FILE="${BACKUP_BASE}/backup.log"
mkdir -p "${BACKUP_BASE}/db" "${BACKUP_BASE}/coolify-config" "${BACKUP_BASE}/system-config"
log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"}
log "=== バックアップ開始 ==="
# === 1. PostgreSQL ダンプ ===log "PostgreSQL: coolify-db"docker exec coolify-db pg_dumpall -U coolify \ | gzip > "${BACKUP_BASE}/db/coolify-db_${DATE}.sql.gz"
log "PostgreSQL: immich-database"IMMICH_DB=$(docker ps --format '{{.Names}}' | grep immich-database)docker exec "$IMMICH_DB" pg_dumpall -U postgres \ | gzip > "${BACKUP_BASE}/db/immich-db_${DATE}.sql.gz"
# === 2. MySQL / MariaDB ダンプ ===# Zabbix MySQLZABBIX_MYSQL=$(docker ps --format '{{.Names}}' | grep -E '^fswk')log "MySQL: Zabbix ($ZABBIX_MYSQL)"docker exec "$ZABBIX_MYSQL" mysqldump -u root --all-databases --single-transaction \ | gzip > "${BACKUP_BASE}/db/zabbix-mysql_${DATE}.sql.gz"
# WordPress 共有 MariaDBWP_SHARED_DB=$(docker ps --format '{{.Names}}' | grep -E '^fqff')log "MariaDB: WordPress共有 ($WP_SHARED_DB)"docker exec "$WP_SHARED_DB" mariadb-dump -u root --all-databases --single-transaction \ | gzip > "${BACKUP_BASE}/db/wp-shared-db_${DATE}.sql.gz"
# AI Moderator MariaDBlog "MariaDB: AI Moderator"docker exec ai-moderator-lipsync-db-1 mariadb-dump -u root --all-databases --single-transaction \ | gzip > "${BACKUP_BASE}/db/ai-moderator-db_${DATE}.sql.gz"
# WordPress 個別 MariaDBWP_TERA_DB=$(docker ps --format '{{.Names}}' | grep -E '^p8sg')log "MariaDB: WordPress teraren ($WP_TERA_DB)"docker exec "$WP_TERA_DB" mariadb-dump -u root --all-databases --single-transaction \ | gzip > "${BACKUP_BASE}/db/wp-teraren-db_${DATE}.sql.gz"
# === 3. Coolify 設定ディレクトリ ===log "Coolify設定: /data/coolify"sudo rsync -a --delete /data/coolify/ "${BACKUP_BASE}/coolify-config/"
# === 4. システム設定 ===log "システム設定のバックアップ"sudo cp -r /etc/zabbix/ "${BACKUP_BASE}/system-config/zabbix/" 2>/dev/null || truesudo cp -r /etc/cloudflared/ "${BACKUP_BASE}/system-config/cloudflared/" 2>/dev/null || truecrontab -l > "${BACKUP_BASE}/system-config/crontab.txt" 2>/dev/null || true
# === 5. 古いバックアップの削除 ===log "古いバックアップの削除 (${RETENTION_DAYS}日以上)"find "${BACKUP_BASE}/db" -name "*.sql.gz" -mtime +${RETENTION_DAYS} -delete
# === 6. サイズ確認 ===TOTAL_SIZE=$(du -sh "${BACKUP_BASE}" | cut -f1)log "バックアップ完了。合計サイズ: ${TOTAL_SIZE}"log "=== バックアップ終了 ==="crontab への登録
毎日 AM 4<00>00> に実行:
# Coolify環境の全DBバックアップ + 設定バックアップ0 4 * * * /home/matsu/bin/coolify-backup.sh >> /tmp/coolify-backup.log 2>&1復旧手順
バックアップは取るだけでは意味がない。「壊れたときに何をするか」 が明確でないと、パニック時に役に立たない。
ケース1: データベースの破損
特定のデータベースだけが壊れた場合。
# 最新のダンプを確認ls -lt /mnt/storage/coolify-backups/db/ | head -10
# PostgreSQL の復元(例: coolify-db)gunzip -c /mnt/storage/coolify-backups/db/coolify-db_YYYYMMDD_HHMMSS.sql.gz \ | docker exec -i coolify-db psql -U coolify
# MariaDB の復元(例: WordPress)gunzip -c /mnt/storage/coolify-backups/db/wp-shared-db_YYYYMMDD_HHMMSS.sql.gz \ | docker exec -i <container_name> mariadb -u rootケース2: Coolifyの再インストール
サーバは生きているが、Coolify自体が壊れた場合。
# 1. Coolify を再インストールcurl -fsSL https://cdn.coollabs.io/coolify/install.sh | bash
# 2. 設定を復元sudo systemctl stop coolifysudo rsync -a /mnt/storage/coolify-backups/coolify-config/ /data/coolify/sudo systemctl start coolify
# 3. データベースの復元は不要(設定に含まれている)ケース3: サーバの全損
ハードウェア故障でOSごと失った場合。
# 1. 新しいサーバにOSをインストール(Debian/Ubuntu)# 2. mergerfsストレージをマウント(HDDが無事であれば)# 3. Coolify をインストールcurl -fsSL https://cdn.coollabs.io/coolify/install.sh | bash
# 4. 設定を復元sudo rsync -a /mnt/storage/coolify-backups/coolify-config/ /data/coolify/
# 5. 各データベースを順番に復元for dump in /mnt/storage/coolify-backups/db/*_latest.sql.gz; do echo "Restoring: $dump" # DB種類に応じて pg_restore or mysql で復元done
# 6. cloudflared を再設定sudo cp -r /mnt/storage/coolify-backups/system-config/cloudflared/ /etc/cloudflared/sudo systemctl restart cloudflared
# 7. Zabbix agent を再設定sudo cp -r /mnt/storage/coolify-backups/system-config/zabbix/ /etc/zabbix/sudo systemctl restart zabbix-agent2ケース4: snapraid ドライブ障害
mergerfsプール内の1台が故障した場合。
# 1. 故障したドライブを特定sudo smartctl -a /dev/sdX
# 2. 新しいドライブを同じマウントポイントにマウント# 3. snapraid fix で復元sudo snapraid fix -d dN
# 4. パリティを再構築sudo snapraid syncバックアップの検証
バックアップは「取っている」だけでは不十分。定期的に復元テストをすべき。
簡易チェック(毎日)
バックアップスクリプトのログで、ファイルサイズがゼロでないことを確認。
# ダンプファイルが空でないか確認find /mnt/storage/coolify-backups/db/ -name "*.sql.gz" -size 0 -print# 出力がなければOK復元テスト(月1回推奨)
# テスト用コンテナでダンプを読み込んでみるdocker run --rm -i postgres:15-alpine psql -U postgres < test_dump.sqlオフサイトバックアップ(将来の拡張)
現在のバックアップは同一サーバ内の別ドライブ。火事や盗難には対応できない。将来的には:
| 方式 | コスト | 特徴 |
|---|---|---|
| Backblaze B2 | ~$0.5/月(12GB) | 安い。S3互換API |
| rclone + Google Drive | $0(15GBまで) | 無料枠で収まる |
| 物理メディア(USB HDD) | 初期費用のみ | 最もシンプル。月1回持ち出し |
12GBのDBダンプなら、Backblaze B2で月$0.5以下。導入するなら rclone でスクリプトに1行追加するだけ。
まとめ
| 対象 | 方式 | 頻度 | 保持期間 |
|---|---|---|---|
| データベース(6つ) | ロジカルダンプ + gzip | 毎日 AM 4<00>00> | 7日分 |
| Coolify設定 | rsync | 毎日 AM 4<00>00> | 最新のみ(差分) |
| システム設定 | ファイルコピー | 毎日 AM 4<00>00> | 最新のみ |
| ストレージ冗長化 | snapraid parity | 定期sync | パリティ1台分 |
バックアップは「やらなきゃ」と思いつつ後回しにしがち。でも、第6回でsentinelが5.2GBメモリを食っていたことを発見したように、見えていないリスクは常にある。バックアップスクリプト1本と、復旧手順の文書化。これだけで「壊れても戻せる」安心感が手に入る。
シリーズ記事
- Vercel月額$42→自宅サーバ月額$0。Coolifyで個人サービス基盤を作った話
- Coolifyインストールから「プロンプトでデプロイ」まで:Claude Code MCP実践
- Coolifyハンズオン:Hono・Go・Railsを実際にデプロイしてみる
- Cloudflare Tunnel×Coolify:自宅サーバを安全に外部公開する
- API-firstなインフラが生き残る:LLM時代のセルフホスト戦略
- ZabbixでDockerコンテナをリソース監視する:Coolify環境の可視化
- Coolify環境のバックアップ戦略:6つのDBを自動ダンプ+復旧手順(この記事)
- Coolify環境のログ管理と障害対応:Docker + Zabbix + Discordで運用を回す
Coolify環境のバックアップ戦略:6つのDBを自動ダンプ+復旧手順
https://blog.teraren.com/posts/coolify-backup-strategy/ Claude Opus 4.6 + ブラウザ自動操作で2025年確定申告:CSV解析・仕訳生成・MoneyForward入力・e-Tax送信
Coolify環境のログ管理と障害対応:Docker + Zabbix + Discordで運用を回す
関連記事
この記事が役に立ったら
GitHub Sponsorsで応援できます