背景・状況
prima-beads.com/media/ のWordPressサイトでは、SWELLの子テーマをGitHub Actions経由でFTPデプロイする運用フローを構築していた。GitHub上でコードを管理し、Actionsのワークフローでサーバーへ自動デプロイする仕組みだ。デプロイにはSamKirkland/FTP-Deploy-Actionを使用している。
インシデントの詳細
FTP Deploy Actionを実行した際、functions.phpとstyle.cssが丸ごと上書きされ、本番環境の既存カスタマイズが消失するインシデントが発生した。具体的に消えたのは以下の要素だった。
- SEO関連のカスタムコード(メタディスクリプション、構造化データ)
- カスタム投稿タイプの定義
- ショートコードの登録
- カルーセル表示用のCSS
- 既存のウィジェット設定に依存するスタイル
根本原因の分析
原因1: 既存ファイルのバックアップ未取得
デプロイ前に本番環境の既存ファイルをFTPで取得してバックアップするプロセスが存在しなかった。「GitHubにあるコードが正」という前提で作業していたが、本番環境にはGit管理されていないカスタマイズが存在していた。
原因2: FTP Deploy Actionの挙動を誤解
FTP Deploy Actionの実行ログに「Server Files: 0」と表示されたことを、「サーバーにファイルが存在しない」と誤解した。実際にはこれはステートファイル(.ftp-deploy-sync-state.json)が存在しないことを意味しており、サーバー上のファイルの有無とは無関係だった。この誤解により、「サーバーにファイルがないから全ファイルをアップロードしても安全」という誤った判断に至った。
原因3: functions.phpの丸ごと上書き
functions.phpは既存のカスタマイズと新規のコードをマージすべきだったが、GitHub上の新しいfunctions.phpで丸ごと上書きしてしまった。
復旧対応
手動でFTPクライアントを使い、サーバー上の残存ファイルを取得。バックアップから既存のカスタマイズコードを復元し、新規コードとマージする形で修正を行った。復旧には約2時間を要した。
策定した運用ルール
このインシデントを受け、以下の6つのルールを策定し、SCRATCHPAD.mdの「デプロイ安全規約」セクションに文書化した。
- 必ず既存ファイルをFTPで取得してバックアップしてからデプロイする
- functions.php等の既存ファイルは丸ごと上書き禁止。既存コードを確認し、マージする
- FTPデプロイは手動トリガー(workflow_dispatch)のみ。on:push での自動デプロイは禁止
- dry_run=true で差分を確認してから、dry_run=false で本番デプロイ
- dangerous-clean-slate: false を必ず設定(サーバー側のファイル削除を防止)
- ユーザー(サイトオーナー)に変更内容を説明し、承認を得てからデプロイする
本番環境への変更は「壊す前提」で備えろ。バックアップがないデプロイは、命綱なしのロッククライミングと同じだ。
この記事のポイント
- 本番環境への変更は「壊す前提」で備える。バックアップ取得、dry_run確認、承認プロセスの3段階を必ず踏む。
- FTPデプロイツールの挙動を正確に理解してから使う。「Server Files: 0」の意味を誤解したことが事故の直接的な引き金だった。
- 事故後にルールを文書化し、二度と繰り返さない仕組みを作る。個人の注意力に頼るのではなく、プロセスで防ぐ。