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
入手・展開(SRC を lax か tky のどちらかにする。手順は同一):
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.jsonのisoで最終成功時刻を確認(日次レポートメール冒頭バナーでも監視)。
OS 前提(Ubuntu 26 / RHEL 10)
両 OS 共通で Docker Engine + Docker Compose v2 が要る(本スタックは docker compose 前提。podman-compose は overlay/外部ネットワークの互換が不完全で非推奨)。
- Ubuntu 26: 公式リポジトリから
docker-ce docker-ce-cli containerd.io docker-compose-pluginを導入。ufw は既定無効。基本そのまま動く。 - RHEL 10(追加対応が必須):
- Docker が同梱されない(既定は podman)。docker.com の CentOS/RHEL リポジトリから Docker CE を導入する。
- SELinux が enforcing 既定。本スタックは
./deploy/litellm_config.yamlと./deploy/Caddyfileを bind mount(:ro) する(docker-compose.prod.yaml)。SELinux はこれらのコンテナからの読み取りを拒否するため、そのままでは litellm と caddy が設定を読めず起動失敗する。対策のいずれか:- compose のマウントに
:z/:Zを付ける(例:- ./deploy/litellm_config.yaml:/app/config.yaml:ro,Z)、または - ホスト側でラベル付与:
sudo chcon -Rt container_file_t /opt/davar-ai/deploy(semanage fcontextで永続化)。
- compose のマウントに
- firewalld で 80/443(Caddy)を開放:
sudo firewall-cmd --add-service={http,https} --permanent && sudo firewall-cmd --reload。
- 設定の正本はgit: 復元は必ず下記の
git cloneから始め、別ホストの作業ディレクトリをそのままコピーしない。起動後はwebui.dbの PersistentConfig も確認し、埋め込みモデル、reranker、チャンク設定がgitの現行値と一致することを検証する。
バックアップの中身(インベントリ)
| zip 内パス | 内容 | 復元での役割 |
|---|---|---|
corpus/ | rh10 /opt/davar-ai/data 全体(収集コーパス・curated・memory・台帳) | 収集の源泉・再投入元。/opt/davar-ai/data へ戻す |
owui/webui.db | OWUI 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.env | rh10 /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_passwd | rh10 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)・uploads・cache(埋め込みモデルキャッシュ含む)、ollama モデル(qwen3 ~7.7G)、container images。
→ reindex でベクタ再構築、ollama pull、docker pull で復元(埋め込みはローカル無料)。外向きインターネット(HuggingFace 到達)が必要(下記 A.7)。
A. rh10(OWUI/RAG/LLM スタック)復元
- 新ホスト準備: 上記「OS 前提」に従い docker + docker compose、
uv(~/.local/bin)を導入。 - コード:
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 配置先ボリュームがズレる)。
- クローン先ディレクトリ名は
- 秘密情報:
secrets/rh10-davar.env→/opt/davar-ai/.env(chmod 600)。 - コーパス:
corpus/→/opt/davar-ai/data/(rsync -a)。 - 起動(searxng オーバーレイも必ず含める。含めないと OWUI の Web 検索が死ぬ):
→ davar-ollama / davar-litellm / davar-webui / davar-caddy / searxng が起動。cd /opt/davar-ai && docker compose \ -f docker-compose.yml -f docker-compose.prod.yaml -f docker-compose.searxng.yaml up -d- LLM 連携の鎖:
.envのANTHROPIC_API_KEY+deploy/litellm_config.yaml+ compose envOPENAI_API_BASE_URLS=http://litellm:4000/v1→ LiteLLM 経由で Claude(Haiku/Sonnet)。 - Open WebUIは確認済みの0.11.0 digestへ固定済みです(
sha256:72c0ba641ba75e7aa52655cb242570906ececd09b1140fb736483038a22b3228)。復元前にdocker-compose.ymlがこのdigestを指すことを確認し、mainやlatestへ置き換えません。別版を同じwebui.dbへ先に接続するとschema migrationが走る可能性があります。更新時はdocs/SECURITY-PATCHING.mdの複製volumeと出典付きcanaryを使います。
- LLM 連携の鎖:
- ローカルモデル(フォールバック用。
ollama pullは1引数ずつ):docker exec davar-ollama ollama pull qwen3:8b docker exec davar-ollama ollama pull qwen3:4b - OWUI 状態の復元(KB/モデル/設定/users):
- コンテナ停止:
docker compose stop open-webui owui/webui.dbを named volumedavar-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 認証必須):
初回 reindex で埋め込み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"BAAI/bge-m3(~2.3GB) と rerankerBAAI/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 等)とも一致。
- コンテナ停止:
- 収集 cron:
crontab -e→0 2 * * * OPENWEBUI_URL=http://localhost:8080 /opt/davar-ai/scripts/run_weekly_collect.sh >> /opt/davar-ai/data/web/cron.log 2>&1 - 日次レポート(任意): postfix relay を構成し
secrets/rh10-postfix-sasl_passwdを/etc/postfix/sasl_passwdに復元(postmap後 reload)。 - TLS: Caddy
tls internal(自己署名)は自動。正式証明書は CF DNS-01(.envのCLOUDFLARE_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 スタックが作る)に接続する。
- インフラ展開:
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 がこの名前で接続する)。
- WP スタックのディレクトリ名は
- 起動(順序が重要。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 が無くサイトに到達できない。 - WP DB 復元(wp-app の初回初期化完了後)。
--all-databasesダンプはmysqlシステムDB(grant/user)も含むため、同じ zip の.env(同一の DB パスワードハッシュ)と対で使うこと:
(wp-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 相当)mariadb。mysqlバイナリは無い。MARIADB_ROOT_PASSWORDはコンテナ env に実在。) - wp-config / テーマ / メディア(wp-app は named volume
wordpress-docker_wp_data→/var/www/html。初回初期化完了後に docker cp):secrets/dot9-wp-config.php→docker 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 状況に依存せず復元可。
- ドメインが変わる場合(別ドメインで復元するとき): 以下は
d.cblh.usにハードコードされているので書き換える(DNS を新ホストへ向けるだけで同一ドメイン継続なら不要):- WP:
wp_optionsのhome/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 が新ホストを指すこと)。
- WP:
- テーマ有効化確認:
docker exec wp-app wp theme activate davar-ai-church-theme --allow-root(必要なら)。Cookie ゲート(DAVAR_SITE_PASSWORD)・レート制限・FAQ cron は wp-config/DB に含まれる。
C. 復元後の検証
- rh10 スタック:
docker psで davar-ollama/litellm/webui/caddy/searxng が Up。OWUI に管理者ログイン → 各 KB のファイル数が復元前と一致(knowledge_filejoin)。 - 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問のスポット)。 - .9 サイト: ブラウザで会員サイトを開き(TLS 有効)、チャットを1問投げて回答+「根拠となった抜粋」が返ることを確認。Web 検索を要する質問で searxng 経由が動くことも確認。
復元後: バックアップの再設定
rh10 と d.cblh.us の旧ホストを名指しで pull しています。別ホストへ復元したら取得先を新ホストへ向け直さないと復元した環境は一切バックアップされません。しかも鮮度マーカーは旧ホストを見続けるので、日次レポートは「正常」を出し続けます。- lax の SSH 設定:
lax:~/.ssh/configのrh10/d.cblh.usのHostNameを新ホストへ変更。rh10 側は踏み台経由が必要なら-Jの指定も見直す(現行はssh -J d.cblh.us,opn1 rh10)。 - スクリプト:
lax:/opt/davar-backup/backup_davar_lax.shのRSH_RH10/SSH_DOT9/DOT9_VOLと、鮮度マーカーの書き込み先(/opt/davar-ai/data/web/last_backup_ok.json)が新ホストで有効か確認。 - 鍵: 新ホストの
~/.ssh/authorized_keysに lax の共有鍵を登録し、sudo -nがパスワード無しで通ること(docker execと--rsync-path="sudo rsync"に必要)。 - 疎通確認:
ssh lax 'DAVAR_SKIP_TKY=1 /opt/davar-backup/backup_davar_lax.sh'を1回手動実行し、rc=0とarchive/*.zipの生成、マーカー更新を確認してから cron に任せる。 - DR 手順書のマスター:
scp docs/RESTORE.md lax:/opt/davar-backup/DR-RESTORE.md(本ファイルを更新した場合)。
復元後: セキュリティ自動パッチの再設定
別ホストへ復元したら、無人セキュア維持の自動パッチ構成も再設定する(docs/SECURITY-PATCHING.md 参照)。
- rh10(RHEL):
dnf install dnf-automatic dnf-utils→automatic.conf(security/apply=yes)+ timer +davar-autoreboot.sh(cron.d 04:15)。 - .9(Ubuntu):
unattended-upgrades+52davar-unattended(自動再起動04:00)。WP は wp-config(WP_AUTO_UPDATE_CORE=minor/FS_METHOD=direct)+ プラグイン auto-updates +scripts/davar-wp-image-update.sh(cron 日曜03:30)。
注意
- 秘密情報の移送:
secrets/は平文。安全な経路で移送し、配置後 chmod 600。 - ホスト名/IP/ドメイン:
.env/wp-config/traefikdynamic/にホスト・ドメイン固有値がある(B.5)。新環境に合わせて更新。 - 整合性:
webui.db・corpus・secretsは同一 zip(単一実行の point-in-time スナップショット)を使う。 - 参照ドメイン: 会員サイト = d.cblh.us(WordPress)。チャットは WP → rh10 OWUI へ REST 中継。
- git が正本: rh10 の /opt ディスクは drift しうる。復元は必ず GitHub から clone すること(OS 前提の注記参照)。
- バックアップの再設定を忘れない: 上記「復元後: バックアップの再設定」。復元しただけでは新ホストは保護されない。