このブログのサーバを、最新のイメージに移行しました。ダウンタイムはゼロ、RSSフィードの生成は8秒から0.78秒に、記事ページの転送量は3分の1になりました。かかったのは一日です。
きっかけは、サイトが落ちていたことでした。Claude Codeと原因を調べていくと、自分の思い込みが次々に覆されていきます。最終的に、設定の手直しではなくイメージごと移行することを決めました。
コーディングにAIを使った話は以前書きました。今回はインフラ編です。

一日でやったこと
| 前 | 後 | |
|---|---|---|
| RSSフィード生成 | 8.0秒 / 646KB | 0.78秒 / 362KB |
| 記事ページ(gzip後) | 115KB | 42KB |
| サーバ側の記事描画 | 8,156ms | 833ms |
| 500エラー率 | 46% | 0% |
| OS / PHP | Debian 11 / 8.1.18 | Debian 12 / 8.2.33 |
| 月額 | $7.95(1GB/1vCPU) | $12.00(2GB/2vCPU) |
やったのは、落ちた原因の究明、サーバイメージの移行、性能改善、セキュリティ強化、そして監視の設置です。月額はプランを増強したぶん上がっていますが、旧プランで繰り返していたメモリ枯渇ごと解消しています。
なぜ触ることになったか
きっかけは、サイトが「データベース接続確立エラー」で落ちていたことでした。しかも私はそれに気づいていませんでした。
CloudFront 5xxエラー率
2026-08-29 18:25 74.0%
2026-08-29 20:25 84.1%
2026-08-30 19:25 68.5%
2026-08-30 20:25 3.6% ← 対処開始
26時間以上、7〜8割のリクエストが失敗していました。この数字はCloudFrontが無料でずっと記録していたものです。見ていなかっただけでした。
監視を入れていなかったわけではありません。Jetpackのダウンタイム監視を有効にして、通知はスマホアプリで受け取っていました。ところが、そのアプリがいつの間にか自分のブログの購読を解除していて、通知が届かなくなっていたのです。さらにDBを調べると、Jetpack自体の同期も止まっていました。
jp_sync_last_success_sync → 2026-07-03 22:21 JST
7月3日を最後に58日間、一度も同期していません。通知の経路と監視本体が、二重に沈黙していたことになります。そしてどちらも、止まったことを知らせてはくれませんでした。後日、CloudWatchに残っていた日次データ(1時間粒度なら15ヶ月遡れます)を掘り直すと、疑いは確定に変わりました。7月4日から8月29日までの57日間、日平均の5xxエラー率が20%を下回った日は一日もなく、大半の日は5〜8割。このブログは実質2ヶ月落ちていたのです。
AIに何をどこまでやらせたか
準備
Claude Codeは手元のターミナルで動き、私が普段打つコマンドをそのまま実行します。渡したのは二つだけです。まず~/.ssh/configに接続設定を書き、「ssh blogでサーバに入れます」と伝える。調査はこれで始まります。移行を頼む段階になってから、AWS CLIのプロファイルを追加で渡しました。静的IPの付け替えやRoute53の修正はこちらの経路です。
認証は有効期限つきなので、切れるたびに私が再ログインします。手間ではありますが、AIが持つ権限はその時々で自分が渡したものだけ、という安心感があります。準備はこれだけです。ここから先は、すべて会話で進みました。
まず全部読ませて、当たりをつけさせる
最初の指示は「WordPressをホストしているサーバが最近不安定。原因を探って」程度の曖昧なものでした。そこからAIは、メモリの状態、journal、Apacheのログ、監視プロセスのログを順にさらっていき、数分で当たりを二つ挙げてきました。
- journalに、OOM KillerがMariaDBを殺した記録が6回
- 231MBある監視ログの中に、一行だけ残っていた決定的な記録
"mariadb was unmonitored after 5 failed tries"
監視プロセス(gonit)は再起動に5回失敗すると、そのサービスの監視自体をやめる仕様でした。つまり6月21日以降、DBが死んでも誰も起こさない状態だったのです。落ちたままだった理由はこれでした。
231MBのログから一行を拾うのは、人力ではまずやりません。まず全体をさらわせて当たりをつけさせ、それから深掘りする。探索のコストがほぼゼロになるのが、インフラ作業でAIがいちばん効くところだと思います。
当たりは「測って」潰す
ただし、探索で出てきた仮説をそのまま信じないことも大事でした。「なぜ遅いか調べて」ではなく、実際に走らせて数字を出させます。
たとえば復旧後もフィードの生成に8秒かかっていた件では、WordPressのthe_contentに登録されている26個のコールバックを1つずつ計測させました。
ms callback
3308.4 do_shortcode
68.9 replace_anchor_links
28.0 do_blocks
7.9 url_to_external_blog_card
1つのコールバックが96%を占めていました。さらにショートコードを1種類ずつ分離して計測させ、原因を1個に絞り込む。正体は、障害中に利用資格が失効した外部APIを、全ページで1件150msかけて呼び続けていたことでした。失敗を1時間キャッシュする仕組みを入れて、8.0秒が0.78秒になりました。
フィード以外も同じ進め方です。記事ページの転送量が3分の1になったのは、テーマの設定で全ページのHTMLに埋め込まれていた671KBのCSS(116種類のブロック向け。実際に使っていたのは7種類でした)を外部ファイルに戻したことと、数式ライブラリ(約400KB)を数式を含む1記事だけで読み込むようにしたことが主です。どちらも、何が重いかを測って初めて見つかったものでした。
ログをさらうのも、測るのも、要は事実に基づいて進めるということです。これにはもうひとつ効用がありました。AIは時々、自信満々に間違えます(Lightsailの課金をEC2と混同して説明された、などがありました)。それでも判断を事実に紐付けていれば、間違いは次の計測で露見します。「そう思う」ではなく「こう出た」で進める限り、AIの間違いは致命傷になりませんでした。
既定値も信じすぎない
そもそもなぜOOMが起きるのか。調べると、搭載975MBのインスタンスに対してPHPの同時実行数が45に設定されていました。1プロセス66〜77MB(実測)なので、最大3GB相当です。
私はここを疑ったことがありませんでした。AWSが公式に配っているイメージなのだから、サイズに見合った設定のはずだと思っていたからです。ところが移行先の新イメージ(Lightsail公式)を実測すると、同じ「1GB向け」でこうでした。
| 1GB向け既定値 | Bitnami | Lightsail公式 |
|---|---|---|
| PHP同時実行数 | 45 | 5 |
| Apache MaxRequestWorkers | 256 | 5 |
| PHP memory_limit | 512M | 128M |
9倍の開きです。しかも新イメージの中には、AWS自身のこんなコメントがありました。
# WordPress instances that come with micro memory size (< 1.5 GB) OOM under
# common plugin workloads; a small swap file mitigates this.
「1.5GB未満のWordPressは一般的なプラグイン構成でOOMする」と認めた上で、小さいプランのときだけスワップを自動作成する作りです。今回は実測に基づいて同時実行数を8に下げました。この時点ではまだ旧の1GBインスタンスでしたが、それでも40並列を投げて空きメモリ354MBを維持できています。3年間「なんとなく重い」で済ませていた問題でした。
同じ種類の思い込みがもうひとつありました。ログのローテーションです。当然されているものだと思っていましたが、Bitnami自身の監視ログ(gonit.log)にはローテーション設定が存在せず、2023年の構築以来育ち続けて231MBになっていました。探索のところに出てきた「231MBのログ」はこれです。journaldも上限が未設定で3.9GB。合わせて約4GBを整理し、ディスク使用率は23%から13%に下がりました。
配布イメージは「動く」ようには作られていますが、「運用され続ける」ことまでは面倒を見てくれない。既定値を信じすぎない、というのはチューニング値だけでなくログにも当てはまりました。
移行そのものをAIに任せる
土台も古くなっていました。Debian 11、PHP 8.1.18(2023年4月ビルド)、bullseye-backportsは消滅済み。加えてAWSが2026年11月19日にBitnami版WordPressブループリントを廃止すると告知しています(既存インスタンスは動き続け、スナップショットからの再作成も可能です)。
移行を頼んでからの進み方が、個人的には今回のハイライトでした。設定ファイルをコピーして回るような作業ではありません。私が伝えたのは「移行しよう」だけで、あとはAIが自律的に、問題を見つけては解決策を考えながら進めていきます。実際の流れはこうでした。
- 移行先を実測する。検証用にインスタンスを1台起動し、新ブループリントの中身を調査。docrootもSSHユーザーも違い、cronも入っていない構成でした
- 差分を踏まえた移行手順書を作る。切り替え手段(静的IPの付け替え)と切り戻し手段までこの時点で確定
- データを移送する。WP-CLIでDBごと移し、URLの正規化も移送前に済ませる
- 本番に触らず検証する。hostsの書き換えでCloudFrontと同じ形の接続を再現し、切り替え前に新環境を一通り確認
- 公式手順の穴を塞ぐ。AWS公式の移行手順は「切り替え後に証明書を再取得」ですが、この順序だと数分のダウンタイムが出ます。AIは証明書を先に旧サーバからコピーする手順に組み替え、無停止で切り替えました
環境の差分を把握し、手順を組み、事前に検証してから切り替える。進め方は人間のインフラエンジニアと同じで、違うのは速度だけでした。ダウンタイムゼロはその結果です。
実際には、細かいハマりどころがいくつもありました。静的IPを付け替えてもAAAAレコード(IPv6)は旧サーバを指したまま残る、Bitnamiのwp-contentはシンボリックリンクなのでtarが中身を固めない、新イメージにはcronが入っていない。いずれも、AIがその場の環境を調べて見つけたものです。この種の差分は、次のバージョンでは変わっているかもしれません。だからこそ、個々のTipsを覚えておくより、移行のたびに、その場の環境をLLMに走査してもらう方が確実だと思います。
3年前の記事が、チェックリストになった
Lightsailの移行は今回で3回目です。

| 2021年 | 2023年 | 2026年 | |
|---|---|---|---|
| 移行手段 | エクスポート/インポート | 移行プラグイン | WP-CLIでDBごと移送 |
| ダウンタイム | あり | あり | ゼロ |
| 後始末 | 記録なし | URL一括置換 | 不要 |
| チューニング | 記録なし | 勘と経験 | プロファイリング |
今回、移行計画を立てる前にAIへ過去記事を読ませました。これが想像以上に働きました。
2023年の記事には「データ移行で一部のURLがIPアドレス表記になって壊れ、後から一括置換した」と書いてあります。それを踏まえてAIが移送前にDBを照合したところ、当時の残骸がそのまま見つかりました。siteurlとhomeが旧IPのままでした。表示上はwp-config.phpの定義が上書きしていて、3年間誰も気づけない状態です。移送前に1,243箇所を正規化し、同じ破損の再発を未然に防ぎました。
AAAAレコード(IPv6)が移行の邪魔をするという罠も、実は2023年の記事に書いてありました。
AAAAレコード(IPv6)が設定されているとうまくいかなかったので、一旦外しておく必要があり、地味に面倒でした。
私はすっかり忘れていましたが、今回も形を変えて現れています(当時は証明書ツールが躓く話、今回は静的IP付け替え後にレコードが取り残される話)。
備忘録のつもりで書いた過去記事が、AIの参照資料としてチェックリストのように機能する。自分は忘れていても、AIは照合してくれます。ブログは書いておくものだと思いました。
まとめ
サーバ運用でAIを使ってみて、コーディングのとき以上に「実行して数字を出せること」の価値が大きいと感じました。ログを引く、プロファイラを回す、設定を変えて測り直す。この往復が速いほど原因に近づきますし、何より効果が目に見えない作業に、手応えが生まれます。
技術的な教訓は3つでした。
- 公式配布物でも既定値は自分の環境で検証する。同じ「1GB向け」でPHPの同時実行数に9倍の差があり、ログのローテーション設定は存在しませんでした
- 監視や自動復旧が生きているかを、別の手段で確認する。どちらも静かに止まりますし、止まったことは誰も教えてくれません
- 監視はサイトの外側に置く。サイト内のプラグインで監視すると、サイトごと壊れたときに一緒に黙ります
最後にアラームを2つ設定しました。CloudWatchのアラームは10個まで無料、CloudFrontのメトリクスも無料です。閾値5%に対して今回は74%だったので、これがあれば10分で気づけていました。
Bitnamiブループリントをお使いの方は、2026年11月19日の廃止までに移行の検討をおすすめします。

コメント