― ブラウザ直PUTから本番運用まで、つまずかない完全ガイド ―
Web写真集プラットフォーム「PicZine」 では、画像やページデータの保存先として Cloudflare R2 を採用しています。
この記事では、
- Cloudflare R2 とは何か
- 「ブラウザから直接 PUT する」とはどういう意味か
- なぜ CORS 設定が必要なのか
- 開発環境から本番環境へどう切り替えるのか
といった 初心者が一番つまずきやすいポイントを丁寧に補足しながら、
実際のセットアップ手順を解説します。
「S3互換って聞くけど、結局どう使うの?」
という人を想定しています。
Cloudflare R2 とは?
Cloudflare R2 は、Cloudflare が提供する オブジェクトストレージ です。
Amazon S3 と互換性のある API を持ちながら、次の特徴があります。
- データ転送料が無料
- Cloudflare CDN と直結
- カスタムドメインでそのまま配信可能
- S3 SDK がそのまま使える
特に画像・動画を扱う Web アプリでは
「保存コストよりも転送料が重くなる」ケースが多いため、
R2 はかなり現実的な選択肢になります。
今回の構成の全体像
まずは完成形のイメージです。
[ブラウザ]
↓ PUT(直接アップロード)
[Cloudflare R2]
↓ CDN 経由
[images.xxxxxx.com]
ポイントは アプリサーバーを経由しない ことです。
「ブラウザから直接 PUT する」とは?
この記事で何度も出てくる重要な言葉なので、
まずここをしっかり説明します。
よくあるアップロード構成(サーバー経由)
一般的な Web アプリでは、次のような流れが多いです。
[ブラウザ]
↓ POST
[アプリサーバー]
↓ PUT
[ストレージ]
この場合、
- サーバーが画像データを一度受け取る
- サーバーの帯域・CPU・転送料を消費する
- 同時アップロードが増えるとサーバーが重くなる
という特徴があります。
PicZine で採用している構成(ブラウザ直PUT)
今回採用しているのは、次の構成です。
[ブラウザ]
↓ PUT
[Cloudflare R2]
つまり、
- ブラウザが直接 R2 にファイルをアップロード
- アプリサーバーは画像データを扱わない
- サーバーは「メタ情報保存」など最低限の役割のみ
これを 「ブラウザから直接 PUT する」 と呼んでいます。
PUT とは何か?
HTTP にはいくつかのメソッドがあります。
GET:取得するPOST:処理を依頼するPUT:指定した場所にデータをそのまま置く
R2(S3互換ストレージ)では、
PUT /bucket/path/image.jpg
のように
「このパスに、このファイルを保存する」
という使い方が基本になります。
なぜブラウザ直PUTにするのか?
理由はかなりシンプルです。
① サーバー負荷がほぼゼロ
- 画像をサーバーで処理しない
- API は軽い JSON 通信だけ
→ スケールしやすく、構成もシンプル。
② コストが安定する
- R2 は 転送料が無料
- Cloudflare CDN から直接配信
画像が増えても
想定外の請求が起きにくいです。
③ フロントエンドだけで完結する
- React / Vue / Svelte から直接アップロード可能
fetchや SDK で実装できる
PicZine のような
クライアント主導のアプリと相性が良い構成です。
でも、誰でも勝手にアップロードできない?
ここで重要になるのが CORS と API トークン です。
なぜ CORS 設定が必要なのか?
ブラウザにはセキュリティ制限があります。
「この Web サイトが
他のドメインに勝手にデータを送っていいの?」
これを制御する仕組みが
CORS(Cross-Origin Resource Sharing) です。
CORS を設定しないとどうなる?
たとえ正しい API キーを使っていても、
- ブラウザ → R2 への PUT
- ブラウザ側で通信がブロック
されます。
そのため、
ブラウザ直PUTを行う場合は CORS 設定が必須です。
開発環境のセットアップ(Development)
ここから実際の手順です。
Step 1. R2 バケットを作成
- Cloudflare ダッシュボードにログイン
- R2 → Create bucket
- バケット名を入力
例:xxxxxx-pages
Step 2. API トークンを作成
R2 に書き込みを行うための認証情報を作ります。
設定内容:
- Permissions:
Admin Read & Write - TTL:Forever(または任意)
取得した値を .env に設定します。
VITE_R2_ACCESS_KEY_ID=xxxx
VITE_R2_SECRET_ACCESS_KEY=xxxx
VITE_R2_ENDPOINT=https://xxxx.r2.cloudflarestorage.com
※ 開発中は権限を絞らない方が詰まりにくいです
Step 3. CORS を設定する
方法A:スクリプト(推奨)
node scripts/apply-cors.js
方法B:手動設定
Settings → CORS Policy に以下を追加。
[
{
"AllowedOrigins": [
"http://localhost:5173",
"https://*.pages.dev",
"*"
],
"AllowedMethods": ["GET", "PUT", "POST", "DELETE", "HEAD"],
"AllowedHeaders": ["*"],
"ExposeHeaders": ["ETag"],
"MaxAgeSeconds": 3000
}
]
Step 4. Public Development URL を有効化
画像表示用の公開 URL を有効にします。
- バケットの Settings
- Public Development URL → Enable
- 表示された URL を
.envに設定
VITE_R2_PUBLIC_BASE_URL=https://pub-xxxx.r2.dev
本番環境への切り替え(Production)
Step 1. カスタムドメインを接続
例:images.xxxxx.com
- Settings → Public Access → Custom Domains
- Cloudflare 管理ドメインなら DNS はほぼ自動
Step 2. 環境変数を更新
VITE_R2_PUBLIC_BASE_URL=https://images.xxxxxx.com
VITE_STORAGE_PROVIDER=r2
API エンドポイントと公開 URL の違い(重要)
| 種類 | 用途 |
|---|---|
r2.cloudflarestorage.com | API 用(非公開) |
xxxx.r2.dev | 開発用公開 URL |
images.xxxxxx.com | 本番用公開 URL |
画像表示には必ず公開URLを使います。
よくあるトラブル
画像が表示されない
→ VITE_R2_PUBLIC_BASE_URL が API エンドポイントになっていないか確認
CORS エラー
→ ブラウザの Console を確認し、CORS 設定を再確認
AccessDenied
→ API トークンの権限不足(Admin Read & Write で再作成)
まとめ
- ブラウザ直PUT はサーバーを軽くするための設計
- CORS はブラウザの安全装置
- R2 は画像配信と非常に相性がいい
- 開発は
r2.dev、本番はカスタムドメインが基本
この構成を理解しておくと、
画像・動画系の Web アプリ設計が一段楽になります。

コメント