💾

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台分の冗長性を確保
  • 常時同期ではなく定期実行。省電力
  • 既存データの保護に特化(追記メインのバックアップに最適)

バックアップスクリプト

設計方針

  1. データベースはロジカルダンプpg_dumpmysqldump)。バイナリコピーは復元が面倒
  2. 世代管理は7日分。古いダンプは自動削除
  3. Coolify設定は rsync。差分コピーで高速
  4. ログを残す。成功・失敗がわかるように

スクリプト全体

/home/matsu/bin/coolify-backup.sh:

#!/bin/bash
set -euo pipefail

# === 設定 ===
BACKUP_BASE="/mnt/storage/coolify-backups"
DATE=$(date +%Y%m%d_%H%M%S)
RETENTION_DAYS=7
LOG_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 MySQL
ZABBIX_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 共有 MariaDB
WP_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 MariaDB
log "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 個別 MariaDB
WP_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 || true
sudo cp -r /etc/cloudflared/ "${BACKUP_BASE}/system-config/cloudflared/" 2>/dev/null || true
crontab -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 に実行:

# 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 coolify
sudo 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 7日分
Coolify設定 rsync 毎日 AM 4:00 最新のみ(差分)
システム設定 ファイルコピー 毎日 AM 4:00 最新のみ
ストレージ冗長化 snapraid parity 定期sync パリティ1台分

バックアップは「やらなきゃ」と思いつつ後回しにしがち。でも、第6回でsentinelが5.2GBメモリを食っていたことを発見したように、見えていないリスクは常にある。バックアップスクリプト1本と、復旧手順の文書化。これだけで「壊れても戻せる」安心感が手に入る。

シリーズ記事

  1. Vercel月額$42→自宅サーバ月額$0。Coolifyで個人サービス基盤を作った話
  2. Coolifyインストールから「プロンプトでデプロイ」まで:Claude Code MCP実践
  3. Coolifyハンズオン:Hono・Go・Railsを実際にデプロイしてみる
  4. Cloudflare Tunnel×Coolify:自宅サーバを安全に外部公開する
  5. API-firstなインフラが生き残る:LLM時代のセルフホスト戦略
  6. ZabbixでDockerコンテナをリソース監視する:Coolify環境の可視化
  7. Coolify環境のバックアップ戦略:6つのDBを自動ダンプ+復旧手順(この記事)
  8. Coolify環境のログ管理と障害対応:Docker + Zabbix + Discordで運用を回す
株式会社マインディア テックブログ

Discussion