Davar 環境 バックアップ運用
全体像
日次バックアップは 米国 LA の lax(主)と東京の tky(副)の cloud VM 2 箇所に、最新 1 本ずつを保持します。内容は完全に対称で、どちらからでも同じ手順で復元できます。運用者の Mac・外付け SSD・iCloud には一切依存しません(2026-07-31 に移行。理由は移行の経緯)。
| 項目 | 設定 |
|---|---|
| 実行元 | lax の cron。08:00 EDT(= 05:00 PT) |
| 保存先 | lax と tky の /opt/davar-backup/ |
| 保持 | 両ホストとも最新 1 本のみ |
| 1 本のサイズ | 約 7.8 GB |
| 鮮度監視 | 48 時間を超えると日次レポートメールが警告 |
| 最終検証 | 2026-07-31(rc=0・両ホストで整合性確認済み) |
方式は pull 型です。保存先である lax が取りに行くので、取得元が侵害されてもバックアップ側を消せません。
守る対象
Davar の実体は 2 つのホストに分かれています。どちらが失われても会員向けサービスが止まるため、両方を 1 つのバックアップに揃えて取ります。
| ホスト | 役割 | 失うと何が起きるか |
|---|---|---|
rh10 | Davar AI。Open WebUI・RAG(bge-m3 + reranker)・LiteLLM・ollama | 質問応答が停止。学習済み Knowledge・モデル定義・システムプロンプト・利用者が消える |
d.cblh.us | Member Web。WordPress + Traefik + MariaDB | 会員サイトが停止。投稿・質問履歴・FAQ・アップロード済みメディア・テーマが消える |
コードは GitHub にあるため対象外です。バックアップが担うのは データと秘密情報、つまり GitHub から再生成できないものだけです。
2箇所の対称性
両ホストは同一パス・同一構成です。以下は 2026-07-31 の実測値です。
lax
主 · RHEL 9.8 · 米国 LA · 実行 + 保存- zip
- 8,274,937,854 B
- zip 内エントリ
- 11,263
- 非圧縮合計
- 8,423,729,246 B
- staging
- 11,221 files
- sha256 検証
- OK
- unzip -t
- OK
tky
副 · Ubuntu 24.04 · 東京 · 保存のみ- zip
- 8,274,936,666 B
- zip 内エントリ
- 11,263
- 非圧縮合計
- 8,423,729,246 B
- staging
- 11,221 files
- sha256 検証
- OK
- unzip -t
- OK
zip のサイズが 1,188 バイト違うのは正常です。各ホストが独立に圧縮するため、zip のバイト列と
.sha256はホスト間で一致しません。一致するのは格納内容(エントリ数と非圧縮合計)です。整合性検証は必ず取得元と同じホストの.sha256で行ってください。
ディスク上の構成(両ホスト共通)
/opt/davar-backup/
├── archive/
│ ├── d.cblh.us-backup_YYYYMMDD.zip 最新 1 本のみ
│ ├── d.cblh.us-backup_YYYYMMDD.zip.sha256
│ └── DR-RESTORE.md 復元手順書
├── staging/ 展開済みツリー(zip 化元)
│ └── corpus/ owui/ wp/ secrets/ DR-RESTORE.md
├── backup_davar_lax.sh lax のみ
├── DR-RESTORE.md lax のみ(配布マスター)
└── logs/ lax のみ・14 日保持
staging/ は zip を作る元ですが、それ自体が完全なバックアップでもあります。急ぐときは unzip せずこのツリーをそのまま復元に使えます。
東京へ zip を送らない理由
約 8 GB の zip を毎日日米間で転送するのは無駄なので、差分の staging ツリーだけを送り、tky 自身が同じ zip を作ります。初回は 7.9 GB(実測 約 0.5 GB/分)、以降は差分のみで済みます。
secrets/ には rh10 の .env、WordPress の wp-config.php、DB ダンプ、メール中継の資格情報が平文で入ります(個別暗号化はしない方針)。ディレクトリ 700 / ファイル 600 / zip 600 で保護しています。経路とスケジュール
| 経路 | 状態 | 方法 |
|---|---|---|
| lax → d.cblh.us | 到達 | 直接 SSH。sudo はパスワード不要 |
| lax → rh10 | 到達 | 二段ジャンプ必須 ssh -J d.cblh.us,opn1 rh10 |
| lax → opn1(直接) | 不通 | タイムアウト。これが二段ジャンプの理由 |
| lax → tky | 到達 | 直接 SSH。ファイアウォール変更は不要だった |
| Mac → tky | 不通 | 網の制限。必要なら ssh -J lax tky |
# lax の crontab
0 8 * * * /usr/bin/flock -n /opt/davar-backup/.lock /opt/davar-backup/backup_davar_lax.sh
08:00 EDT(= 05:00 PT)。Davar AI の収集ジョブ(02:00 PT)と OS 自動パッチの再起動(04:15 PT)より後に置き、再起動途中のデータを掴まないようにしています。flock で多重起動を防ぎます。
取得対象
| 区分 | 中身 | 目安 |
|---|---|---|
corpus/ | 収集コーパス・curated Knowledge・memory・台帳(学習データの源泉) | 89 MB |
owui/ | webui.db — モデル定義・システムプロンプト・Knowledge 定義とファイル本文・RAG 設定・利用者 | 68 MB |
wp/ | アップロード済みメディア・テーマ・質問と FAQ の JSON | 7.8 GB |
secrets/ | .env・wp-config.php・WP DB 全表ダンプ・インフラ設定・メール中継資格 | 12 MB |
取得しないもの(復元時に作り直せる)
| 対象外 | 復元方法 |
|---|---|
| ベクタ DB・キャッシュ(約 4 GB) | webui.db がファイル本文を持つので reindex で再構築(埋め込みは無料) |
| ollama のモデル(約 7.7 GB) | ollama pull |
| コンテナイメージ | docker pull |
非対象を切ったことで 1 本あたり約 12 GB を節約しています。wp/ が全体の 99% を占めるのは、会員サイトのメディアが 7.6 GB あるためです。
DR手順書の配布
「バックアップはあるが手順書が無い」状態を作らないため、復元手順書 DR-RESTORE.md を zip の中を含む 10 箇所に配布し、毎回同期しています。
| 場所 | 意図 |
|---|---|
GitHub リポジトリ docs/RESTORE.md | 正本 |
lax の配布マスター | ここから各所へ配る元 |
lax / tky の archive/ | zip と同じ場所に手順書がある |
lax / tky の staging/ | ツリーを直接使う場合用 |
| lax / tky の zip 内 | バックアップ 1 本だけで手順が揃う |
rh10 / d.cblh.us の本番ホスト | SSH できる状態ならその場で読める |
docs/RESTORE.md を更新したら scp docs/RESTORE.md lax:/opt/davar-backup/DR-RESTORE.md を実行してください。忘れると各所へ古い手順書を配り続けます。監視
バックアップが静かに止まる事故を二度起こさないため、成功したときだけ rh10 に成功マーカーを書きます。日次レポートメールがその鮮度を見て、48 時間を超えるか、マーカーが無ければ冒頭に赤い警告を出します。
# 最終成功時刻と保存先(dest=lax+tky が正常)
ssh rh10 'cat /opt/davar-ai/data/web/last_backup_ok.json'
# 直近の実行ログ
ssh lax 'tail -30 /opt/davar-backup/logs/backup-$(date +%Y%m%d).log'
# 両ホストの保持状況(それぞれ 1 本だけあること)
ssh lax 'ls -l /opt/davar-backup/archive/'
ssh lax 'ssh tky "ls -l /opt/davar-backup/archive/"'
# 整合性(取得元と同じホストの .sha256 で)
ssh lax 'cd /opt/davar-backup/archive && sha256sum -c *.sha256 && unzip -t *.zip | tail -1'
成功マーカーは「動いたこと」しか保証しません。中身が正しいことは別に確かめる必要があり、それが上の sha256sum -c と unzip -t です。
手動実行・一時停止
# 手動実行(cron と同じ経路。flock で二重起動を防ぐ)
ssh lax '/usr/bin/flock -n /opt/davar-backup/.lock /opt/davar-backup/backup_davar_lax.sh'
# 東京へのミラーを飛ばして lax だけ取る
ssh lax 'DAVAR_SKIP_TKY=1 /opt/davar-backup/backup_davar_lax.sh'
# 一時停止(cron 行をコメントアウト)
ssh lax 'crontab -l | sed "s#^0 8 \* \* \*#\#&#" | crontab -'
所要時間の目安は、差分実行で数分〜十数分です。zip の生成が最も重く、7.8 GB を書き出すのに各ホストで十数分かかります。初回のみメディア 7.6 GB の転送が加わります。
ハマり所
いずれも実際に踏んで判明したものです。同じ場所で止まらないために残します。
lax から rh10 へは踏み台を 2 段重ねる
lax の SSH 設定には rh10 用の踏み台が書いてありますが、lax からその踏み台自身に届かないため機能しません。会員サイトのホストが踏み台と同じネットワークにいるので、それを 1 段目にします。
ssh -J d.cblh.us,opn1 rh10 # OK
ssh -J d.cblh.us rh10 # NG: そこから先が届かない
rsync -e "ssh -J d.cblh.us,opn1" ... # rsync にも同じ指定が必要
「Mac から届かない」をファイアウォールの不備と決めつけない
東京のホストは SSH の接続元が特定の網に制限されています。Mac から届かないのはその制限であって、経路の不備ではありません。lax → tky は元から疎通しており、設定変更は不要でした。当事者間で実測してから変更を検討してください。
メディアはコンテナ経由でコピーしない
7.6 GB を一旦コンテナから /tmp へ複製すると、会員サイトのディスクを一時的に食い、所要時間も大幅に伸びます。WordPress のデータは named volume なので、ホスト側のパスから直接 rsync します(読み取りに sudo を使う)。
wp-cli はコンテナ再作成で消える
WordPress 操作に使う wp-cli は volume の外にあるため、コンテナを作り直すと消えます。スクリプトは使う前に存在を確認して自動復元します。このガードを外さないでください。
2 箇所の zip は .sha256 で突き合わせられない
独立に圧縮するとバイト列が一致しません。対称性を確かめるときはエントリ数と非圧縮合計で比較します。
移行の経緯
以前は運用者の Mac が毎朝 5 時に取得し、外付け SSD に保存、書けなければ iCloud に退避する構成でした。2026 年 7 月に破綻し、cloud VM へ移しました。原因は独立した 3 つが重なったもので、どれもエラー通知を出しませんでした。
| 要因 | 何が起きたか |
|---|---|
| 容量 | 会員サイトのメディアが 7.6 GB 増え、1 本が 199 MB から 7.7 GB へ約 37 倍に膨張。iCloud が容量不足になり、7/27 と 7/30 が書き込み失敗 |
| 外付け SSD | 接続されていても、自動実行の文脈からは OS の保護機能で書き込みを拒否され続けていた |
| 世代管理 | 「各月の最新だけ残す」処理が 7/28 以降まったく動かず、古い世代が残って容量をさらに圧迫。失敗ではなく無言だったため気づけなかった |
設計判断は 3 つです。保存先を運用者端末に依存させない、世代管理を最新 1 本に単純化する(状態が目で見て分かる)、保存先を地理的に離れた 2 箇所にする。
残課題
- 実地テスト復元が未実施。まっさらな新規 VM に対して通しで復元し、手順書の不足を洗い出す必要があります。必要なのは zip 1 本と手順書、非公開リポジトリを clone できる認証、外向きのネットワークです。本番への SSH は不要(zip だけで完結する設計)。
- メディアの増加を見張る。現在 7.6 GB。1 ホストにつき展開済みツリーと zip の 2 重で持つため、増えると消費は約 2 倍で効きます。東京側の空きが先に苦しくなります。大容量メディアを別扱いにするかは、空きを見て判断します。
- 秘密情報は平文のまま。個別暗号化はしない方針ですが、保存先 2 ホストのアクセス権は本番と同等に管理する必要があります。