URLهای خام S3 رو با یه پروکسی تصویر لاراول تمیز کن
خلاصهٔ کاملتر
نویسنده میگه اگه فایلهای تصویر و رسانه رو مستقیم از یه object storage سازگار با S3 (مثل Hetzner، AWS S3 یا DigitalOcean Spaces) سرو کنی، URLهات هم زشتن، هم provider و اسم باکت رو لو میدن، و اگه باکت private باشه اصلاً مستقیم قابلسرو نیستن. تو این مقاله تعریف میکنه چطور همهٔ URLهای خام رسانه رو تو وبلاگ لاراولش با مسیرهای پروکسیشدهٔ تمیز عوض کرده، ضمن نگه داشتن کش ۲۴ ساعتهٔ CDN.
استک به گفتهٔ نویسنده لاراول + Octane پشت Traefik و Cloudflare ئه، با دو باکت: یه private برای رسانهٔ آپلودی و یه public برای تصاویر Open Graph تولیدشده. قبلاً اپ با Storage::url() مستقیم به object storage لینک میداد، که یعنی URLهای باکت private غیرقابلدسترس بودن و جزئیات provider تو HTML هر صفحه لو میرفت.
قدم اول یه کلاس helper بهاسم MediaUrlBusiness ئه که تولید URL برای هر دو disk رو متمرکز میکنه؛ بهجای صدا زدن Storage::url() تو تمپلیتهای blade، حالا متدهایی مثل MediaUrlBusiness::forOgImage($path) صدا زده میشن که یه مسیر نسبی تمیز مثل /storage/og-images/... برمیگردونن. قدم دوم کنترلر پروکسیه: ObjectProxyController همهٔ درخواستهای /storage/{disk}/{path} رو میگیره، disk رو اعتبارسنجی میکنه، کلید کامل S3 رو resolve میکنه و فایل رو استریم میکنه:
$stream = $disk->readStream($fullPath);
return response()->stream(
callback: function () use ($stream) {
fpassthru($stream);
fclose($stream);
},
headers: [
'Content-Type' => $disk->mimeType($fullPath),
'Content-Length' => $disk->fileSize($fullPath),
'Cache-Control' => 'public, max-age=86400, immutable',
]
);یه نکته که به گفتهٔ نویسنده گیرش انداخت این بود که Storage::download() و streamDownload() کل فایل رو تو حافظه buffer میکنن، که برای تصاویر بزرگ حافظه هدر میده؛ سوییچ به readStream() + response()->stream() فایل رو مستقیم از S3 به کلاینت میفرسته بدون buffer. برای route هم یه مسیر با ->where('path', '.*') گذاشته و middlewareِ کش رو طوری تغییر داده که پاسخهایی که خودشون هدر Cache-Control دارن رو دست نزنه.
نویسنده یه هشدار مهم هم میده: حالا هر چیزی تو باکت private از طریق پروکسی قابلدسترسه اگه کسی مسیرش رو حدس بزنه، پس باید مطمئن شی اون باکت فقط داراییهای عمومی نگه میداره. نتیجهٔ نهایی به گفتهٔ نویسنده URLهای تمیز و provider-agnostic ئه که اسم باکت رو لو نمیدن و اگه یه روز provider رو عوض کنی، فقط کافیه پیکربندی disk رو عوض کنی و URLهای عمومی ثابت میمونن.
نکات کلیدی:
- یه helper مثل MediaUrlBusiness تولید URL رو متمرکز و مسیرها رو نسبی و تمیز میکنه
- کنترلر پروکسی فایل رو با readStream مستقیم از S3 استریم میکنه، بدون buffer در حافظه
- هدر Cache-Control کش تهاجمی Cloudflare و مرورگر رو حفظ میکنه
- URLها provider-agnostic میشن و موقع تغییر provider ثابت میمونن؛ ولی حواست به دسترسی حدسی به باکت private باشه




