自宅のProxmox上でDocker Composeの投稿システムを運用していて、最近はテーマ調整や下書き作成をAIエージェントにも手伝わせている。そんな運用をしている方ほど、ある時点で同じ不安に行き着きます。「本番を直接いじるのが、だんだん怖くなってきた」という不安です。
バックアップは取っている。ロールバック手順もある。それでも、AIエージェントがUIや下書きに関わる範囲が広がるほど、本番に直接当てる変更の点数が増え、戻すコストと判断の負荷が静かに積み上がっていきます。本記事は、この不安に対して「本番と同型のステージングを家庭内Proxmoxに用意し、確認が済んだものだけを本番へ一方向で送る」という運用へ移すための、実機検証ログと判断の流れをまとめたものです。
なお今回の検証は、本番システムや実データには一切触れていません。使い捨てのVM内に合成データの投稿システムを2系統立て、手順そのものが再現可能に成立するか、そして本番側へ意図せず逆流しないかを一度確認したものです。実本番データの移送結果ではない点を、先にお断りしておきます。
なぜステージングが必要になったか
きっかけは「直したい箇所」よりも「直し方を試す場所」が足りない、という感覚でした。テーマの余白を少し変える、ブロックの組み方を変える、AIに提案させたレイアウトを当ててみる——どれも単体では小さな変更ですが、本番に直接当てて確認すると、表示崩れやキャッシュ、検索エンジンへの露出といった副作用が読みにくくなります。
本番と同じ形の場所で先に当てておけば、崩れても誰の目にも触れず、戻すのも環境ごと捨てるだけで済みます。これが「本番を守るためにステージングを作る」という判断の出発点でした。
検証環境
- 実行場所: 使い捨ての検証用VM(VM+Docker、検証後に破棄)
- Docker: Docker Engine 29.6.0 / Docker Compose v5.1.4
- 構成: Docker Composeで 投稿システム(6系, PHP 8.2)+ MariaDB 11 + WP-CLI を1セットとし、ソース(本番相当の踏み台)とステージングの2系統を用意
- データ: すべて合成データ。本番のデータベースやメディアは未使用
- 公開面: いずれもホスト内ループバックにのみポート公開(ソース:8081 / ステージング:8082)
所在地や内部アドレス、VMの管理IDといった運用情報は、再現には不要なため本記事では丸めています。
実行コマンドと実行ログ(抜粋)
すべてのステップは終了コード0で完了しました。以下は要点のみのサニタイズ済み抜粋です。
1. ソース(本番相当)を立てて合成データを投入
docker compose up -d
wp core install --url='http://source.local' --title='Prod Stand-in' --admin_user=admin --admin_password=*** --skip-email
wp theme activate twentytwentyfour
wp post create --post_title='Synthetic Post N' --post_status=publish # 3件
wp post list --format=count # => 4(サンプル含む)
2. DBダンプとwp-contentを取得し、機密スキャンをかける
wp db export /var/www/html/dump.sql # => 約 80 KB
tar -czf wp-content.tgz -C /var/www/html wp-content # => 約 13 MB
grep -aiE '(api[_-]?key|password|secret|10\.|192\.168\.|...)' dump.sql | head
ここで一つ学びがありました。素朴な機密スキャンは、投稿システムが初期生成する「プライバシーポリシー」雛形の本文(コメント収集時に訪問者のIPアドレスを取得する、という説明文)にヒットします。つまり実際の秘密情報ではなく、既定文面への誤検知です。本番データで同じスキャンを回す際は、こうした既定コンテンツの誤検知を前提に、ヒット内容を必ず目視確認する必要があります。
3. ステージングを立て、ダンプを取り込む
sed 's/8081:80/8082:80/' source/docker-compose.yml > staging/docker-compose.yml
docker compose up -d
wp db import /var/www/html/dump.sql
wp post list --format=count # => 4(ソースと一致)
4. URL書き換えと検索除外(noindex)
wp search-replace 'http://source.local' 'http://staging.local' --skip-columns=guid # => 5件置換
wp option update blog_public 0
wp option get siteurl # => http://staging.local
wp option get home # => http://staging.local
wp option get blog_public # => 0
search-replace で options テーブルの siteurl/home も置換されたため、その後の option update は「変更なし」と返っています。意図どおりの状態です。
5. 一方向promoteの確認
wp post create --post_title='Promoted From Staging' --post_status=publish
wp post list --format=count # => 5
test -f source/pull_from_staging.sh && echo 設定項目 || echo 設定項目
# => 設定項目
検証後は両系統とも docker compose down -v でボリュームごと破棄し、コンテナ・ボリュームが残っていないことを確認しています。
結果まとめ
| 項目 | 結果 |
|---|---|
| ソース→ダンプ→ステージング取り込み | 記事数が4で一致し、復元成立 |
| URL書き換え(search-replace) | 5件置換、siteurl/home がステージングURLに |
| 検索除外(blog_public) | option値が 0 に更新済み(※HTTP実地確認は未取得) |
| 一方向promote | ソースへの追加は成立、逆流スクリプトは不在 |
| 後始末 | ボリュームごと破棄、残存なし |
他の選択肢との比較
本番を直接いじる怖さを減らす方法は、Proxmox同型ステージングだけではありません。読者が現実に天秤にかける選択肢を並べます。
| 選択肢 | 本番との同型度 | 本番への逆流リスク | AIエージェント連携の自由度 | コスト感 | 検索流出対策 |
|---|---|---|---|---|---|
| 本番を直接編集(バックアップ頼み) | — | 高(本番そのもの) | 制限なしだが危険 | ほぼ0 | 事故時の露出は最大 |
| マネージド投稿システムのステージング機能 | 高(同基盤) | 中(同期操作次第) | 環境制約あり | 月額が継続発生 | 提供側が制御 |
| ステージング系プラグイン(同一サーバー内) | 中 | 中(同居ゆえの取り違え) | 中 | 低 | プラグイン設定依存 |
| ローカルDockerだけの簡易環境 | 低〜中 | 低 | 高 | 低 | 環境次第 |
| Proxmox同型ステージング(本記事) | 高(OS/Compose/DB/構造を寄せる) | 低(別系統+一方向) | 高(自分の環境で自由) | 既存ホームラボなら追加費用小 | blog_public=0等を自分で制御 |
要点は、AIエージェントに自由に試させたいほど「連携の自由度」と「逆流リスクの低さ」を両立させたくなる、という点です。Proxmox同型ステージングは、既にホームラボを持っているならこの両立をコストを抑えて狙えます。
作る/まだ作らない の判断条件
作る価値が高いのは、次のいずれかに当てはまる場合です。
- AIエージェントや複数人が下書き・UI調整に関わり、本番直変更の点数が増えている
- テーマや表示まわりの試行錯誤を、誰の目にも触れずに繰り返したい
- 既にProxmox/Dockerを運用しており、VMやコンテナを1系統増やす余地がある
逆に、まだ作らなくてよいのは次のような場合です。
- 変更頻度が低く、本番の編集が月に数回程度で、バックアップとプレビューで足りている
- 同型度をそこまで求めず、ローカルDockerの簡易確認で判断が付く
- ホームラボの余剰リソースがなく、別系統を常時持つ負担の方が大きい
SWELLなど有料テーマを同型にする場合の扱い
今回の実機検証で有効化したテーマは Twenty Twenty-Four であり、SWELLそのものの動作は検証していません。その上で、同型ステージングにSWELLのような有料テーマを入れる場合の安全側の考え方を述べます。
同一管理者が、自分の本番と同じライセンス下で動作確認を行うための非公開な検証環境であれば、リスクは小さいと考えられます。一方で、ステージングを第三者に提供したり、会員情報・テーマのダウンロードURL・認証情報を外部に出すことは避けるべきです。検証環境はあくまで自分の手元で閉じ、検索エンジンからも遮断しておく(blog_public=0、内部ネットワーク側に置く)のが無難です。
失敗・制約・再現条件
正直に書いておくべき制約があります。
- 検索除外のHTTP実地確認は未取得です。 blog_public は option値として 0 に更新済みですが、本ログではステージングのHTTP応答取得に失敗(ポート接続不可)しており、実際の meta robots 出力や robots.txt のレベルまでは確認できていません。本番相当で運用する際は、ブラウザやcurlで
noindex相当が出ているかを別途確認してください。 - 合成データでの手順検証です。 実本番データでは、絵文字・マルチバイト・シリアライズ済みのオプション値・大容量メディアにより、search-replaceやダンプ移送が想定より重く・繊細になることがあります。
- 一方向性は「逆流スクリプトが存在しないこと」での確認にとどまります。 運用上の強制ではないため、promote方向を仕組みで固定したい場合は、別途ガード(書き込み経路の分離など)が必要です。
- 機密スキャンは既定文面に誤検知します。 ヒット=秘密、と短絡せず、内容の目視確認を前提にしてください。
再現条件は単純です。同じ構成のVM+Docker環境で、上記の手順(ソース構築→ダンプ取得→ステージング取り込み→URL書き換え→noindex→一方向promote→破棄)を同じ順で再実行すれば、同じ流れが成立します。
結論
「本番投稿システムを壊さずに、テーマ調整やAIエージェント連携を試したい」という問いに対する今回の答えは、Proxmox上に本番同型のステージングを別系統で立て、確認が済んだものだけを本番へ一方向で送る、というものです。少なくとも手順そのものは、使い捨てVM上の合成データで再現可能に成立しました。残るのはnoindexのHTTP実地確認と実本番データでの移送検証であり、ここを潰せば日常運用に乗せられる、という見通しが立ったところです。
この検証を回している環境
この検証は、自宅の常設ラボ(使い捨てVM/LXCを回す母艦+GPU+VLAN分離ネットワーク)で動かしています。使っている機材と選定理由、全体構成は1本にまとめています。
ラボ構成のまとめを見る →