前回の記事で、「このブログのサーバーにはPHPの修正パッケージが来ない」と書きました。CentOS 7とPHP 7.4のKUSANAGI 8で、どちらもとっくにサポート切れだったからです。
結論から言います。申し込みからDNS切り替えまで半日、同じ日のうちに本登録まで終わりました。PHPは7.4から8.3へ、OSはCentOS 7からAlmaLinux 9へ、KUSANAGIは8から9へ。9年動かしてきた環境が、1日で全部入れ替わっています。
「9年ものの環境をそんな簡単に動かせるのか」と思う方もいると思います。自分も最初はそう思っていました。ただ、冷静に考えるとWordPressの引っ越しで運ぶものは wp-content ディレクトリとデータベースの2つだけです。荷物は少ない。時間がかかるとしたら、荷物の量ではなく段取りの方です。
この記事では、その段取りを順番に書きます。事前に本番と同じ条件で動作確認する方法、DB移行時の落とし穴、切り替えた後にハマった2つ。同じようにVPSでWordPressを動かしていて、OSやPHPのサポート切れが気になっている方の参考になれば嬉しいです。
移行先の選び方|同じさくらVPSでKUSANAGI 9を選んだ理由
移行先は、同じさくらのVPSでKUSANAGI 9のイメージを選びました。理由は単純で、さくらのVPSの標準OSに「KUSANAGI 9(AlmaLinux 9)」が用意されているからです。サーバー作成画面でOSにKUSANAGIを選ぶと、バージョンでAlmaLinux 9かCentOS Stream 9が選べます。AlmaLinux 9はサポートが2032年までなので、迷わずこちらを選びました。
ゾーンは石狩第1です。これは選んだというより、東京第2が新規受付を停止していて選べませんでした。旧サーバーは東京にあるので、ゾーンが変わることになりますが、ブログの表示速度で差が出るレベルではありません。
プランは1G(メモリ1GB / SSD 50GB / 2コア、月880円)にしました。実は旧サーバーは512MBプランで、移行直前に free -m で見たらメモリ使用366MBにswap 186MBという状態でした。KUSANAGIの公式推奨は4GB以上なので心細い数字ですが、個人ブログのアクセス量なら1G + swapで足りると判断しました。足りなければスケールアップで2Gにできます。
契約条件は前回の記事に書いたとおりで、クレジットカード払いなら2週間無料、本登録後の最低利用は3か月です。お試し期間中は外向きの25番ポートが閉じていてメールが送れないので、後半のメール設定はここが効いてきます。
サーバー作成でつまずく前に|管理ユーザー名とパケットフィルターの初期状態
サーバーの作成は、作成画面でポチポチ選んでいくだけですが、2つだけ事前に知っておくと楽な点があります。
1つ目は、ログインユーザー名です。 KUSANAGI 8のころは kusanagi ユーザーで入っていましたが、KUSANAGI 9のAlmaLinux 9イメージでは管理ユーザーが alma になります。パスワードは作成画面で自分が決め、SSH鍵は自分の公開鍵を登録します(新規で用意しても既存のものでも構いません)。「パスワードによるログインを許可しない」にチェックを入れて、鍵認証のみにしました。
2つ目は、パケットフィルターです。 さくらのVPSのパケットフィルターは、初期状態ではSSH(22番)しか開いていません。ここにWeb(80/443)を自分で足す必要があります。これを忘れると、後でLet’s Encryptの証明書を取るときにHTTP-01チャレンジが80番に届かず失敗します。作成完了画面にフィルターの状態が出るので、そこで足しておくのが確実です。
申込が完了すると、IPアドレスと管理ユーザー名が表示されます。ここから先はSSHでの作業です。
初期設定|1Gプランはswapを作らないとdnfが死ぬ
SSHで入って最初にやったのは、順番に次の4つです。
- SSHのポートを22番から別の番号に変更(ボットの総当たりログを減らすため)
- swapの作成
dnf upgradeと再起動kusanagi initでミドルウェアの選択
ポート変更で1つ注意点があります。AlmaLinux 9はSELinuxが有効なので、sshd_config を書き換えるだけではsshdが起動しません。semanage port -a -t ssh_port_t -p tcp <番号> で新しいポートをSELinuxに登録する必要があります。semanage コマンドは policycoreutils-python-utils パッケージに入っています。あわせて、さくら側のパケットフィルターもSSHの許可ポートを新しい番号に変えます。
ここで最初にハマりました。 swapを作る前に dnf upgrade を打ったところ、リポジトリのメタデータを読み込んでいる途中で Killed と出て止まります。1GBプランは初期状態でswapがなく、dnfのメタデータ処理だけでメモリを使い切ってOOM Killerに落とされていました。
対処は単純で、先にswapを2GB作ります。
fallocate -l 2G /swapfile
chmod 600 /swapfile
mkswap /swapfile
swapon /swapfile
echo '/swapfile none swap sw 0 0' >> /etc/fstab
これで dnf upgrade は通りました。1Gプランでいくなら、swapは「あった方がいい」ではなく「ないと初期設定すら終わらない」です。
dnf upgrade と再起動のあと、kusanagi init でミドルウェアを選びます。KUSANAGI 9はnginxのバージョン、PHPのバージョン、DBの種類をinitの引数で指定する方式です。自分は --nginx131 --php83 --mariadb10.11 で、nginx 1.31 / PHP 8.3 / MariaDB 10.11の組み合わせにしました。引数名はバージョンによって変わるので、kusanagi init --help で確認してから打つのが安全です。
続けて kusanagi provision でサイトのプロファイルを作ります。--wp でWordPress用、--fqdn tsukarooohi.com --with-www でドメイン、--dbname と --dbuser は旧サーバーのwp-config.phpに合わせました。DB名とユーザー名を旧と同じにしておくと、後でwp-config.phpをそのまま持ってこられて差分が小さくなります。
もう1つ、DNSを切り替える前なのでLet’s Encryptはまだ取れません。provisionに --noemail を付けて証明書の取得をスキップし、切り替え後に kusanagi ssl で取る段取りにしました。
ここまでで、空のKUSANAGI 9が動いている状態になります。
旧→新の転送|wp-contentをrsync、DBはキャッシュ表を除外してmysqldump
運ぶものは2つです。wp-content ディレクトリ(テーマ・プラグイン・アップロード画像で1.7GB)と、データベースのダンプ。
転送は新サーバーから旧サーバーへ取りに行く形にしました。 Macから新サーバーに ssh -A でエージェント転送して入り、新サーバーの中から旧サーバーへrsyncします。こうすると、旧サーバーの秘密鍵を新サーバーに置かずに済みます。
# 新サーバーで(ssh -A で入っている前提)
sudo -E rsync -avz --delete -e 'ssh -p <旧のSSHポート>' \
kusanagi@<旧IP>:/home/kusanagi/<旧プロファイル>/DocumentRoot/wp-content/ \
/home/kusanagi/<新プロファイル>/DocumentRoot/wp-content/
転送後に所有者を kusanagi:www に、権限をディレクトリ775 / ファイル664に揃えました。旧サーバーでは一部が777になっていたので、ついでに直しています。
DBは旧サーバーで mysqldump を取って新サーバーで流し込みます。ここで2つのテーブルを除外しました。
wp_site_cache: KUSANAGIのページキャッシュ(bcache)用。新サーバーで作り直すので不要wp_popularpostssummary: WordPress Popular Postsのアクセス集計。統計は切替日から積み直せばよい
mysqldump --single-transaction --default-character-set=utf8mb4 \
--ignore-table=<DB名>.wp_site_cache \
--ignore-table=<DB名>.wp_popularpostssummary \
<DB名> | gzip > <DB名>.sql.gz
ここに落とし穴がありました。 --ignore-table は、中身だけでなくテーブル定義ごと落とします。新サーバーで流し込んだ後、wp_popularpostssummary がテーブルごと存在しない状態になっていました。旧サーバーで mysqldump --no-data を使って定義だけ取り直し、新サーバーに作ってから解決しています。「中身は要らないけど表は要る」テーブルは、最初から --no-data で別に取っておくのが正解です。
wp-config.php は旧のものをコピーして、3点だけ直しました。
| 項目 | 変更 | 理由 |
|---|---|---|
FS_METHOD |
direct に |
KUSANAGI 9はFTP経由でなく直接書き込む方式 |
FTP_* の定義 |
削除 | 上と同じ理由で不要 |
WP_CACHE |
false に |
KUSANAGI 8のbcache用。9では後で kusanagi bcache on が書き換える |
あわせて、旧の advanced-cache.php(KUSANAGI 8のキャッシュ用ドロップイン)は wp-content から外して退避しました。残しておくとKUSANAGI 9のキャッシュ初期化と衝突します。
DNSを切り替える前に確かめる|「DBにURLが保存されている」問題はhostsで解決
移行で自分が一番気にしていたのは、ここでした。
WordPressのデータベースには、サイトのURLがドメイン付きで入っています。wp_options の siteurl と home は https://tsukarooohi.com、記事本文中の画像パスや内部リンクも全部このドメインです。なので、新サーバーをさくらの仮ドメイン(xxx.vs.sakura.ne.jp)で開いて確認しようとすると、WordPressが「ここは tsukarooohi.com のはずだ」とリダイレクトをかけたり、画像パスが本番ドメインを向いて旧サーバーの画像を表示したりして、まともに確認できません。
よくある対処は、Search Replace系のプラグインやWP-CLIでDB内のURLを仮ドメインに書き換えて確認し、切り替え時に本番ドメインへ戻す方法です。できなくはないですが、2回書き換える手間と、戻し忘れのリスクがあります。
今回はDBを一切書き換えず、Macの /etc/hosts で解決しました。
# Mac の /etc/hosts に追加
<新IPアドレス> tsukarooohi.com www.tsukarooohi.com
DNSは世界共通の電話帳で、hostsは自分のスマホの連絡先だと思うとしっくりきます。電話帳(DNS)を書き換える前に、自分の連絡先(hosts)だけ新しい番号に登録して、試しにかけてみる。相手(WordPress)からは本番ドメインで呼ばれているように見えるので、何も気づきません。自分のMac以外の人には影響なし、仮ドメインは一度も使いません。
残る問題はHTTPSです。URLがhttpsなので証明書が要りますが、DNSが旧サーバーを向いている間はLet’s Encryptが新サーバー向けに発行してくれません。これは、旧サーバーの /etc/letsencrypt/live/ にある証明書と秘密鍵を新サーバーにコピーして、nginxの ssl_certificate を一時的にそこへ向けることでしのぎました。同じドメインの正規の証明書なので、ブラウザから見れば何の問題もありません。切り替え後に正規取得したら削除します。
この状態で確認した項目です。
- 管理画面のログイン。初回に「データベースの更新が必要です」と出るので、1クリックで更新
- REST APIで全記事が返ること。Rinkerのショートコードが展開されていること
- Table of Contents Plusの目次、Simple Lightboxの画像表示
- メディアアップロード(multipartのPOSTが通ること。前回の緩和策で遮断していた部分なので念入りに)
- サイトヘルス
そして、2017年のSTORK 1.3.9はPHP 8.3で動きました。 白画面もFatal errorもなし。前回の記事で一番心配していた点は、拍子抜けするほどあっさり通っています。ただ、このまま使い続けるつもりはなく、切り替え後に最新版へ更新しました(後述)。
サイトヘルスで残ったのは「バックグラウンド更新が利用できない」と「ページキャッシュが検出されない」の2つで、どちらも切り替え後に対処する項目です。ここまで来れば、DNSを切り替える準備は整っています。
DNSの切替|Route 53のTTLを60にしてからAレコードを差し替える
このブログのDNSはAWSのRoute 53で管理しています。切り替えの手順は4つです。
1. 切り替えの少し前にTTLを下げておく。 Aレコードは300秒でしたが、60秒に下げました。TTLはDNSの答えをキャッシュしてよい時間なので、切り替え前に短くしておくと、切り替え後に古いIPを見続ける人が減ります。下げた値が行き渡るのに元のTTL分(300秒)かかるので、切り替えの直前ではなく少し前に下げるのがポイントです。
2. DBを取り直す。 hostsで確認している間にも旧サーバーにはコメントが付いたりしうるので、切り替え直前に旧サーバーでもう一度mysqldumpを取って、新サーバーに流し直しました。wp-content も --delete 付きでrsyncし直しています。
3. Aレコードを新IPに変更。 同時に、SPFレコードに新サーバーのIPを追加しました。旧サーバーからもしばらくメールが出る可能性があるので、この時点では新旧両方を残しています。dig +short コマンドで新IPが返るのを確認して次へ進みます。
4. Let’s Encryptで正規の証明書を取る。 DNSが新サーバーを向いたので、ようやく証明書が取れます。KUSANAGI 9では kusanagi ssl コマンド一発です。
kusanagi ssl --email <メールアドレス> --https redirect --auto on <プロファイル名>
--https redirect でhttp→httpsの301リダイレクト、--auto on で自動更新が有効になります。証明書はapexとwwwの両方がSANに入った状態で発行され、自動更新はKUSANAGIが管理します(certbotのタイマーはKUSANAGIが無効化していました)。取れたら、一時流用していた旧サーバーの証明書は削除しました。
最後にMacのhostsから追加した行を消し、本物のDNSで記事と管理画面を開いて確認。14時30分に切り替え完了です。旧サーバーは念のため30分ほど動かしたままにして、15時ごろに停止しました。
切替後にハマった2つ|mu-pluginsの先祖返りとbcacheの初回セットアップ不発
切り替えが終わったので、サイトヘルスに出ていた「ページキャッシュなし」を解消しに行きます。KUSANAGI 9では kusanagi bcache on <プロファイル名> でページキャッシュが有効になるはずでした。ここで2つハマりました。
1つ目は、mu-pluginsがKUSANAGI 8のものに戻っていた件です。 wp-content を --delete 付きでrsyncしたので、新サーバーのprovisionで置かれていたKUSANAGI 9用の mu-plugins が、旧サーバーの2017年版(KUSANAGI 8用)で上書きされていました。bcacheを有効にしても何も起きないので調べたら、これが原因でした。/opt/kusanagi/lib64/kusanagi/resource/DocumentRoot/wp-content/mu-plugins にKUSANAGI 9用の原本があるので、そこからコピーし直しています。
2つ目は、旧DBに残っていたオプション値です。 mu-pluginsを直しても、bcacheの初回セットアップ(wp_site_cache テーブルの作成と advanced-cache.php の生成)が走りません。原因は、旧DBから持ってきた wp_options に site_manager_cache_installed = 5 という値が残っていたことでした。KUSANAGIのプラグインはこの値を見て「もうセットアップ済み」と判断してスキップします。中身は新しいのに、DBだけが旧環境の記憶を持っている状態です。
対処は、wp_site_cache テーブルを手で作り、site_manager_cache_installed のオプション行を削除してから管理画面を開き直す。これで初回セットアップが走り、レスポンスヘッダーに x-b-cache: cache が出るようになりました。
この2つに共通するのは、移行元のデータには移行元の環境の状態が焼き付いているということです。ファイルを丸ごと持ってくれば、KUSANAGI 8の部品も一緒に来る。DBを丸ごと持ってくれば、KUSANAGI 8で設定済みという記録も一緒に来る。「環境側のファイルとオプション」と「自分のコンテンツ」を分けて考えないと、こういう形で噛み合わなくなります。
ようやく「更新」を押せた|STORK 1.3.9→1.4.3、PHP 8.3で動いた
キャッシュが動いたので、ずっと押せなかった管理画面の「更新」をまとめて実行しました。
- WordPress本体を7.1.4(最新)に
- プラグイン20個を全て最新に
- STORKを1.3.9から1.4.3へ
STORKはOPEN CAGEの正規配信から、PHP 8対応版の1.4.3に更新しました。子テーマ(jstork_custom)は有効のまま、見た目の崩れもなし。1.3.9のままでもPHP 8.3で動いてはいましたが、テーマ側がPHP 8を正式にサポートしているバージョンにしておく方が、次にPHPを上げるときも安心です。
サイトヘルスのcriticalの正体|wp-config-sample.phpの権限
サイトヘルスの「バックグラウンド更新が利用できない」の原因は、wp-config-sample.php の権限でした。rsyncで持ってきたこのファイルだけ書き込み権限がなく、WordPressの自動更新チェックがそこで引っかかっていました。664にしたら解決します。criticalの表示にしては原因が地味すぎて、少し拍子抜けしました。
KUSANAGIのFTP警告|direct方式なら無視してよい
KUSANAGIの管理画面に「FTP接続情報が設定されていません」という警告が出ます。これはKUSANAGI独自の自動更新タブ用で、FS_METHOD を direct にしている構成では無視して問題ありません。
メールと本登録|DKIM鍵を持ち越し、OP25B解除を待つ
このブログからのメールは、Contact Form 7の問い合わせ通知だけですが、SPFとDKIMを設定してあります。旧サーバーの /etc/opendkim と /etc/postfix を丸ごと退避しておいて、新サーバーでopendkimをEPELから入れ、鍵とKeyTable / SigningTable / TrustedHostsをそのまま配置しました。DNSのDKIMレコードは変えていないので、同じセレクタ(m1)の鍵をそのまま使い続けられます。
テスト送信で DKIM-Signature d=tsukarooohi.com s=m1 が付くところまでは確認できました。ただ、ここで冒頭の「お試し期間中は25番ポートが閉じている」が効いてきます。メールはキューに溜まったまま出ていきません。
なので、動作確認が終わったこのタイミングで本登録しました。2週間の無料期間を使い切らずに本登録したのは、OP25Bの解除が本登録から約72時間後だからです。無料期間を引っ張るより、問い合わせフォームを早く復旧させる方を取りました。
16時30分に本登録完了。申込からちょうど半日でした。
まとめ|引っ越しは荷物より段取り
今回の移行を3つにまとめます。
- DNSを切り替える前に、本番そっくりの条件で確認する。 DBのURLは書き換えず、自分のMacのhostsで新サーバーを本番ドメインとして見る。証明書は旧サーバーのものを一時流用する。これで仮ドメインを一度も使わずに済みました。
- 移行元のデータには、移行元の環境が焼き付いている。 mu-pluginsの先祖返りも、
site_manager_cache_installedも、「コンテンツ」と「環境側のファイル・設定」を分けずに丸ごと運んだのが原因です。KUSANAGIに限らず、キャッシュ系や管理系のプラグインを使っているなら同じことが起きます。 - 1Gプランならswapは最初に作る。 これがないと
dnf upgradeすら完走しません。
前回の記事で「動いているから、は対策ではない」と書きました。今回やってみて、載せ替え自体は半日で終わる作業でした。9年間やらなかった理由は難しさではなく、「いつか」で済ませていただけだったと思います。
残っている作業は、OP25B解除後のContact Form 7の送信テスト、旧サーバーの解約とSPFからの旧IP削除、それから別サーバーで運用しているもう1つのサイトの移行です。そのあたりは、またどこかで記事にするかも知れません。
同じようにCentOS 7のVPSでWordPressを動かしている方は、よかったら一緒に試してみてください。















