WP-StatelessでCloudStorageからCloudflare R2に移行して費用を大幅カットする方法とURLバグ解決策

この記事は約 12 分で読めます

WP-StatelessでCloudStorageからCloudflare R2に移行して費用を大幅カットする方法とURLバグ解決策 image 6

Google Cloud StorageからCloudflare R2へ移行する理由

本ブログはGoogle Cloud StorageとWP-Statelessを組み合わせて画像をアップロード&表示しています。設定当初は費用がそうでもなかったのですが、最近は転送量コスト(エグレス料金)が毎月500円ほどかかるようになりました。

費用を削減するために、Cloud StorageからCloudflare R2に乗り換えました。R2はデータ転送量が無料です。保存料金も安く、WordPressのメディア保存先を置き換えるだけで毎月のコストを削減できるようなので試してみます。

実際に9月20日にCloudStorageからCloudFlare R2に移行したあとの費用グラフです。

CloudStorageからCloudFlare R2に移行したあとの費用グラフ
年間で6,000円ほど安くなりました

移行した日(9/20)は通信量が増えたため、費用が増加していますが、それ以降はCloudStorageの費用(青い部分)がゼロになっていることがわかります。R2ではClass Bの読み込みが無料枠に収まっているため、費用がかかっていません。

Cloudflare R2の料金体系

2026年9月現在の料金体系は以下の通り。

項目Class A
(書き込み・変更)
Class B
(読み込み)
役割データを追加・変更・削除・一覧取得データを読み取り
主な操作(S3 API)PUT, POST, COPY, ListObjects などGET, HEAD など
無料枠(月間)100万回 / 月1,000万回 / 月
超過後の料金$4.50 / 100万回$0.36 / 100万回

Cloudflareのキャッシュを有効にしておけば、キャッシュで読み込まれるのでR2までリクエストが届かず、1000万回の無料枠を使い切らずに利用できます。Class Aの一覧取得リクエストのみ、同期系のプラグインを使っていると超える可能性があるため注意です。通常利用で課金されることはなさそうです。

Cloudflare R2のバケット作成とAPIトークンの発行手順

まずは保存先となるCloudflare R2のバケットを用意します。

CloudflareのダッシュボードからR2を選択し、バケットを作成を選択します。

R2のバケット作成

任意のバケット名を設定し、位置情報は自動、デフォルトのストレージクラスはStandardに設定します。

R2のバケット作成

バケットの作成が完了したら、WordPressからR2へ接続するための認証情報を準備します。Cloudflare管理画面で専用のAPIトークンを発行し、アクセスキーなどを取得する手順を解説します。

まず、CloudflareダッシュボードのR2概要ページを開き、画面下部のAPIトークン管理をクリックします。

R2の概要ページ

続いてAPIトークンを作成を選択します。

トークン名:WordPress接続用など分かりやすい名称を入力します
権限:オブジェクトの読み取りと書き込みを選択
対象バケット:特定バケットのみ許可するか全バケットを対象にするかを選択
TTL(有効期限):WordPressとの接続を切断させないため、無制限に設定

R2のAPIトークン作成

設定完了後、APIトークンを作成をクリックすると認証情報が表示されます。

画面に表示される以下の情報をメモに控えてください。

アクセスキーID:S3互換APIで接続するためのIDです
シークレットアクセスキー:認証に必要なパスワード情報です。この画面を閉じると再表示されません
エンドポイントURL:S3 APIリクエストの送信先となるURLです

Google Cloud StorageからCloudflare R2へ既存画像を同期する

続いて現状の画像データをGoogle Cloud StorageからCloudflare R2へコピーします。

Google Cloud StorageでHMACキーを発行する

データ移行を実行するにはGoogle Cloud Storage側でS3互換の認証情報であるHMACキーを発行します。この鍵を使うことでCloudflare R2がGoogle Cloud Storage内の画像データを読み取れるようになります。

Google Cloudコンソールを開き、Cloud Storageの設定画面に移動します。インターオペラビリティタブを選択し、サービスアカウントのHMACキーを作成をクリックします。

画面に表示されるアクセスキーとシークレットを作成して手元に控えます。

Cloudflare R2でデータ移行を開始する

CloudflareのR2管理画面を開き、上部のファイルを移行するを選択します。

R2のデータ移行

Google Cloud Storageを選択します。

ソースバケット名:Google Cloud Storageで使っていたバケット名を入力します
アクセスキーID:先ほど発行したHMACアクセスキーを入力します
シークレットアクセスキー:先ほど発行したHMACシークレットキーを入力します
ターゲットバケット:作成しておいたCloudflare R2のバケットを選択します

入力完了後、移行を開始をクリックすると自動的にデータの転送が始まります。しばらく待ちます。私のブログのメディア数は12000個程度でしたが、3~5分程度で終わりました。

転送完了とフォルダ階層の確認

転送完了の表示が出たら、Cloudflare R2のバケット内を開いてファイル一覧を確認します。私は年、月でフォルダをわけていたので、そのとおりに移行されていることを確認しました。

年月の構造になっていることを確認

具体的には、2026/09/ファイル名のような元の階層が保持されていることを確認しました。

WP-Statelessの無効化とメディアオフロードプラグインの導入

データのコピーが終わったら、WordPress側の配信設定を切り替えます。

WP-Statelessを無効化し、Cloudflare R2に対応したプラグインAdvanced Media Offloaderをインストールして有効化します。

Advanced Media Offloaderプラグインの画面
このプラグインです

プラグインの設定画面を開き、先ほど発行したCloudflare R2のアクセスキーID、シークレットアクセスキー、バケット名、エンドポイントURL、配信用のカスタムドメインを設定します。

Advanced Media Offloaderの設定画面

その下にあるFile Handlingでは以下のように設定します。Retention PolicyをSmart Local Cleanupにしておくと不要なファイルを削減されるため、容量を多少節約できます。

Advanced Media Offloaderの設定画面

サーバー上に画像がない場合のメタデータ強制設定

WP-Statelessなどでサーバーローカルから画像を完全に削除して運用していた場合、移行先プラグインがローカルファイルを認識できず、オフロード未完了と判断してしまうことがあります。

この場合、WP-CLIコマンド等を使用してデータベース内のメタデータへ直接移行済みフラグ(advmo_offloaded)を設定します。wpコマンドが入っていない場合はインストールをお願いします。

wp post meta set 2713 advmo_offloaded 1 --allow-root

私の場合は上記に加えて、プラグインによって生成されるURLから年月フォルダ(Y/m/)が抜け落ち、ルート直下に書き換わってしまうトラブルが発生しました。

例:https://media.kuimal.com/2026/09/image-hogehoge.pngが正ですが、URLがhttps://media.kuimal.com/image-hogehoge.pngとなり、表示できていなかったです。

自作プラグインによる年月のURL補正

WordPressのフィルターフックを使用した自作プラグインを作成してURLを補正しました。

WordPressのルートディレクトリ配下にある wp-content ディレクトリ内に mu-plugins ディレクトリを作成し、その中に補正プログラムを配置します。

まずはディレクトリの作成と移動を行います。

cd /var/www/html/wp-content
mkdir -p mu-plugins
cd mu-plugins

次にVimで補正用のPHPファイルを作成して開きます。

vim fix-r2-url.php

Vimが起動したらキーボードの i キーを押して挿入モードへ切り替え、以下のプログラムを貼り付けます。

<?php
/*
  Plugin Name: Fix R2 Media Offloader URL
*/
add_filter('wp_get_attachment_url', function($url, $post_id) {
    $file = get_post_meta($post_id, '_wp_attached_file', true);
    if ($file && strpos($url, 'media.kuimal.com') !== false) {
        return 'https://media.kuimal.com/' . ltrim($file, '/');
    }
    return $url;
}, 999, 2);

貼り付けが完了したら Esc キーを押してコマンドモードに戻り、:wq と入力してEnterキーを押すことで保存して終了します。

このプラグインで、データベースに記録された本来のファイルパス(_wp_attached_file)を参照し、正しく年月が入ったURLで画像を出力できるようになります。この機能は、既存の移行した画像ファイルのURLに対して有効であり、新規にアップロードしたファイルについては、自動的に正しいURLが入ります。

また、この自作プラグインを削除すると再びURLがルート直下に戻って画像が表示されなくなるため、そのままサーバー内に残して運用します。

著:Mana
¥1,980 (2026/09/21 16:52時点 | Amazon調べ)

WordPress内部のキャッシュを消去する

データベースの置換や補正プラグインの設置が完了したら、古いURLの参照がWordPress内に残らないようキャッシュをクリアします。

以下のコマンドを実行してオブジェクトキャッシュを全破棄します。

wp cache flush --allow-root

動作確認とGoogle Cloud Storageの安全な削除

すべての設定が完了したら、動作確認を行います。

画像の確認
正常に表示されています

WordPressのメディアライブラリからテスト画像を新規アップロードし、正しいURLで表示されるか確認します。また、既存の記事を開き、デベロッパーツールのコンソール画面で画像の404エラーが発生していないかを確認します。サイトのファビコンやヘッダーなども合わせて確認してください。

問題なく画像が表示されることを確認し、使用していたGoogle Cloud Storageのバケットやサービスアカウントキーを削除します。これでGoogle Cloud Storageにかかっていた毎月の費用が削減されました。

まとめ

最近ではCloudflareが無料で便利なサービスを次々と展開しているのでありがたいです。一昔前はSSL証明書の自動更新をcronで実行してましたが、今ではCloudflareがすべて自動化してくれます。

費用を抑えて自分の趣味ブログをかけるのは本当に楽しいです。

category :