SiiD BLOG ロゴ

LaravelとCloudflare R2の応用|サーバー複数台・動画アップロード・費用【Fly.io】

LaravelとCloudflare R2の応用|サーバー複数台・動画アップロード・費用【Fly.io】

この記事を書いた人

セイト@エンジニア兼講師

セイト@エンジニア兼講師

2012年に大学を卒業後、株式会社LIGにてWebデザイナー・Webエンジニアを3年務めたあと、株式会社LIG Philippinesの代表・VPoEとして6年間の在籍中に社員数約100名程度のテックチームへ成長させる。 その後2021年に独立し、合同会社BugFixを設立。登録者13万人を超えるテック系YouTubeチャンネルの運営やキャリアに特化したAIプログラミングスクールSiiDを運営中。

こんにちは!SiiD代表エンジニアのセイトです。

この記事は、LaravelのアプリをFly.ioで公開し、画像の保存先をCloudflare R2にした後の応用編です。
サーバーを複数台にする手順と、動画をアップロードするときの注意点、R2の費用とバケットの削除方法をまとめました。
画面はLivewireで作っていて、config/filesystems.phpにr2という名前でR2の設定がある前提で説明します。
公開の途中でつまずいている場合は、先にLaravelをFly.ioで公開するときのよくあるエラーと対処法11選を見てください。

サーバーを複数台にするメリットとデメリット

サーバーが1台だと障害でアプリが止まり、2台なら残りの1台で動き続けることを比べた図

サーバーを複数台にするメリットは、アプリを安定して動かしやすくなることです。
サーバーが1台だけだと、その1台に障害が起きたときにアプリが止まります。
2台以上あれば、残りのサーバーで動かし続けられます。

デメリットは、料金が台数分かかることです。
Fly.ioの場合、シンガポールでメモリ1GBのサーバーを動かし続けると、1台あたり月8.50ドルかかります(2026年11月時点)。
さらに、この記事で説明する設定も必要になります。

ポートフォリオなら1台で十分です。
お客さんが使うサービスなら、2台以上にすることを検討してください。

今の台数は、次のコマンドで確認できます。

fly status

サーバーの行が2行あれば2台です。
Fly.ioは、--ha=falseを付けずに初回のfly deployをすると、サーバーを2台作ります。
1台でよい場合は、次のコマンドで減らしてください。

fly scale count 1

サーバーを複数台にすると画像の投稿に失敗する理由

画像を選ぶアクセスが1台目、投稿のアクセスが2台目に届き、2台目に一時ファイルがなく投稿に失敗する流れの図

サーバーを2台以上にすると、画像の投稿が500エラーで失敗することがあります。
ログには次のようなエラーが出ます。

League\Flysystem\UnableToRetrieveMetadata

原因は、Livewireの一時ファイルです。
Livewireは、画像を選んだ時点で、その画像を投稿前の一時ファイルとしてサーバーに保存します。
投稿ボタンを押すと、その一時ファイルを読み込んで、本来の保存先に保存します。

サーバーが2台あると、届いたアクセスはどちらかに振り分けられます。
そのため、画像を選んだときのアクセスは1台目に、投稿ボタンを押したときのアクセスは2台目に届くことがあります。
ディスクは1台ごとに別なので、2台目には一時ファイルがありません。

そこで、一時ファイルもサーバーの外のR2に置きます。
R2なら、どのサーバーからも同じファイルが見えます。

Livewireの一時ファイルの置き場所をR2にする

一時ファイルをR2に置くと、画像はブラウザからR2へ直接送られ、どのサーバーからも見えることを示す図

まず、Livewireの設定ファイルを作ります。
Sailを使っている場合は、phpの前に./vendor/bin/sailを付けてください。

php artisan livewire:publish --config

config/livewire.phpができるので、'temporary_file_upload'の中の'disk'を、値を'r2'に変えます。

    'temporary_file_upload' => [
        'disk' => 'r2',

こうすると、画像を選んだときの送り先が変わります。
これまでは、ブラウザがアプリのサーバーに画像を送っていました。
設定後は、サーバーは「R2に送ってよい」という許可付きのURLを発行するだけで、画像はブラウザからR2へ直接送られます。

ここで一度デプロイします。
利用者がいるアプリでは、次の節のとおり画像が保存されない状態になるので、先にCORSの節を設定してからデプロイしてください。

fly deploy

Livewireの一時ファイルをR2に変えただけでは画像が保存されない

デプロイしたら、画像つきで投稿してみます。
画像が任意の項目になっているフォームでは、完了の表示が出るのに、投稿した記事に画像がありません。

Chromeなら、ページの上で右クリックして「検証」を選び、「Console」タブを開きます。
もう一度画像を選ぶと、次のような赤いエラーが出ます。

Access to XMLHttpRequest at 'https://<バケット名>.<アカウントID>.r2.cloudflarestorage.com/livewire-tmp/…'
from origin 'https://<アプリ名>.fly.dev' has been blocked by CORS policy: …

これはCORSエラーです。
ブラウザがR2への画像の送信を止めたので、画像はR2に届いていません。
記事は画像なしで保存されます。

ブラウザからCloudflare R2への送信をCORSで許可する

CORS(Cross-Origin Resource Sharing)は、別のオリジンへの通信を、送り先のサーバーが許可するための仕組みです。
オリジンとは、URLのプロトコル・ホスト・ポートの組のことで、どれか1つでも違えば別のオリジンになります。

ブラウザは、ページのJavaScriptから別のオリジンへ送る通信を、セキュリティのために制限しています。
制限がないと、悪意のあるサイトを開いたときに、そのページのJavaScriptがログイン中の別のサービスのデータを読み取れてしまうからです。

これまで画像の送り先は、ページと同じhttps://<アプリ名>.fly.devでした。
設定を変えた後の送り先はhttps://<バケット名>.<アカウントID>.r2.cloudflarestorage.comで、別のオリジンです。
このような送信では、ブラウザは画像を送る前に「このオリジンのページからPUTで送ってよいか」をR2に確認します。この確認をプリフライトと呼びます。
R2が許可を返さなければ、ブラウザは画像を送らず、先ほどのエラーを出します。
そこで、R2のバケットに許可の設定を追加します。

R2のバケットの「Settings」タブを開いて、「CORS Policy」の「Add」を押します。
入力欄を次の内容に置き換えて、保存してください。

[
  {
    "AllowedOrigins": ["https://<アプリ名>.fly.dev", "http://localhost"],
    "AllowedMethods": ["GET", "PUT"],
    "AllowedHeaders": ["*"],
    "MaxAgeSeconds": 3600
  }
]

項目

意味

AllowedOrigins

送信を許可するページのURL

AllowedMethods

許可する操作。画像を送るのがPUT、読み出すのがGET

AllowedHeaders

送信に付けるヘッダー。*はどれでも許可するという意味

MaxAgeSeconds

ブラウザが確認の結果を覚えておく秒数。3600は1時間

AllowedOriginsには、本番のURLと、ローカルで開いているURLを書きます。
ローカルでも一時ファイルの置き場所がR2になるからです。
Sailならhttp://localhostです。
ポート番号が違うと別のオリジンになるので、php artisan serveならhttp://localhost:8000のようにポート番号まで書きます。

保存したら、ページを再読み込みして、もう一度画像つきで投稿してください。
エラーが出ず、投稿した記事に画像が表示されれば設定できています。

R2に残るLivewireの一時ファイルを自動で消す

一時ファイルは、投稿した後もバケットのlivewire-tmpというフォルダに残ります。
サーバーに置いていたときはLivewireが古いものを消していましたが、R2に置くと自動では消えません。
放っておくと、投稿しなかった画像も含めてたまり続け、無料で使える容量を使っていきます。

そこで、R2の「Object Lifecycle Rules」で、livewire-tmp/で始まるファイルだけを1日後に削除します。
投稿した画像はstore()で指定したposts/などのフォルダに保存されているので、消えません。
1日にするのは、Livewireの公式ドキュメントが、24時間より古い一時ファイルを消すよう案内しているからです。

バケットの「Settings」タブにある「Object Lifecycle Rules」の「Add」を押して、次のように入力します。

  • Rule name:livewire-tmp
  • Apply to objects with the following prefix:livewire-tmp/
  • 「Delete uploaded objects after」にチェックを入れて、1 Day

「Save changes」を押して、一覧にlivewire-tmpのルールが「Enabled」で表示されれば完了です。

Fly.ioのサーバーの台数を増やして確認する

準備ができたら、台数を増やします。
セッションがCookie、データベースがNeonのように、ほかのデータもサーバーの外にある前提です。
2台にする場合は次のとおりです。

fly scale count 2

fly statusでサーバーが2行になっていることを確認し、画像つきで投稿と編集をしてみてください。
どちらも成功して画像が表示されれば完成です。

Laravelで動画もR2にアップロードするときの注意点

動画も、画像と同じようにstore()でR2に保存できます。
ただし、画像とは違う注意点が3つあります。

1つ目は、入力チェックと表示です。
画像用にimageやmax:2048のようなルールを書いている場合は、動画に合わせて変えます。
表示には、<img>ではなく<video>タグを使います。

Livewireの一時ファイルをサーバーに置く設定では、初期設定で12MBまでです。
超える動画を扱うなら、config/livewire.phpの'temporary_file_upload'で上限を変えます。
maxの単位はKBなので、次の例は100MBです。
送信に時間がかかる場合は、制限時間のmax_upload_time(単位は分)も合わせて延ばします。

    'temporary_file_upload' => [
        'rules' => ['required', 'file', 'max:102400'],
        'max_upload_time' => 30,

2つ目は、容量です。
動画は画像よりサイズがずっと大きいので、無料で使える10GBもすぐに埋まります。
大きい動画を扱うなら、この記事の「Livewireの一時ファイルの置き場所をR2にする」以降の設定が向いています。
アップロードの通信がアプリのサーバーを通らず、ブラウザからR2へ直接送られるからです。

3つ目は、配信です。
r2.devのURLは本番向けではなく、転送速度が制限されることもあります。
動画を公開するサービスなら、自分のドメインを設定してください。
また、R2はファイルを置くだけなので、回線の速さに合わせて画質を変えるような再生はできません。
動画が中心のサービスを作るなら、Cloudflare Streamのような動画専用のサービスを検討してください。

Cloudflare R2の費用とバケットの削除方法

R2は、保存できる容量が毎月10GBまで、ファイルを書き込む操作が毎月100万回まで、読み出す操作が毎月1,000万回まで無料です。
画像を表示するときのデータの転送量には、料金がかかりません。
超えた分は、例えば保存なら1GBあたり月0.015ドルかかります(2026年11月時点)。
今どれくらい使っているかは、ダッシュボードのR2のトップで確認できます。

使わなくなったときは、バケットの「Settings」タブの一番下にある「Danger Zone」で、「Empty Bucket」の「Empty」を押して中身を空にしてから、「Delete bucket」の「Delete」で削除できます。

AIプログラミングスクール「SiiD」について

AIプログラミングスクール「SiiD」は、未経験からITエンジニア転職を目指す方向けのオンラインスクールです。

SiiDの特徴

  • 現役エンジニアでYouTube登録者約13万人の「セイト先生」が代表兼主任講師
  • 採用側の実務知見(2,000人以上の選考・150名以上のエンジニア採用)にもとづく指導
  • 生成AIを取り入れた学習設計と、実務レベルのフルスタックWeb開発スキル
  • Workship CAREER(株式会社GIG)と連携した無料の転職伴走支援
  • 経済産業省認定のReスキル講座で、給付金の条件を満たせば実質105,600円〜
  • 学割あり(35%オフ)

こんな方におすすめ

  • 未経験・文系・社会人からITエンジニア転職を本気で目指したい方
  • 独学に限界を感じている方
  • 費用を抑えながら実務スキルと転職サポートを両立したい方

「未経験だから」とあきらめる必要はありません。採用する側を知り尽くしたプロが、給付金で負担を抑えながら内定まで伴走します。

シェアする

未経験からのエンジニア転職を本気で目指すなら「SiiD」

SiiDはYouTube 13万人のセイト先生が主任講師のAIプログラミングスクール。元人事部長&現役エンジニアによる徹底指導で、生涯年収を大きくアップさせませんか?

SiiDの詳細を見る