サーバを AlmaLinux 10 に入れ替えた話(作業はほぼ AI)

サーバを AlmaLinux 10 に入れ替えた話(作業はほぼ AI)

この記事について
作業だけでなく、この記事の文章も AI(Claude)がまとめています。内容は実際の作業ログと実測値に基づいていますが、公開前に管理人が目を通しています。

放置していたサーバの話です。
このサイトを含む WordPress 5サイトが載っている AWS の EC2 が、ずっと Amazon Linux 2 のままでした。
Amazon Linux 2 のサポートは 2026年6月30日で終了しているので、とっくに期限切れです。
重い腰を上げて、AlmaLinux 10 の新しいサーバに入れ替えました。

今回の本題はどちらかというとそこではなく、この作業のほぼ全部を AI にやらせたという話です。
使ったのは Anthropic の Claude Code。ターミナルで動く AI エージェントで、こちらの端末でコマンドを実行できます。

方針 — 載せ替えずに、隣に建てて差し替える

同じサーバの中で OS を上げていくやり方は、失敗したときに戻せません。
なので新しいサーバを別に建てて、Elastic IP(固定IP)を付け替えるだけにしました。
うまくいかなければ IP を戻せば元通りです。

調べてみて助かったのが、このサーバは CloudFront(CDN)が前に立っていて、HTTPS の終端は CloudFront 側だったことです。
サーバ自身は 80番で CloudFront からのアクセスだけを受けていました。
つまり新サーバ側で証明書を作り直す必要がない
さらに CloudFront のオリジン指定がインスタンスの DNS 名だったので、IP を移すだけで 5サイトが同時に切り替わります。CDN 側の設定変更はゼロで済みました。

この「証明書を作り直さなくていい」という判断は、最初に構成を実測で洗い出したから出てきたものです。
思い込みで進めていたら、要らない作業を一日分やっていたはずです。

AlmaLinux 10 は、9 までの作法がわりと通じない

RHEL 10 系になって変わったところで、けっこう時間を取られました。

1. dnf module がもう無い
AppStream のモジュール機構そのものが廃止されていて、dnf module list は何も返しません。
MySQL も mysql-server というパッケージ名が存在しません。正しくは mysql8.4-server です。
これを知らずに dnf list mysql-server をやると「AlmaLinux 10 に MySQL は無い」と誤解します(しました)。

なお Oracle の repo.mysql.com を足す必要はありません。
そちらは署名鍵が 2025年10月に期限切れで dnf に弾かれますし、AppStream 版とファイルが衝突します。

2. postfix のハッシュ形式が変わった
Berkeley DB が廃止されて、hash: が使えなくなりました。既定は lmdb です。
たちが悪いのは、postmap が黙って .lmdb を作ってしまうところです。
設定ファイル側が hash: のままでもエラーが出ず、実際にメールを送る段になって初めて失敗します

3. cron の systemd ユニット名は crond
cronie では起動しません。しかも systemctl enable --now に nginx や php-fpm と並べて書いていると、そこで止まって後ろが全部起動しません

MySQL 8.4 とゼロ日付

照合順序(文字の並び順のルール)を utf8mb4_unicode_520_ci に揃えようとしたら、いくつかのテーブルで止まりました。

ERROR 1067 (42000): Invalid default value for 'xxx'

原因は datetime DEFAULT '0000-00-00 00:00:00'、いわゆるゼロ日付です。
MySQL 8.4 はこれを既定で拒否します。CONVERT TO CHARACTER SETOPTIMIZE TABLE も、中でテーブルを作り直すので引っかかります。

対処はセッションの sql_mode を空にすることでした。

mysql -e "SET SESSION sql_mode=''; ALTER TABLE `db`.`tbl` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_520_ci;"

結果、66テーブルすべて変換できました。失敗ゼロ、ストレージエンジンの変更もゼロです。

いちばん詰まったのは SELinux

このサーバはサイトを /home/<ユーザー>/public_html に置く構成です。
AlmaLinux は SELinux が既定で enforcing なので、ここが3段構えの壁になりました。どれか1つでも欠けると全サイト落ちます。

1段目は SELinux ですらない。
useradd が作る /home/<ユーザー> のパーミッションは 700 で、nginx が通り抜けられません(旧サーバは 711 でした)。
このときの症状が 403 ではなく php-fpm の「File not found.」で、SELinux の拒否ログ(AVC)も出ません。
SELinux を疑って延々と時間を溶かす罠です。

2段目、ラベルは自作しないほうが早い。
既定ポリシーが public_htmlhttpd_user_content_t を付けてくれます。
ここで汎用的な自作ルールを足すと、既定ルールの正規表現のほうが長いので優先されて負けます。
ユーザー名まで書いた明示的なルールにすれば勝てます。

3段目、public_html の外は別扱い。
wp-config.php を公開ディレクトリの外に置いていたので、既定では php-fpm も nginx も読めませんでした。

あと boolean が4つ要ります。httpd_enable_homedirshttpd_read_user_content(どちらも既定 off)、WordPress の更新 API のために httpd_can_network_connect、メール送信のために httpd_can_sendmail
setsebool に複数まとめて書くと失敗するので、1つずつ実行します。

この設計が正しかったかどうかは、切り替えのあとに自分で答え合わせができました。
5サイトの WordPress を一気に全更新して約4,000ファイルが書き込まれましたが、SELinux の拒否は0件でした。

切り替え

データの移送は、旧サーバに一切触らずにやりました。
旧サーバのセキュリティグループは CDN からの 80番しか開いていないので、新サーバから直接は届きません。
穴を開けるのは本番の変更になるので、ディスクのスナップショットからボリュームを作って、新サーバに読み取り専用でマウントする経路にしました。

ここで小さな罠がひとつ。root ファイルシステムの複製なのでファイルシステムの UUID が元と重複します。mount -o ro,nouuid が必須でした。

さらに棚卸しの途中で気づいたのですが、旧サーバは毎朝6時23分に全テーブルロック付きの DB ダンプを作っていました。自分で昔しかけたものです。
整合性があるので、そのまま移送元に使えました。本番で mysqldump を走らせる必要がありませんでした。

切り替え直前の最終同期だけは新しいダンプを取りましたが、書き込みが止まったのは10秒だけ(約250MB)です。

あとは Elastic IP を付け替えるだけ。2026年9月5日の午前0時19分に完了しました。

検証は、切り替えの前後で各サイトの応答をバイト単位で突き合わせました。

サイトA 200 / 77,315 B → 200 / 77,315 B 一致
このサイト 200 / 66,628 B → 200 / 66,628 B 一致
サイトC 200 / 2,281 B → 200 / 2,281 B 一致

1サイトだけ 178バイトの差が出ましたが、中身を見たらページ内の動的な部分でした。
そのあとキャッシュ回避のクエリを付けて本番 URL を叩き、新サーバのアクセスログに着弾していることまで確認しています。

実質的なダウンタイムはありませんでした。

ついでに直ったこと

移行後、表示が遅いのが気になって調べてもらいました。
てっきり古いプラグインが吐いている大量の PHP Warning のせいだと思っていたのですが、実際は PHP の OPcache の容量不足でした。
設定を変えただけで応答が約3.4倍速くなりました。

思い込みで「プラグインを消す」方向に進んでいたら、速くならないうえにサイトが壊れていたかもしれません。

AI と組んでみての感想

よかったのは、実測してから判断するのを徹底してくれるところです。
「たぶんこうだったはず」で進めると事故るタイプの作業なので、毎回その場で確認してから手を動かしてくれるのは助かりました。
実際、「昔は別サービスへリダイレクトしていたはず」と思っていたドメインが、実は切り替え前からとっくに到達不能だったことも、この過程で判明しています。

接続も全部 AWS Systems Manager(SSM)経由で、SSH は一度も使っていません。22番ポートを開けずに済みました。

一方で、丸投げはできません。
「これを消していいか」「本番を止めていいか」といった判断は全部こちらに聞いてきますし、聞いてこないと困ります。
やらせるのは調査・手順化・実行で、決めるのは人間、という分担がちょうどよかったです。

作った手順書やバックアップも、AI 側から「復元できるか実際に試しましょう」と言ってきて、試したら自分の作り込みのバグが見つかりました。
作れたことと、動くことは別というのを、あらためて思い知らされた作業でした。

コメントを残す

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください