Pada lingkungan production, kasus file Laravel yang berhasil di-upload tetapi saat dibuka justru menghasilkan 403 Forbidden atau 404 Not Found adalah masalah yang sangat umum. Biasanya gejalanya terlihat seperti ini: file ada di server, path tampak benar, database menyimpan nama file, tetapi URL file tidak bisa diakses dari browser.
Dalam banyak kasus, penyebabnya bukan pada proses upload, melainkan pada cara Laravel mengekspos file dari storage ke web server. Akar masalah yang paling sering adalah symlink public/storage belum ada, permission folder salah, owner file tidak sesuai dengan user web server, konfigurasi disk public keliru, atau URL asset yang dipakai tidak tepat.
Artikel ini fokus pada pendekatan problem-oriented: apa yang harus dicek, kenapa itu penting, dan bagaimana memverifikasi hasilnya di server Linux dan browser.
Memahami alur akses file Laravel
Secara default, file yang di-upload ke disk public Laravel akan disimpan di:
storage/app/publicAgar file itu bisa diakses dari browser, Laravel mengandalkan symlink:
public/storage -> storage/app/publicDengan begitu, file seperti:
storage/app/public/uploads/avatar.jpgbisa diakses melalui URL:
https://domainanda.com/storage/uploads/avatar.jpgJika salah satu bagian dari alur ini bermasalah, browser bisa menerima 403 atau 404:
- 404 biasanya berarti path publik tidak ditemukan, symlink belum ada, atau URL salah.
- 403 biasanya berarti file atau folder ditemukan, tetapi web server tidak punya hak baca/traverse yang cukup.
Penyebab paling umum dan cara mengeceknya
1. Symlink storage:link belum dibuat atau rusak
Ini penyebab paling sering. Laravel tidak otomatis membuat symlink di semua deployment. Jika folder public/storage tidak ada atau bukan symlink yang benar, URL file akan gagal.
Cek di server Linux:
ls -l publicPastikan ada output mirip:
storage -> /path/to/project/storage/app/publicJika belum ada, jalankan:
php artisan storage:linkJika sudah ada tetapi menunjuk ke path yang salah, hapus lalu buat ulang:
rm -f public/storage
php artisan storage:linkKenapa ini penting? Karena browser hanya bisa mengakses file di document root web server, biasanya folder public. Folder storage/app/public sendiri tidak langsung diekspos ke web tanpa symlink.
Catatan: pada deployment berbasis symlink release directory atau shared storage, pastikan symlink tidak mengarah ke folder lama yang sudah tidak aktif.
2. Permission folder atau file salah
Jika symlink sudah benar tetapi browser mengembalikan 403, periksa permission direktori dan file. Web server membutuhkan izin untuk masuk ke setiap folder pada path file dan membaca file tersebut.
Cek permission:
ls -ld storage storage/app storage/app/public public public/storage
find storage/app/public -type d | head
find storage/app/public -type f | headUmumnya, permission yang aman dan cukup adalah:
- Folder:
755 - File:
644
Perbaiki dengan:
find storage -type d -exec chmod 755 {} \;
find storage -type f -exec chmod 644 {} \;
find public -type d -exec chmod 755 {} \;
find public -type f -exec chmod 644 {} \;Jika aplikasi perlu menulis ke folder tertentu, seperti storage dan bootstrap/cache, user web server juga harus memiliki izin tulis. Banyak orang langsung memberi 777, tetapi itu bukan praktik yang baik untuk production karena terlalu longgar dan berisiko keamanan.
Kenapa 403 bisa terjadi? Karena meskipun file ada, web server seperti Nginx atau Apache tidak bisa membaca file atau melewati direktori di atasnya jika bit execute/read pada folder tidak memadai.
3. Owner file tidak sesuai dengan user web server
Masalah lain yang sering muncul adalah file di-upload atau dipindahkan oleh user deploy, sedangkan web server berjalan sebagai user lain, misalnya www-data, nginx, atau apache. Akibatnya, aplikasi bisa tampak normal tetapi akses file gagal atau upload berikutnya bermasalah.
Cek owner dan group:
ls -l storage/app/public
ls -ld storage bootstrap/cache publicDi Ubuntu dengan Nginx/Apache, user web server sering adalah www-data. Di CentOS/AlmaLinux bisa nginx atau apache. Anda bisa cek proses web server:
ps aux | egrep '(nginx|apache|httpd|php-fpm)'Jika owner belum sesuai, perbaiki misalnya:
sudo chown -R www-data:www-data storage bootstrap/cache public/storageAtau, jika strategi deployment Anda memakai group bersama:
sudo chgrp -R www-data storage bootstrap/cache public/storage
sudo chmod -R g+rw storage bootstrap/cacheTrade-off: Mengubah owner seluruh project ke user web server memang memudahkan, tetapi tidak selalu ideal untuk alur deploy. Banyak tim memilih user deploy sebagai owner dan group web server untuk menyeimbangkan keamanan dan operasional.
4. Konfigurasi disk public di config/filesystems.php keliru
Jika Anda menyimpan file ke disk yang salah, URL yang dihasilkan juga bisa salah. Untuk akses browser biasa, disk public harus mengarah ke storage/app/public dan URL ke APP_URL/storage.
Periksa konfigurasi:
'public' => [
'driver' => 'local',
'root' => storage_path('app/public'),
'url' => env('APP_URL').'/storage',
'visibility' => 'public',
],Pastikan proses upload memang memakai disk ini, misalnya:
$path = $request->file('image')->store('uploads', 'public');Atau:
$path = Storage::disk('public')->putFile('uploads', $request->file('image'));Jika Anda tanpa sadar menyimpan ke disk default local, file akan masuk ke storage/app, bukan storage/app/public, sehingga URL /storage/... tidak akan cocok.
Setelah mengubah konfigurasi, jangan lupa bersihkan cache config:
php artisan config:clear
php artisan cache:clearJika aplikasi menggunakan cache produksi:
php artisan config:cache5. URL asset tidak tepat
Banyak kasus sebenarnya sederhana: file tersimpan benar, symlink ada, tetapi URL yang dibangun salah. Misalnya database menyimpan path uploads/file.pdf, tetapi di view dipanggil sebagai:
{{ asset($file) }}Hasilnya menjadi:
https://domainanda.com/uploads/file.pdfPadahal file publik Laravel ada di bawah prefix /storage. Yang benar biasanya:
{{ asset('storage/' . $file) }}Atau jika menyimpan path hasil store(..., 'public') yang memang relatif terhadap disk public:
{{ Storage::url($file) }}Kenapa Storage::url() sering lebih aman? Karena URL dibangun berdasarkan konfigurasi disk, sehingga lebih konsisten daripada merangkai string manual.
Periksa juga nilai APP_URL di environment. Jika salah domain, salah skema HTTP/HTTPS, atau ada subfolder yang terlupa, URL file bisa tampak rusak walaupun file tersedia.
Checklist diagnosis cepat di server Linux
Berikut urutan cek yang praktis saat menerima laporan file storage Laravel error 403 atau 404:
- Pastikan file benar-benar ada
ls -l storage/app/public/uploads - Cek symlink publik
ls -l public/storage - Cek permission dan owner
namei -l public/storage/uploads/file.jpgPerintah
namei -lsangat berguna karena menampilkan permission tiap komponen path, bukan hanya file akhirnya. - Cek user web server
ps aux | egrep '(nginx|apache|httpd|php-fpm)' - Cek konfigurasi disk dan cache config
php artisan tinkerconfig('filesystems.disks.public') - Uji URL langsung dari server
curl -I https://domainanda.com/storage/uploads/file.jpg
Jika hasilnya 404, fokus ke symlink dan URL. Jika 403, fokus ke permission, owner, atau aturan web server.
Verifikasi dari sisi aplikasi dan browser
Verifikasi hasil upload
Jangan hanya mengandalkan bahwa upload “berhasil” karena tidak ada exception. Cek path yang benar-benar tersimpan:
$path = $request->file('image')->store('uploads', 'public');
logger()->info('Uploaded file path', ['path' => $path]);Nilai $path umumnya seperti:
uploads/abc123.jpgItu berarti file fisik seharusnya ada di:
storage/app/public/uploads/abc123.jpgDan URL publiknya seharusnya:
/storage/uploads/abc123.jpgVerifikasi di browser
Salin URL file dan buka langsung di browser, bukan lewat halaman aplikasi dulu. Lalu cek:
- Apakah statusnya 403 atau 404?
- Apakah URL mengarah ke domain yang benar?
- Apakah menggunakan HTTPS jika situs dipaksa HTTPS?
- Apakah file bisa diakses jika nama file sederhana tanpa spasi atau karakter khusus?
Di DevTools browser, tab Network akan membantu memastikan apakah masalah ada di URL, redirect, atau response dari server.
Kesalahan umum yang sering terlewat
- Menjalankan
storage:linkdi lokal tetapi tidak di production. - Menyimpan file ke disk
localtetapi mengakses seolah-olah diskpublic. - Menggunakan
asset($path)untuk path storage tanpa prefixstorage/. - Permission file benar, tetapi permission folder parent salah.
- Owner berubah setelah deploy, rsync, atau extract archive.
- Config sudah diperbaiki, tetapi cache config belum dibersihkan.
- Document root web server tidak menunjuk ke folder
public.
Poin terakhir penting. Jika Nginx atau Apache diarahkan ke root project alih-alih folder public, perilaku akses file bisa membingungkan dan berisiko secara keamanan.
Penutup: mulai dari path fisik, lalu naik ke URL publik
Saat menghadapi file Laravel yang error 403 atau 404 di production, pendekatan terbaik adalah memeriksa alurnya dari bawah ke atas: apakah file fisik ada, apakah symlink benar, apakah permission dan owner sesuai, apakah disk public terkonfigurasi benar, lalu apakah URL yang dibangun aplikasi memang tepat.
Dalam praktik sehari-hari, sebagian besar kasus selesai dengan tiga tindakan: buat ulang storage:link, benahi owner/permission, dan pastikan view menggunakan Storage::url() atau asset('storage/...') yang benar. Jika setelah itu masih gagal, barulah lanjut memeriksa konfigurasi web server, cache aplikasi, dan struktur deployment.
Intinya, error 403 atau 404 pada file storage Laravel hampir selalu bisa dilokalisasi dengan cepat jika Anda memisahkan masalah menjadi tiga lapisan: penyimpanan file, eksposur ke public path, dan URL akses dari aplikasi.
Komentar
0 komentar
Masuk ke akun kamu untuk ikut berkomentar.
Belum ada komentar
Jadilah yang pertama ikut berdiskusi!