こんにちは。今朝からWordPressのプラグインの不具合でブログがアクセス不可になり、ブログを再構築しました。エラーが発生した様子と解決した流れについて記録しておきます。
エラーの原因
このブログはGoogle Compute Engine(以下GCE)にWordPressをインストールして運用しています。様々なプラグインを入れていますが、そのうちの一つ「WP-Stateless」が悪さをしていたようです。
WP-Statelessとは
WP-Statelessは、Google Cloud Storage(以下GCS)経由でメディアをアップロードできるプラグインです。
GCEはAlwaysFreeというサービスがあり、一定の利用量であれば費用が発生しません。そのため、AlwaysFreeに収まるようにCPUや容量を設定して運用することで、ランニングコストを大きく抑えることができます。
GCEで使える無料ストレージは30GBで、それを超えると費用が発生します。しかし、このWP-Statelessプラグインを用いてGCSにアップロードすることでGCEのストレージを消費せずにすみます。GCSは月5GBまで無料で使うことができるため、5GB以内のメディア利用であれば費用はかかりません。気兼ねなく写真や動画をアップロードできます。
AlwaysFreeの規約は逐次変化するため、最新の情報をご確認ください。
エラー発生
そんな便利なWP-Statelessですが、設定が複雑でエラーが起きやすいと感じていました。昨日は特にシステム周りは変えていないのですが、突然サイトにアクセスできなくなりました。
このサイトで重大なエラーが発生しました。
うーん見たくない画面。とりえあずバックアップから復元を試みます。
スナップショットが使えない…だと…
有事に備えて、GCEのスナップショット機能で定期的にバックアップをとっていたのですが、なぜかスナップショットから復元しても、同様のエラーが出ます。どうやらスナップショットが不完全だったようです。
推測ですが、スナップショットを作成するときのアプリケーション整合性
のオプションが必要かもしれません。このオプションを適用するには、GCEのインスタンスを一時停止する必要がありました。次に障害が起こったときに、このオプションを適用したスナップショットで復元したいと思います。
プラグインが怪しい
まず原因を把握するために、GCEのコンソールにログインしてWordPressのプラグインをすべて無効化します。おおよそWordPressの不具合はプラグインだとばっちゃんが言ってました。
NGINXとWordPressが含まれているパッケージの WordPress with NGINX and SSL Certified by Bitnami and Automattic
をインストールした場合は、以下のディレクトリにプラグインがインストールされています。
/opt/bitnami/wordpress/wp-content/plugins
プラグインディレクトリの配下に移動したら、念のためpluginフォルダをバックアップします。
sudo cp -r plugin plugin_bak
その後に、pluginのフォルダ名を変更することで無効化されます。
sudo mv -r plugin plugin_old -r
すべて無効化したら、ログイン画面に再度アクセスします。すると、正常にログインできました。やはりプラグインが原因でした。WordPressのプラグイン画面から一つずつ有効化していった結果、WP-Statelessのときにアクセス不可になりました。
デバッグでエラーを表示する
プラグインのエラーの詳細を探るために、WordPressのデバッグ機能をオンにします。エラー文が表示されるため、セキュリティに注意してください。検証が終了したら再度デバッグ機能をオフにしてください。
wp-config.php
にデバッグの設定があります。以下のコマンドはvimで編集しています。
sudo vim /opt/bitnami/wordpress/wp-config.php
/WP_DEBUG
で検索して該当行を編集します。define{ 'WP_DEBUG', false )
のfalseをtrueに変更して:wq
コマンドでファイルを保存します。
ファイルを保存したら以下のコマンドでphpとnginxを再起動します。
sudo /opt/bitnami/ctlscript.sh restart nginx && sudo /opt/bitnami/ctlscript.sh restart php-fpm
再度ログイン画面にアクセスすると、エラー文がつらつらと書かれていました。
Fatal error: Uncaught Google\Cloud\Core\Exception\ServiceException: {"error":{"code":401,"message":"Invalid Credentials","errors":[{"message":"Invalid Credentials","domain":"global","reason":"authError","locationType":"header","location":"Authorization"}]}} in /bitnami/wordpress/wp-content/plugins/wp-stateless/lib/Google/vendor/google/cloud-core/src/RequestWrapper.php:397 Stack trace: #0 /bitnami/wordpress/wp-content/plugins/wp-stateless/lib/Google/vendor/google/cloud-core/src/RequestWrapper.php(214): Google\Cloud\Core\RequestWrapper->convertToGoogleException() #1 /bitnami/wordpress/wp-content/plugins/wp-stateless/lib/Google/vendor/google/cloud-core/src/RestTrait.php(102): Google\Cloud\Core\RequestWrapper->send() #2 /bitnami/wordpress/wp-content/plugins/wp-stateless/lib/Google/vendor/google/cloud-storage/src/Connection/Rest.php(730): Google\Cloud\Storage\Connection\Rest->traitSend() #3 /bitnami/wordpress/wp-content/plugins/wp-stateless/lib/Google/vendor/google/cloud-storage/src/Connection/Rest.php(258): Google\Cloud\Storage\Connection\Rest->send() #4 /bitnami/wordpress/wp-content/plugins/wp-stateless/lib/Google/vendor/google/cloud-core/src/Iterator/PageIteratorTrait.php(238): Google\Cloud\Storage\Connection\Rest->listObjects() #5 /bitnami/wordpress/wp-content/plugins/wp-stateless/lib/Google/vendor/google/cloud-storage/src/ObjectPageIterator.php(55): Google\Cloud\Storage\ObjectPageIterator->executeCall() #6 /bitnami/wordpress/wp-content/plugins/wp-stateless/lib/Google/vendor/google/cloud-core/src/Iterator/ItemIteratorTrait.php(93): Google\Cloud\Storage\ObjectPageIterator->current() #7 /bitnami/wordpress/wp-content/plugins/wp-stateless/lib/Google/vendor/google/cloud-storage/src/StreamWrapper.php(774): Google\Cloud\Storage\ObjectIterator->current() #8 /bitnami/wordpress/wp-content/plugins/wp-stateless/lib/Google/vendor/google/cloud-storage/src/StreamWrapper.php(604): Google\Cloud\Storage\StreamWrapper->getDirectoryInfo() #9 /bitnami/wordpress/wp-content/plugins/wp-stateless/lib/classes/class-gs-stream-wrapper.php(53): Google\Cloud\Storage\StreamWrapper->url_stat() #10 [internal function]: wpCloud\StatelessMedia\StreamWrapper->url_stat() #11 /opt/bitnami/wordpress/wp-includes/functions.php(2037): file_exists() #12 /opt/bitnami/wordpress/wp-includes/functions.php(2371): wp_mkdir_p() #13 /bitnami/wordpress/wp-content/plugins/wp-stateless/lib/classes/class-bootstrap.php(1057): wp_upload_dir() #14 /bitnami/wordpress/wp-content/plugins/wp-stateless/lib/classes/class-bootstrap.php(1028): wpCloud\StatelessMedia\Bootstrap->convert_to_gs_link() #15 /opt/bitnami/wordpress/wp-includes/class-wp-hook.php(310): wpCloud\StatelessMedia\Bootstrap->post_metadata_filter() #16 /opt/bitnami/wordpress/wp-includes/plugin.php(205): WP_Hook->apply_filters() #17 /opt/bitnami/wordpress/wp-includes/meta.php(633): apply_filters() #18 /opt/bitnami/wordpress/wp-includes/meta.php(572): get_metadata_raw() #19 /opt/bitnami/wordpress/wp-includes/post.php(2492): get_metadata() #20 /opt/bitnami/wordpress/wp-includes/post.php(723): get_post_meta() #21 /opt/bitnami/wordpress/wp-includes/post.php(6733): get_attached_file() #22 /opt/bitnami/wordpress/wp-includes/post.php(6786): wp_attachment_is() #23 /opt/bitnami/wordpress/wp-includes/media.php(192): wp_attachment_is_image() #24 /opt/bitnami/wordpress/wp-includes/media.php(954): image_downsize() #25 /bitnami/wordpress/wp-content/plugins/amp/includes/amp-helper-functions.php(1871): wp_get_attachment_image_src() #26 /bitnami/wordpress/wp-content/plugins/amp/includes/amp-helper-functions.php(1915): amp_get_publisher_logo() #27 /bitnami/wordpress/wp-content/plugins/amp/includes/class-amp-theme-support.php(1718): amp_get_schemaorg_metadata() #28 /opt/bitnami/wordpress/wp-includes/class-wp-hook.php(308): AMP_Theme_Support::start_output_buffering() #29 /opt/bitnami/wordpress/wp-includes/class-wp-hook.php(332): WP_Hook->apply_filters() #30 /opt/bitnami/wordpress/wp-includes/plugin.php(517): WP_Hook->do_action() #31 /opt/bitnami/wordpress/wp-includes/template-loader.php(13): do_action() #32 /opt/bitnami/wordpress/wp-blog-header.php(19): require_once('...') #33 /opt/bitnami/wordpress/index.php(17): require('...') #34 {main} thrown in /bitnami/wordpress/wp-content/plugins/wp-stateless/lib/Google/vendor/google/cloud-core/src/RequestWrapper.php on line 397
エラーはどうやらGCSの認証まわりのようです。認証設定を変えようにもプラグインを有効にした瞬間にアクセス不可になるため、詰みでした。
構築しなおす
似たようなエラーを探しましたが、似た例があまりなかったため、一から構築しなおすことにしました。
バックアップ
まずは現状をできるだけバックアップします。一括でバックアップできるAll-in-One WP Migration
を使いましたが、すべてをバックアップしたファイルを移行先でインポートすると、完了せずに進捗が100%のまま止まりました。
エクスポート時に、テーマのみ出力すると移行先でインポートできました。
次は記事のエクスポートです。標準の機能を使いました。
ツール > エクスポートからすべてのコンテンツ
を選び、ダウンロードしました。
GCEのインスタンス立ち上げ
立ち上げの際には、こちらのサイトを参考にいたしました。
作成するときは、既存のインスタンスを停止して、ネットワークインターフェースの静的外部IPv4アドレスを外しておきます。また、無料枠になるようにリージョンと容量に気をつけます。
そして、新たに作成したインスタンスに静的外部IPv4を割り当てます。ネットワーク設定をそのまま移すことで、以前設定したCloudFlareなどの設定をそのまま使いました。
WP-Statelessを再インストール
新たにインスタンスが立ち上がったら、まっさらな状態でWP-Statelessプラグインをインストールして動作することを確認しました。(怯えながら有効化しました)
次に、先程バックアップした記事データやテーマデータをインポートします。私はインスタンス立ち上げから2ヶ月ほどしてからWP-Statelessを使ってGCSにメディアをリンクしたため、一部の画像がうまく移行できていませんでした。そのため、リンク切れした画像はスナップショットから復元してWP-Statelessを無効化したサイトからコピペして再度アップロードしました(大変でした)
記事とテーマが移行できたのを確認したら、WP-Statelessを設定しました。
ModeはStateless
、File URL ReplacementはEnable Editor & Meta
にしました。Supported File Typesにwebp
を追加しました。
BucketにはGCSで作成したバケット名を入力しました。Domainに関しては、CloudflareでSSL認証をしているため、https://バケット名
を設定します。このhttps://に気づかずに結構ハマりました。
WP-Statelessのセットアップが完了したら、他のプラグインも同様にインストールして設定を済ませました。半日以上かかって大変でした。
マシンイメージのバックアップ
スナップショットはディスクをバックアップしますが、マシンイメージは環境ごとバックアップできるようです。
マシンイメージは、仮想マシン(VM)インスタンスの複数のディスクからのすべての構成、メタデータ、権限、データを保存する Compute Engine リソースです。マシンイメージは、多くのシステム メンテナンス、バックアップと復元、インスタンスのクローン作成のシナリオで使用できます。
https://cloud.google.com/compute/docs/machine-images?hl=ja#whats_next
マシンイメージのバックアップ手順としては、Compute Engine > マシンイメージ > マシンイメージを作成から実行できました。
料金はus-westリージョンの場合、1GBあたり$0.05 (per GB / month)だそうです。試しに30GBのディスクを持ったインスタンスをバックアップしましたが、月200円くらいだと思います。
おわりに
スナップショットが機能するかと思いきや、うまく復元できなかったのはショックでしたが、一から構築したことでセットアップのやり方がしっかりと身につきました。
エラーは二度と起こらないでほしいですが、もし再度エラーが発生したら整合性ありのチェックを入れたスナップショットで復元を試したいと思います。スナップショットはスケジューリング機能があり、月5GBまで無料なので積極的にバックアップしていきたいですね。参考になれば幸いです。
Be First to Comment