PHPの緊急更新が必要になり、私のブログをLightsailのBitnami版WordPressから、Lightsail公式のWordPressイメージへ移行しました。この記事はその作業記録です。古いサーバーをすぐ消さず、バックアップをサーバー外にも置き、復元・再起動・公開後の表示を順に確かめました。
同じ構成なら追いやすいように、実際に使ったパスと確認方法を書きます。コマンド中の example.com、OLD_IP、NEW_IP、鍵ファイル名は自分の値に置き換えてください。秘密鍵、DBパスワード、実際のIP、アカウント番号は掲載していません。WordPressマルチサイト、別のDBサーバー、独自のテーマ・アプリがある場合は追加の移行手順が必要です。
今回の環境と、移行を選んだ理由
| 項目 | 旧サーバー | 新サーバー |
|---|---|---|
| 提供イメージ | WordPress by Bitnami | WordPress by Lightsail |
| WordPress | 6.5.13 | 7.1.3 |
| PHP | 8.2.19 | 8.2.35 |
| インスタンス | 東京、1GB RAM・2 vCPU・40GB SSD | 東京、同じサイズ・月額7ドルのプラン |
| 主な配置場所 | /opt/bitnami/wordpress |
/var/www/html |
PHP 8.2.35は今回の重大な脆弱性2件を修正したリリースです。PHP公式のリリース案内で確認できます。古いBitnami環境のPHPをその場で入れ替える方法もありますが、今回はWordPress本体や設定を含めて新しい管理方式へ移すことにしました。AWSは、既存のBitnamiインスタンスを更新して使い続ける方法と、新しいLightsailイメージへ移行する方法の両方を案内しています。AWSの移行案内
1. 旧環境を確認し、変更を止めてバックアップする
まず投稿やコメント、フォームなどの書き込みが移行中に増えないよう、メンテナンスに入ります。私の旧環境ではApacheが静的な503ページを返し、古いPHP-FPMが起動しない状態にしました。WordPressプラグインのメンテナンス表示だけではPHP自体が動くため、今回の一時隔離策として同じ意味にはなりません。旧サーバーの設定方式が異なる場合は、PHPへの外部リクエストを確実に止められる方法を選んでください。
より確実に切り戻せるよう、Lightsail管理画面の旧インスタンスで「スナップショット」→「手動スナップショットを作成」を推奨します。スナップショットは同じ環境に戻すための保険です。私の作業では移行直前のスナップショットは作らず、旧インスタンスを残し、WordPressのデータをサーバー外にも保存しました。古いスナップショットだけでは移行直前の状態に戻せません。バックアップ領域の空きを先に df -h で確認してください。スナップショットには保存料金がかかります。AWSのスナップショット手順
旧BitnamiサーバーにSSH接続して、DBと wp-content を退避します。wp-content には画像、テーマ、プラグインなどが入ります。ここではBitnami付属のWP-CLIラッパーを使うため sudo wp です。
sudo install -d -o bitnami -g bitnami -m 700 /home/bitnami/migration-backup
sudo wp --path=/opt/bitnami/wordpress db prefix
sudo wp --path=/opt/bitnami/wordpress db export /home/bitnami/migration-backup/wordpress.sql --add-drop-table
sudo tar -C /opt/bitnami/wordpress -czf /home/bitnami/migration-backup/wp-content.tar.gz wp-content
sudo chown bitnami:bitnami /home/bitnami/migration-backup/*
chmod 600 /home/bitnami/migration-backup/*
cd /home/bitnami/migration-backup
sha256sum wordpress.sql wp-content.tar.gz > SHA256SUMS
sha256sum -c SHA256SUMS
このSQLには「既存テーブルを削除して作り直す」命令が入ります。移行先の初期DBをバックアップしてから読み込んでください。WordPress以外の独自アプリ、cron、メール送信設定、証明書、Webサーバー設定も棚卸しします。私の環境ではWordPressの裏に資金残高シミュレーターがあり、別途移行が必要でした。
手元のPCへコピーし、照合します。以下はLinux/macOSまたはWindowsのWSLで実行する例です。SSH鍵はPCに保管し、サーバーへ秘密鍵をコピーしません。
export OLD_IP='旧サーバーのIPv4'
export KEY_OLD="$HOME/.ssh/旧サーバー用の秘密鍵.pem"
scp -i "$KEY_OLD" -r "bitnami@$OLD_IP:/home/bitnami/migration-backup" "$HOME/"
chmod -R go-rwx "$HOME/migration-backup"
cd "$HOME/migration-backup"
sha256sum -c SHA256SUMS
ハッシュが一致し、SQLとアーカイブがPCにもあることを確認してから次へ進みます。サイトに書き込みが入った後のバックアップでは差分が失われるので、メンテナンス開始後に最終バックアップを取るのが肝心です。
2. 修正版PHPを含む新インスタンスを作る
Lightsailの「インスタンスの作成」で東京リージョンを選び、「リナックスアプリ」→WordPress 7.1 / Lightsailを選択しました。「WordPress Multisite」や古いBitnami版と取り違えないようにします。下の図は実際の作成画面を基に、公開用に匿名化して再構成したものです。画面上のバージョンや料金は作成時点の表示で、今後変わる可能性があります。

プランは1GB RAM・2 vCPU・40GB SSDの月額7ドルを選びました。以前のサーバーと同じメモリ・ディスク容量です。アクセスは減っていましたが、旧環境ではPHP停止中でもメモリに余裕が少なく、512MBではWordPressと別アプリの同居に不安がありました。自分のサイトではディスク使用量、メモリ、同居サービスを先に確認してください。スナップショットから小さいディスクのプランへは戻せません。AWSの説明

作成したらSSHでログインし、PHPの実際のバージョンを確認します。イメージのWordPress 7.1という表示だけで、PHPが修正版だとは判断できません。今回の新環境はPHP 8.2.35でした。
ssh -i "$HOME/.ssh/新サーバー用の秘密鍵.pem" admin@NEW_IP
php -v
sudo apache2ctl -M | grep -E 'php|proxy_fcgi'
wp --path=/var/www/html core version
sudo apache2ctl configtest
php -v はCLI版の確認です。Apacheで使うPHPモジュールやPHP-FPMのパッケージも確認し、Web側が修正版を使っているか照合してください。今回の環境ではApacheの php_module と修正版PHPを確認しました。新しいLightsail WordPressではWP-CLIをadminユーザーで実行します。旧Bitnamiの sudo wp をそのまま持ち込まないでください。AWSの更新手順
SSHのポート22は自分の接続元IPに限定し、LightsailのブラウザSSHも復旧経路として残しました。私は従来のSSHコマンドを使い続けるため、新サーバーに互換ユーザーと既存鍵の公開鍵を登録しました。一般的には新環境の admin ユーザーで十分です。秘密鍵をサーバーへコピーする必要はありません。接続元IPが変わったらファイアウォールの許可元も更新します。
3. 公開前の新サーバーを隔離し、WordPressを復元する
復元途中の新サーバーを公開しないため、Apacheで通常ページへの外部アクセスを拒否しました。私が使った設定例です。証明書のHTTP認証に必要なパスだけ例外にします。設定を有効化したら必ず構文を検査してください。
<Location />
Require local
</Location>
<Location "/.well-known/acme-challenge/">
Require all granted
</Location>
sudoedit /etc/apache2/conf-available/migration-private.conf
# 上のLocation設定を保存してから続ける
sudo a2enconf migration-private
sudo apache2ctl configtest
sudo systemctl reload apache2
ホストの管理画面やSSHまで閉じる設定ではありません。構成によってApacheの認可設定が異なるので、外から通常ページを見たときに403になり、ローカルからは読めることを確認します。
移行先の初期状態もバックアップし、旧サーバーのファイルをPCから転送します。下のコマンドは新サーバーに admin でログインした状態の例です。
mkdir -p "$HOME/migration-incoming"
chmod 700 "$HOME/migration-incoming"
wp --path=/var/www/html db export "$HOME/migration-incoming/fresh.sql"
sudo tar -C /var/www/html -czf "$HOME/migration-incoming/fresh-wp-content.tar.gz" wp-content
sudo chown admin:admin "$HOME/migration-incoming/fresh-wp-content.tar.gz"
chmod 600 "$HOME/migration-incoming/"*
PC側で次のように送ります。
export NEW_IP='新サーバーのIPv4'
export KEY_NEW="$HOME/.ssh/新サーバー用の秘密鍵.pem"
scp -i "$KEY_NEW" "$HOME/migration-backup/wordpress.sql" "$HOME/migration-backup/wp-content.tar.gz" "admin@$NEW_IP:/home/admin/migration-incoming/"
新サーバーで復元します。これは新規作成した移行先のDBを上書きする操作です。接続先と fresh.sql の存在を確認してください。旧サーバーと新サーバーの wp db prefix の結果も比較し、異なる場合は新サーバーの wp-config.php の接頭辞を調整してから進めます。アーカイブには古いバックアッププラグインの保存領域が含まれる場合があります。復元前に tar -tzf で中身を見て、公開領域へ戻す必要のないバックアップやキャッシュを除外します。
cd "$HOME/migration-incoming"
tar -tzf wp-content.tar.gz | head
wp --path=/var/www/html db prefix
wp --path=/var/www/html db import wordpress.sql
sudo tar --no-same-owner \
--exclude='wp-content/updraft' \
--exclude='wp-content/ai1wm-backups' \
--exclude='wp-content/cache' \
-xzf wp-content.tar.gz -C /var/www/html
sudo chown -R admin:www-data /var/www/html/wp-content
sudo find /var/www/html/wp-content -type d -exec chmod g+ws {} +
wp --path=/var/www/html core update-db
wp --path=/var/www/html db check
除外したディレクトリは元のアーカイブとPC側バックアップに残ります。wp-config.php やWordPress本体を旧Bitnami環境から丸ごと上書きしません。新旧でDB接続情報、パス、Apacheとの連携方法が違うためです。
4. URL、プラグイン、別アプリを確かめる
DBの home と siteurl を本番URLへ合わせます。新イメージの /var/www/wp-config.php に WP_HOME / WP_SITEURL が定義されている場合、そちらがDBの設定より優先されます。今回も最初はホスト名から動的にURLを作る定義だったため、確認して本番URLに合わせました。定義を重複させず、既存行を編集します。
sudo grep -nE 'WP_HOME|WP_SITEURL' /var/www/wp-config.php
sudoedit /var/www/wp-config.php
# 既存の定義を次のような本番URLに合わせる
# define( 'WP_HOME', 'https://example.com' );
# define( 'WP_SITEURL', 'https://example.com' );
wp --path=/var/www/html option update home 'https://example.com'
wp --path=/var/www/html option update siteurl 'https://example.com'
wp --path=/var/www/html option get home
wp --path=/var/www/html option get siteurl
記事やウィジェット内に旧IPなどのURLが残る場合は、シリアライズ済みデータも扱えるWP-CLIでdry-runを見てから置換します。今回の環境では旧IP参照が182件見つかりました。自分のサイトにその参照がなければ、この置換は不要です。WP-CLIの説明
wp --path=/var/www/html search-replace 'http://OLD_IP' 'https://example.com' \
--all-tables-with-prefix --skip-columns=guid --dry-run
# 件数と置換対象を確認できた場合だけ実行する
wp --path=/var/www/html search-replace 'http://OLD_IP' 'https://example.com' \
--all-tables-with-prefix --skip-columns=guid
プラグイン・テーマは互換性を確認して更新します。WordPress 6.5系から7.1系への移行では、管理画面が開くことだけでなく、問い合わせフォーム、ログイン、キャッシュ、画像、メール、バックアップも点検します。今回も有効プラグインの更新を実施しました。
wp --path=/var/www/html plugin list --fields=name,status,version,update
wp --path=/var/www/html theme list --fields=name,status,version,update
私のサイトにはWordPressとは別のPython製シミュレーターがありました。/srv/ のアプリ本体とsystemdサービスを移し、ApacheのAPIプロキシを設定しました。旧Bitnami専用ディレクトリを前提とするsystemd制限は新環境では合わず、修正してから起動できました。「WordPressが表示された」だけでは移行完了ではありません。 別アプリ、cron、メール、証明書更新も一覧にして確認します。
5. 静的IPを切り替え、HTTPSを取り直す
WordPressと別アプリの内部検査が通ってから、Lightsailの「ネットワーキング」で旧サーバーに付いていた静的IPをデタッチし、新サーバーへアタッチします。同じ静的IPならDNSのAレコードを変えずに切り替えられます。IPの移し先を間違えないよう、静的IP名とアドレスを作業前に控えます。旧インスタンスを削除する操作ではありません。AWSの静的IP説明

切替後にLet’s Encryptの証明書を新サーバーで取得しました。以下は今回使ったWebroot方式の要点です。example.com が新サーバーを指し、ポート80が開き、上のACMEパスが読める状態で実行します。certbot がない場合はディストリビューション公式パッケージから導入します。
sudo certbot certonly --webroot -w /var/www/html -d example.com
sudoedit /etc/apache2/sites-available/default-ssl.conf
# SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem
# SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
sudo apache2ctl configtest
sudo systemctl reload apache2
sudo systemctl enable --now certbot.timer
sudo certbot renew --dry-run
上の証明書パスは、default-ssl.conf の既存の SSLCertificateFile と SSLCertificateKeyFile を置き換える値です。更新成功時のApache再読込を忘れないよう、私は次のdeploy hookも設定しました。設定後にdry-runと手動再読込を確認します。
sudo install -d -m 755 /etc/letsencrypt/renewal-hooks/deploy
sudo tee /etc/letsencrypt/renewal-hooks/deploy/reload-apache.sh >/dev/null <<'EOF'
#!/bin/sh
set -eu
/bin/systemctl reload apache2
EOF
sudo chmod 755 /etc/letsencrypt/renewal-hooks/deploy/reload-apache.sh
sudo /etc/letsencrypt/renewal-hooks/deploy/reload-apache.sh
sudo certbot renew --dry-run
証明書の秘密鍵を記事やGitHubへアップロードしないでください。AWSのLightsail SetupでHTTPSを設定する方法もあります。AWSのWordPressガイド
公開可能な状態になってから一時隔離を解除します。
sudo a2disconf migration-private
sudo apache2ctl configtest
sudo systemctl reload apache2
6. 「起動した」で終わらせず、再起動後まで確認する
記事、管理画面、REST API、画像、問い合わせフォーム、別アプリの画面とAPIを開きます。私の環境ではシミュレーターの画面で実際に計算結果が出るところまで試しました。HTTPからHTTPSへの転送、証明書検証、ログのエラーも確認します。
sudo systemctl reboot
# SSHで再接続したあと
systemctl is-active apache2 mariadb certbot.timer
systemctl is-enabled apache2 mariadb certbot.timer
wp --path=/var/www/html db check
curl -sS -L -o /dev/null -w '%{http_code} %{ssl_verify_result}\n' https://example.com/記事URL
curl -sS -L -o /dev/null -w '%{http_code} %{ssl_verify_result}\n' https://example.com/wp-json/
上の 記事URL は存在する記事のパスに置き換えます。200 0 は、ここではページ応答200とTLS証明書検証成功を表します。ただし、フォーム送信や別アプリの実際の操作も確認してください。再起動後の自動起動設定が抜けていると、その場の成功だけでは見落とします。
切り戻しと、旧サーバーを消すタイミング
切替で異常が出たら、静的IPを旧インスタンスへ戻せます。ただし私の旧サーバーは脆弱なPHPを停止したままなので、戻した直後は503メンテナンスになります。安全確認なしに古いPHPを再公開しない方針です。旧サーバーとサーバー外バックアップは、十分な実運用確認が済むまで保持しています。Lightsailは停止してもインスタンス料金が続くため、削除を決めるまでは2台分の費用がかかります。AWSの課金FAQ
今回の作業で特に重要だったのは、①旧環境を隔離して最終バックアップを取る、②移行先のPHPが修正版か確認する、③WordPress以外のサービスも棚卸しする、④静的IPと証明書を切り替える、⑤再起動後に実ページと機能を試す、という順番です。個々のサイトの構成は違うので、各段階で確認が通らなければ次へ進まず、バックアップから戻せる状態を維持してください。
なおPHP 8.2.35は今回の脆弱性には修正版ですが、PHP公式の案内によればPHP 8.2系は2026年12月31日にサポート終了予定です。移行後も次のPHP系列への更新計画が必要です。

コメント