Disaster Recovery Runbook · 正本: davar-ai/docs/RESTORE.md · 正本照合: 2026-09-02

Davar 環境 DR 復元手順

日次バックアップから、Davar AIとMember Webをまっさらな別ホストへ復元するための運用者向け手順書です。バックアップ側の設計・運用はバックアップ運用を参照してください。

取り扱い注意:このページには秘密値そのものは掲載していません。実際のバックアップ内の secrets/ は平文のため、安全な経路で移送し、同一世代のデータと組み合わせてください。
バックアップ OS前提 インベントリ Davar AI復元 Member Web復元 復元後の検証 バックアップ再設定 自動パッチ 注意事項

Davar 環境 DR 復元手順(別ホストへのフル展開)

このドキュメントは、日次バックアップ zip d.cblh.us-backup_YYYYMMDD.zip から、 rh10(OWUI/RAG/LLM スタック)と .9(WordPress 会員サイト d.cblh.us)を、まっさらな別ホストへ完全復元するための手順書です。 災害時にこの zip と本手順書さえあれば環境を再構築できることを目的にしています(コードは GitHub、データ・秘密情報はこの zip)。

このファイルは davar-ai リポジトリの docs/RESTORE.md が正本で、その写しが lax と tky の /opt/davar-backup/archive/DR-RESTORE.md(zip と同じ場所)、および zip の中(トップレベル)に置かれています。

検証状態(2026-07-24): 本手順は実インフラ(rh10 / .9)と突き合わせて精査済み。以下の「OS前提」「A」「B」の 注記は、Ubuntu 26 / RHEL 10 のまっさらなホストで復元が詰まった実監査結果を反映している。

保存先の変更(2026-07-31): バックアップは ローカル Mac(自動実行 + iCloud/外付けSSD)から cloud VM(lax 主 / tky 副)へ移行。 Mac 側の自動実行は停止済み。iCloud / 外付けSSD は使用しない。


0. バックアップの入手と展開

保存場所lax と tky は完全対称。どちらからでも同じ手順で復元できます (バックアップ側の設計・運用は バックアップ運用 が正本)。

優先ホストパス内容
1(主)lax(RHEL 9.8 / LA)/opt/davar-backup/archive/d.cblh.us-backup_YYYYMMDD.zip + .sha256 + DR-RESTORE.md
2(副)tky(Ubuntu 24.04 / 東京)/opt/davar-backup/archive/同上(tky 側で生成した同一内容の zip)
両ホスト/opt/davar-backup/staging/展開済みツリー(zip 化元。unzip せずそのまま使える)

保持ポリシー: 両ホストとも最新 1 本のみ

zip の同一性: 各ホストが独立に圧縮するため zip のバイト列(と .sha256)はホスト間で一致しませんが、格納内容は同一(エントリ数・非圧縮合計が一致)。整合性検証は必ず同じホストの .sha256 で行うこと。

接続経路(Mac から。tky は特定の網からのみ 22/tcp 到達可):

ssh lax    # → opn2 経由
ssh tky    # ※到達できない網からは lax 経由: ssh -J lax tky

入手・展開(SRClaxtky のどちらかにする。手順は同一):

SRC=lax   # または SRC=tky(lax が失われている場合)
Z=d.cblh.us-backup_YYYYMMDD.zip

rsync -az --progress "$SRC:/opt/davar-backup/archive/$Z" "$SRC:/opt/davar-backup/archive/$Z.sha256" .
sha256sum -c "$Z.sha256"      # 整合性チェック(OK)※必ず取得元と同じホストの .sha256 を使う

mkdir -p /tmp/davar-restore && cd /tmp/davar-restore
unzip -t "../$Z"              # 整合性チェック(No errors detected)
unzip "../$Z"                 # → corpus/ owui/ wp/ secrets/ + DR-RESTORE.md(本手順書)が展開される

# --- zip を使わず、展開済みツリーを直接引く場合(unzip 不要・どちらのホストでも可) ---
rsync -az --progress "$SRC:/opt/davar-backup/staging/" /tmp/davar-restore/

秘密情報: secrets/平文。安全な経路で新ホストへ移送し、配置後は chmod 600 を維持。

同一バックアップで揃える: secrets/(.env・DB dump)と owui/corpus/同じ zip のものを使う(鍵とデータの不整合・DB認証ロックを避ける)。

鮮度確認: corpus/web/last_backup_ok.jsoniso で最終成功時刻を確認(日次レポートメール冒頭バナーでも監視)。


OS 前提(Ubuntu 26 / RHEL 10)

両 OS 共通で Docker Engine + Docker Compose v2 が要る(本スタックは docker compose 前提。podman-compose は overlay/外部ネットワークの互換が不完全で非推奨)。


バックアップの中身(インベントリ)

zip 内パス内容復元での役割
corpus/rh10 /opt/davar-ai/data 全体(収集コーパス・curated・memory・台帳)収集の源泉・再投入元。/opt/davar-ai/data へ戻す
owui/webui.dbOWUI DB(KB定義+ファイル本文 file.data.content・3モデル定義/システムプロンプト/RAG設定(PersistentConfig)/users/アクセス権)これ1つで KB・モデル・設定・ユーザを復元。reindex でベクタ再構築
wp/davar_wp_latest.json.9 質問ログ+FAQ(人間可読・補助)参照用
wp/uploads/, wp/theme/.9 WP アップロード + テーマ davar-ai-church-theme.9 のメディア・テーマ復元
secrets/rh10-davar.envrh10 /opt/davar-ai/.env(下記「必須キー」)必須。無いと LLM/収集/TLS/レポートが起動しない
secrets/dot9-wpdb-full.sql.9 WP DB 全表ダンプ(mariadb --all-databases)WP DB 復元
secrets/dot9-wp-config.php.9 wp-config.php(DAVAR 定数+DB資格+salts).9 設定復元
secrets/dot9-infra.tar.gz/opt/wordpress-docker(WP compose+.env)+/home/ubuntu/traefik-wordpress(traefik).9 インフラ復元
secrets/rh10-postfix-sasl_passwdrh10 Gmail relay 資格日次レポートメール(任意)
DR-RESTORE.md本手順書そのもの(zip トップレベルに同梱)zip 1 本だけで復元手順が揃う

.env の必須キー(secrets/rh10-davar.env に含まれる。1つでも欠けると起動/機能が壊れる): ANTHROPIC_API_KEY(LLM)・CLOUDFLARE_API_TOKEN(Caddy の CF DNS-01 TLS)・ADMINUSER/ADMINPASS(OWUI 管理者=reindex/収集のトークン取得に必須)・DAVAR_REPORT_TOKEN(日次レポート)・Dropbox 系トークン(収集)。※ .env.example はリポジトリに無いので、この表を参照キーの一覧とすること。

非対象(バックアップ不要・復元時に再生成/再pull): OWUI vector_db(~4G)・uploadscache(埋め込みモデルキャッシュ含む)、ollama モデル(qwen3 ~7.7G)、container images。 → reindex でベクタ再構築、ollama pulldocker pull で復元(埋め込みはローカル無料)。外向きインターネット(HuggingFace 到達)が必要(下記 A.7)。


A. rh10(OWUI/RAG/LLM スタック)復元

  1. 新ホスト準備: 上記「OS 前提」に従い docker + docker compose、uv(~/.local/bin)を導入。
  2. コード: git clone git@github.com:yotake/davar-ai.git /opt/davar-ai
    • クローン先ディレクトリ名は davar-ai(webui.db が入る named volume 名 davar-ai_open-webui は compose プロジェクト名=ディレクトリ basename から決まる。名前が変わると A.7 の webui.db 配置先ボリュームがズレる)。
  3. 秘密情報: secrets/rh10-davar.env/opt/davar-ai/.env(chmod 600)。
  4. コーパス: corpus//opt/davar-ai/data/(rsync -a)。
  5. 起動(searxng オーバーレイも必ず含める。含めないと OWUI の Web 検索が死ぬ):
    cd /opt/davar-ai && docker compose \
      -f docker-compose.yml -f docker-compose.prod.yaml -f docker-compose.searxng.yaml up -d
    → davar-ollama / davar-litellm / davar-webui / davar-caddy / searxng が起動。
    • LLM 連携の鎖: .envANTHROPIC_API_KEY + deploy/litellm_config.yaml + compose env OPENAI_API_BASE_URLS=http://litellm:4000/v1 → LiteLLM 経由で Claude(Haiku/Sonnet)。
    • Open WebUIは確認済みの0.11.0 digestへ固定済みです(sha256:72c0ba641ba75e7aa52655cb242570906ececd09b1140fb736483038a22b3228)。復元前にdocker-compose.ymlがこのdigestを指すことを確認し、mainlatestへ置き換えません。別版を同じwebui.dbへ先に接続するとschema migrationが走る可能性があります。更新時はdocs/SECURITY-PATCHING.mdの複製volumeと出典付きcanaryを使います。
  6. ローカルモデル(フォールバック用。ollama pull は1引数ずつ):
    docker exec davar-ollama ollama pull qwen3:8b
    docker exec davar-ollama ollama pull qwen3:4b
  7. OWUI 状態の復元(KB/モデル/設定/users):
    • コンテナ停止: docker compose stop open-webui
    • owui/webui.db を named volume davar-ai_open-webui/app/backend/data/webui.db へ配置。 docker cp owui/webui.db davar-webui:/app/backend/data/webui.db の後、davar-webui:/app/backend/data/webui.db-wal-shm を削除(docker exec davar-webui rm -f /app/backend/data/webui.db-wal /app/backend/data/webui.db-shm)。
    • 起動: docker compose start open-webui
    • ベクタ再構築(reindex): webui.db はファイル本文を保持するので外部再取得は不要。管理者トークンを取り POST /api/v1/knowledge/reindex(admin 認証必須):
      TOKEN=$(curl -s http://localhost:8080/api/v1/auths/signin \
        -H 'Content-Type: application/json' \
        -d "{\"email\":\"$ADMINUSER\",\"password\":\"$ADMINPASS\"}" | python3 -c 'import sys,json;print(json.load(sys.stdin)["token"])')
      curl -s -X POST http://localhost:8080/api/v1/knowledge/reindex -H "Authorization: Bearer $TOKEN"
      初回 reindex で埋め込み BAAI/bge-m3(~2.3GB) と reranker BAAI/bge-reranker-v2-m3(~2.2GB) を HuggingFace から volume 内キャッシュ /app/backend/data/cache/embedding/models へDLする(バックアップ対象外)。外向きインターネット/HF 到達が必須、15〜35分。
    • 設定(ENABLE_RETRIEVAL_QUERY_GENERATION=false・TOP_K=8・TOP_K_RERANKER=6・bge-m3・hybrid・task model=Haiku)は webui.db(PersistentConfig)に含まれ、compose env(git 版=bge-m3 等)とも一致。
  8. 収集 cron: crontab -e0 2 * * * OPENWEBUI_URL=http://localhost:8080 /opt/davar-ai/scripts/run_weekly_collect.sh >> /opt/davar-ai/data/web/cron.log 2>&1
  9. 日次レポート(任意): postfix relay を構成し secrets/rh10-postfix-sasl_passwd/etc/postfix/sasl_passwd に復元(postmap 後 reload)。
  10. TLS: Caddy tls internal(自己署名)は自動。正式証明書は CF DNS-01(.envCLOUDFLARE_API_TOKEN)。

webui.db を使わない再構築(緊急時のみ): 空の OWUI に scripts/setup_custom_model.py でモデル作成 → collect.py all + ingest_curated.py で投入 → reindex。ただし埋め込みは git 版 compose の bge-m3(1024次元)である必要がある(古い e5-small(384次元)で作ると次元不一致で RAG が壊れる)。webui.db 復元の方が高速・確実。

B. .9(WordPress 会員サイト d.cblh.us)復元

構成: WP 本体(db=wp-db mariadb:11 / wordpress=wp-app wordpress:php8.3-apache)は /opt/wordpress-docker(compose プロジェクト wordpress-docker)。traefik(traefik:v3.6)は別スタック /home/ubuntu/traefik-wordpress(別プロジェクト)。traefik は外部ネットワーク wordpress-docker_wp_net(WP スタックが作る)に接続する。

  1. インフラ展開: sudo tar xzf secrets/dot9-infra.tar.gz -C //opt/wordpress-docker(compose+.env)・/home/ubuntu/traefik-wordpress(traefik 設定+dynamic/+letsencrypt/acme.json)。
    • WP スタックのディレクトリ名は wordpress-docker のままにする(プロジェクト名=ネットワーク名 wordpress-docker_wp_net がこれに依存。traefik がこの名前で接続する)。
  2. 起動(順序が重要。WP → traefik):
    cd /opt/wordpress-docker && docker compose up -d          # wp-db + wp-app(=ネットワーク wordpress-docker_wp_net 作成)
    # wp-app の初回セットアップ(named volume wordpress-docker_wp_data を初期化)完了を待つ
    cd /home/ubuntu/traefik-wordpress && docker compose up -d  # traefik(先に起動すると network not found で失敗)
    /opt/wordpress-docker/docker-compose.yml は db と wordpress の2コンテナのみ。traefik を別途起動しないと 443 リバースプロキシ/TLS が無くサイトに到達できない
  3. WP DB 復元(wp-app の初回初期化完了後)。--all-databases ダンプは mysql システムDB(grant/user)も含むため、同じ zip の .env(同一の DB パスワードハッシュ)と対で使うこと:
    docker exec -i wp-db sh -c 'MYSQL_PWD="$MARIADB_ROOT_PASSWORD" mariadb -uroot' < secrets/dot9-wpdb-full.sql
    docker compose -f /opt/wordpress-docker/docker-compose.yml restart db   # grant 再読込(FLUSH PRIVILEGES 相当)
    (wp-db のクライアントは mariadbmysql バイナリは無い。MARIADB_ROOT_PASSWORD はコンテナ env に実在。)
  4. wp-config / テーマ / メディア(wp-app は named volume wordpress-docker_wp_data/var/www/html初回初期化完了後に docker cp):
    • secrets/dot9-wp-config.phpdocker cp - wp-app:/var/www/html/wp-config.php(DAVAR 定数・DB資格・salts 込み。DAVAR_OWUI_URL/API_KEY が新 rh10 を指すか確認)。
    • wp/theme//var/www/html/wp-content/themes/davar-ai-church-theme/wp/uploads//var/www/html/wp-content/uploads/(docker cp)。
    • テーマは git@github.com:yotake/davar-web-draft.git でも管理。zip の wp/theme/ は deploy 済み版なので git push 状況に依存せず復元可。
  5. ドメインが変わる場合(別ドメインで復元するとき): 以下は d.cblh.us にハードコードされているので書き換える(DNS を新ホストへ向けるだけで同一ドメイン継続なら不要):
    • WP: wp_optionshome/siteurl(=https://d.cblh.us)。docker exec wp-app wp search-replace 'https://d.cblh.us' 'https://<新ドメイン>' --all-tables --allow-root(または UPDATE wp_options)。書き換えないとリダイレクトループ/管理画面ロックになる。
    • traefik: /home/ubuntu/traefik-wordpress/dynamic/wordpress.yml の router 規則 Host(`d.cblh.us`) と ACME email。新ドメインでは HTTP-01 で証明書を再発行(80番到達+DNS が新ホストを指すこと)。
  6. テーマ有効化確認: docker exec wp-app wp theme activate davar-ai-church-theme --allow-root(必要なら)。Cookie ゲート(DAVAR_SITE_PASSWORD)・レート制限・FAQ cron は wp-config/DB に含まれる。

C. 復元後の検証

  1. rh10 スタック: docker ps で davar-ollama/litellm/webui/caddy/searxng が Up。OWUI に管理者ログイン → 各 KB のファイル数が復元前と一致(knowledge_file join)。
  2. RAG 動作: ssh <newhost> 'set -a; . /opt/davar-ai/.env; set +a; MODEL=davar-bible-assistant-fast python3 /opt/davar-ai/scripts/verify_davar.py'(API課金が出るので通常は代表2〜3問のスポット)。
  3. .9 サイト: ブラウザで会員サイトを開き(TLS 有効)、チャットを1問投げて回答+「根拠となった抜粋」が返ることを確認。Web 検索を要する質問で searxng 経由が動くことも確認。

復元後: バックアップの再設定

忘れると復元先が無保護になります。バックアップは lax の cron が rh10d.cblh.us旧ホストを名指しで pull しています。別ホストへ復元したら取得先を新ホストへ向け直さないと復元した環境は一切バックアップされません。しかも鮮度マーカーは旧ホストを見続けるので、日次レポートは「正常」を出し続けます。
  1. lax の SSH 設定: lax:~/.ssh/configrh10 / d.cblh.usHostName を新ホストへ変更。rh10 側は踏み台経由が必要なら -J の指定も見直す(現行は ssh -J d.cblh.us,opn1 rh10)。
  2. スクリプト: lax:/opt/davar-backup/backup_davar_lax.shRSH_RH10 / SSH_DOT9 / DOT9_VOL と、鮮度マーカーの書き込み先(/opt/davar-ai/data/web/last_backup_ok.json)が新ホストで有効か確認。
  3. : 新ホストの ~/.ssh/authorized_keys に lax の共有鍵を登録し、sudo -n がパスワード無しで通ること(docker exec--rsync-path="sudo rsync" に必要)。
  4. 疎通確認: ssh lax 'DAVAR_SKIP_TKY=1 /opt/davar-backup/backup_davar_lax.sh' を1回手動実行し、rc=0archive/*.zip の生成、マーカー更新を確認してから cron に任せる。
  5. DR 手順書のマスター: scp docs/RESTORE.md lax:/opt/davar-backup/DR-RESTORE.md(本ファイルを更新した場合)。

復元後: セキュリティ自動パッチの再設定

別ホストへ復元したら、無人セキュア維持の自動パッチ構成も再設定する(docs/SECURITY-PATCHING.md 参照)。

注意