はじめに
「クラウドストレージの転送料金が高すぎる…」と悩んでいませんか?
AWS S3を使っていると、ダウンロード(エグレス)料金が予想以上に膨らむことがあります。
この記事では、エグレス料金が完全無料のCloudflare R2について、料金比較からPHPでの実装方法、セキュリティ対策まで解説します。

実際にR2を導入してみたので、その経験をもとにお伝えします👍
Cloudflare R2とは
Cloudflare R2は、Cloudflare社が提供するS3互換のオブジェクトストレージサービスです。2022年にリリースされ、エグレス(ダウンロード)料金が完全無料という画期的な料金体系が特徴です。
AWS S3と互換性があるため、既存のS3向けコードやツールをほぼそのまま使えます。
料金比較(2025年12月時点)
主要なオブジェクトストレージサービスと料金を比較します。
無料枠の比較
| サービス | 無料ストレージ | 無料エグレス |
|---|---|---|
| Cloudflare R2 | 10GB/月 | 無制限 |
| Backblaze B2 | 10GB | 保存量の3倍まで |
| Wasabi | なし | 保存量の1倍まで |
| AWS S3 | 5GB(12ヶ月のみ) | 100GB/月(12ヶ月のみ) |
有料プランの比較
| サービス | ストレージ料金 | エグレス料金 |
|---|---|---|
| Cloudflare R2 | $0.015/GB/月 | 無料 |
| Backblaze B2 | $0.006/GB/月 | $0.01/GB |
| Wasabi | $0.0069/GB/月 | 保存量の1倍まで無料 |
| AWS S3 | $0.023/GB/月 | $0.09/GB |
具体的なコスト試算
100GBのファイルを保存し、月に500GBダウンロードされる場合(画像CDNなど):
| サービス | 月額コスト |
|---|---|
| Cloudflare R2 | $1.50(ストレージのみ) |
| Backblaze B2 | $2.60($0.60 + $2.00) |
| AWS S3 | $47.30($2.30 + $45.00) |
ダウンロードが多いケースでは、R2はS3と比較して約97%のコスト削減になります。

顧客に写真を配布するような用途では、R2のコスパが圧倒的です💰
R2のセットアップ手順
1. Cloudflareアカウント作成
Cloudflareの公式サイトでアカウントを作成します。無料で登録できます。
2. R2サブスクリプションの有効化
ダッシュボードの左メニューから「R2 Object Storage」→「Overview」を選択し、サブスクリプションを有効化します。クレジットカードの登録が必要ですが、無料枠内なら課金されません。
3. バケットの作成
「Create bucket」をクリックし、バケット名を入力します。Locationは「Automatic(Asia Pacific)」のままでOKです。
4. APIトークンの発行
R2 Overview画面から「Manage R2 API Tokens」→「Create API token」でトークンを作成します。権限は「Object Read & Write」を選択してください。
作成完了後に表示されるAccess Key IDとSecret Access Keyは、この画面でしか確認できません。必ずコピーして安全な場所に保存してください。
PHPでのアップロード実装
AWS SDK for PHPの準備
R2はS3互換なので、AWS SDK for PHPを使用します。Composerが使える環境なら以下のコマンドでインストールできます。
composer require aws/aws-sdk-php
Composerが使えない場合は、AWSの公式サイトからZIPファイルをダウンロードして設置します。ただし、PHP 8.1以上が必要です。PHP 8.0以下の場合は旧バージョン(3.269.0)を使用してください。
アップロードコード
<?php
require '/path/to/aws-autoloader.php';
use Aws\S3\S3Client;
use Aws\Credentials\Credentials;
$account_id = 'あなたのAccount ID';
$access_key = 'あなたのAccess Key ID';
$secret_key = 'あなたのSecret Access Key';
$bucket_name = 'バケット名';
$s3 = new S3Client([
'region' => 'auto',
'endpoint' => "https://{$account_id}.r2.cloudflarestorage.com",
'version' => 'latest',
'credentials' => new Credentials($access_key, $secret_key),
'use_path_style_endpoint' => true // R2では必須
]);
// アップロード
$s3->putObject([
'Bucket' => $bucket_name,
'Key' => 'photos/sample.jpg', // 保存先パス(自由に設定可能)
'Body' => fopen('/path/to/local/file.jpg', 'rb'),
'ContentType' => 'image/jpeg'
]);
use_path_style_endpoint => trueの設定が重要です。これがないと403エラーになります。

Keyのパスは完全に自由です。「photos/2024/12/sample.jpg」のように階層を作ることもできます📁
ファイルの公開方法
方法1:Public URLを有効化
バケットの「Settings」→「Public Access」→「R2.dev subdomain」を有効にすると、以下の形式でアクセスできるようになります。
https://pub-xxxxxxxx.r2.dev/photos/sample.jpg
方法2:署名付きURL(期限付き)
一時的なアクセスURLを発行する方法です。期限が切れるとアクセスできなくなります。
$cmd = $s3->getCommand('GetObject', [
'Bucket' => $bucket_name,
'Key' => 'photos/sample.jpg'
]);
$request = $s3->createPresignedRequest($cmd, '+1 hour');
$url = (string) $request->getUri();
セキュリティを考慮したファイル名
顧客に写真を共有する場合、ファイル名をランダムな文字列にすることでURLの推測を困難にできます。
function generateRandomFilename($extension) {
return bin2hex(random_bytes(16)) . '.' . $extension;
}
// 例: a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6.jpg
ランサムウェア対策(Bucket Locks)
R2にはBucket Locks機能があり、WORM(Write Once Read Many)モデルでデータを保護できます。
Bucket Locksとは
指定期間中、オブジェクトの削除・上書きを禁止する機能です。攻撃者がAPIキーを入手しても、データを暗号化・削除できません。
設定方法
バケットの「Settings」→「Bucket lock rules」→「Add rule」から設定できます。
| 設定項目 | 説明 |
|---|---|
| Rule name | ルールの名前(例:backup-90days) |
| Prefix | 対象フォルダ(空欄で全体) |
| Retention period | 保護期間(日数/日付/無期限) |

バックアップ用バケットにはBucket Locksを設定しておくと安心です🔒
注意点
PHP 8.1以上が必要
最新のAWS SDK for PHPはPHP 8.1以上が必要です。PHP 8.0以下の環境では、旧バージョン(3.269.0)を使用してください。
ACLヘッダーは非対応
R2はS3の「x-amz-acl」ヘッダーに対応していません。putObjectで「ACL」パラメータを指定するとエラーになります。
APIキーの管理
Secret Access Keyは作成時に一度しか表示されません。紛失した場合は新しいトークンを発行する必要があります。
まとめ
| 項目 | 内容 |
|---|---|
| 最大のメリット | エグレス料金が完全無料 |
| 無料枠 | 10GB/月のストレージ |
| 互換性 | AWS S3 API互換 |
| セキュリティ | Bucket Locks(WORM)対応 |
| おすすめ用途 | 画像配信、顧客へのファイル共有 |
ダウンロードが多い用途では、R2のコストメリットは絶大です。S3からの移行も、SDK設定を少し変えるだけで完了します。
まずは無料枠で試してみてはいかがでしょうか。

導入は意外と簡単でした。エグレス無料は本当にありがたいです🚀


コメント