『PHP8 KUSANAGI9』WordPressマルチサイトで発生する bcache の罠?

WordPress

見た目は「OGPの不具合」、実際はサイト全体の致命エラーだった

以前のkusanagi8のサーバーから5年ぶりに新規サーバーへ引っ越し。

PHP7から8へ。kusanagiも8から9へ移行。

WordPressのマルチサイト運用だったせいか、かなり手こずりました。

引っ越し自体はうまくいったものの、マルチサイトの親サイトは問題なかったが子サイトのOGP(facebookやXなどのサムネイルやリンク)だけが正しく出ない現象が起こっていた。

最初は単なるSNSメタタグの問題だと思いがちだが、実際にログを追うと、原因は KUSANAGIのbcache(静的キャッシュ)だった。

そしてこの問題は、見た目のOGPどころか、子サイトのページ全体が500エラーで「死んでいた」 という深刻なケースだった。

なぜすぐに気づかなかったかというと「ログイン中は子サイトは綺麗に表示されていた」からだ。

つまり外部からは503なのだがログインしている自分だけは綺麗に表示されていたのである。

なのでOGPの問題だけかと2週間くらい気づかなかった(笑)

つまりOGPは全く問題なくて、記事そのものが表示されていなかったのだ。

■ 現象の概要

※〇〇〇〇は自分のプロファイル名
※△△△△はドメイン

1. 親サイト(例:△△△△.com)では正常

表示も高速で、OGPも正しく出る。
bcache(nginxレイヤー)ONで安定稼働。

2. 子サイト(例:△△△△/□□□□.com)では異常

ログイン中(管理者)→ 通常表示される。
ログアウト中(一般ユーザー)→ 500 Internal Server Error

Facebook/Xでシェアすると OGP が空、もしくはエラー扱い

■ ログから判明した本当の原因

エラーログを確認すると、以下の致命的エラーが大量に記録されていた。

※〇〇〇〇は自分のプロファイル名
※△△△△はドメイン

PHP Fatal error: Uncaught mysqli_sql_exception: Table ‘wp_〇〇〇〇.wp_16_site_cache’ doesn’t exist
in /home/kusanagi/〇〇〇〇/DocumentRoot/wp-content/advanced-cache.php:160

これは、WordPress内部のキャッシュドロップイン advanced-cache.php が全サイト共通で実行され、存在しない wp_XX_site_cache テーブルを参照したためにPHPが落ちたというもの。

■ さらに悪化させたのが bcache(nginx)の仕様

KUSANAGIのbcacheは、WordPressで生成されたHTMLをnginxがディスクにキャッシュし、次回以降はPHPを通さず直接返す構造になっている。

つまり――
一度500エラーのHTMLをキャッシュすると、それ以降も500を返し続ける。

結果として:
一般ユーザーもGooglebotも「死んだHTML」を受け取る。

Search Consoleが「サーバーエラー」「URLがクロールできません」と通知。

外部のOGPクローラーもHTMLを取得できず、サムネイルが出ない。

OGPが壊れていたのではなく、ページそのものがキャッシュごと死んでいたのだ。

■ 恒久対策:WordPressとbcacheを完全分離する

① WordPress内部キャッシュを無効化

※〇〇〇〇は自分のプロファイル名
※△△△△はドメイン

cd /home/kusanagi/〇〇〇〇/DocumentRoot/wp-content/
mv advanced-cache.php advanced-cache.php.off 2>/dev/null
mv object-cache.php object-cache.php.off 2>/dev/null

→ WordPress側のキャッシュ連携を完全停止。
→ bcacheはサーバー(nginx)レイヤーで独立稼働。

② 子サイトでのキャッシュ参照を防止

/home/kusanagi/〇〇〇〇/wp-config.php に以下を追記:

/* stop editing! Happy publishing */
if (defined('BLOG_ID_CURRENT_SITE') && function_exists('get_current_blog_id') && get_current_blog_id() != 1) {
define('WP_CACHE', false);
}

→ 親サイトのみWP_CACHE有効、子サイトは常に安全モードで動作。
→ 子サイトのDBエラー完全封鎖。

③ bcache はONのまま稼働(高速配信維持)

kusanagi bcache on

→ nginxレイヤーのキャッシュは維持されるため、表示速度は変わらない。
→ PHP層キャッシュのみ停止する構成。

④ bcache 自動クリアを安全に再現(RSS監視スクリプト)

WordPressの「記事更新=キャッシュ削除」機能を安全に再現するため、
RSSフィードを監視し、新しい投稿があれば自動で bcache をクリアする。

/usr/local/bin/wp_update_watch.sh

#!/usr/bin/env bash
RSS_URL="https://△△△△.com/feed/"
CACHE_FILE="/tmp/last_rss_check"
CURRENT_HASH=$(curl -s "$RSS_URL" | md5sum | awk '{print $1}')
LAST_HASH=$(cat "$CACHE_FILE" 2>/dev/null)

if [ "$CURRENT_HASH" != "$LAST_HASH" ]; then
echo "$CURRENT_HASH" > "$CACHE_FILE"
/usr/bin/kusanagi bcache clear 〇〇〇〇 >/dev/null 2>&1
fi

cron 登録(5分おき):

(crontab -l 2>/dev/null; echo "*/5 * * * * /usr/local/bin/wp_update_watch.sh >/dev/null 2>&1") | crontab -

→ 新しい記事が公開されるとRSSが更新され、自動的に bcache clear が実行される。

→ WordPressへの負荷なし、マルチサイトでも安全。

■ 現在の状態

WordPress内部キャッシュ OFF advanced-cache.php無効化済み

KUSANAGI bcache ON nginxレイヤーで高速配信中

子サイト 正常表示 500エラー・OGP不具合解消

親サイト 高速 パフォーマンス維持

キャッシュ更新 自動 RSS更新をトリガーに実行

GSC通知 解消へ 正常200レスポンスへ復帰中

■ 管理画面の体感速度

一般訪問者:ほぼ変化なし(bcacheが完全にカバー)

管理画面:0.2〜0.3秒ほど遅延する程度(許容範囲内)

■ 結論

KUSANAGI 9 のマルチサイト環境では、WordPress内部キャッシュとnginxのbcacheを「完全に分離」するのが最適解。
OGP不具合やサーチコンソール警告の裏では、500エラーがbcacheにキャッシュされていた。
その構造的問題を切り離し、RSS監視による自動bcache更新で安定運用が実現できる。

■ 運用メモ(操作 コマンド)

bcache 状態確認

kusanagi bcache status

手動クリア

kusanagi bcache clear 〇〇〇〇

PHP-FPM 再起動

systemctl restart php-fpm

cron 設定確認

crontab -l

■ 余談:このトラブルが教えてくれたこと

最初は「OGPが出ない」という軽微な現象に見えた。

だが実際は、子サイト自体がエラーだった。ログインしてると表示されるせいで気づきにくかったのである笑

コメント

タイトルとURLをコピーしました