Fix Laravel Storage Symlink pada Shared Hosting cPanel
Problem
Setelah deploy Laravel ke shared hosting cPanel, file berhasil ke-upload ke folder:
storage/app/public/profile-photos
Tapi ketika file tersebut mau diakses dari browser malah muncul error:
404 Not Found
atau:
403 Forbidden
Contoh URL file yang mau diakses:
https://employee.example.my.id/storage/profile-photos/example.jpg
Padahal kalo dicek dari server, file-nya memang ada.
Root Cause
Pada kasus ini, project Laravel gw berada di folder:
/home/USER/repositories/employee
Sedangkan document root domain berada di:
/home/USER/employee.example.my.id
Jadi struktur foldernya kurang lebih seperti ini:
/home/USER/
├── repositories/
│ └── employee/
│
└── employee.example.my.id/
Normalnya Laravel menggunakan:
php artisan storage:link
untuk membuat symlink:
public/storage -> storage/app/public
Masalahnya, document root domain yang digunakan bukan folder:
/home/USER/repositories/employee/public
melainkan:
/home/USER/employee.example.my.id
Jadi symlink storage harus dibuat di document root yang memang diakses oleh domain tersebut.
Selain itu, APP_URL juga harus menggunakan protocol lengkap.
Salah:
APP_URL=employee.example.my.id
Benar:
APP_URL=https://employee.example.my.id
APP_URL ini lebih berpengaruh ke URL yang di-generate Laravel. Jadi kalau URL asset atau URL storage yang dihasilkan masih belum sesuai, bagian ini juga perlu diperbaiki.
Solution
1. Cek symlink yang sekarang
Sebelum ngapus apa pun, cek dulu isi document root:
ls -la ~/employee.example.my.id/
Kalo ternyata ada:
storage -> /path/yang/salah
berarti ada symlink storage yang perlu diperbaiki.
Kalau memang symlink tersebut salah, hapus symlink-nya:
unlink ~/employee.example.my.id/storage
Jangan langsung
rm -rfkalau belum yakinstoragetersebut adalah symlink. Cek dulu supaya nggak salah hapus folder.
2. Buat symlink baru
Sekarang kita buat symlink dari:
/home/USER/repositories/employee/storage/app/public
ke document root domain:
/home/USER/employee.example.my.id/storage
Jalankan:
ln -s ~/repositories/employee/storage/app/public ~/employee.example.my.id/storage
Kemudian cek lagi:
ls -la ~/employee.example.my.id/
Harusnya kurang lebih muncul:
storage -> /home/USER/repositories/employee/storage/app/public
Dengan begitu ketika browser mengakses:
/storage/profile-photos/example.jpg
file tersebut sebenarnya akan diarahkan ke:
/home/USER/repositories/employee/storage/app/public/profile-photos/example.jpg
3. Perbaiki APP_URL
Sekarang buka file .env Laravel.
Kalau sebelumnya:
APP_URL=employee.example.my.id
ubah menjadi:
APP_URL=https://employee.example.my.id
Jangan lupa save.
4. Clear Cache Laravel
Setelah .env diubah, clear cache Laravel:
php artisan optimize:clear
Sebenarnya perintah ini sudah cukup buat membersihkan cache Laravel.
Kalau mau menjalankannya secara terpisah juga bisa:
php artisan config:clear
php artisan view:clear
Tapi sebenarnya nggak wajib kalau sebelumnya sudah menjalankan:
php artisan optimize:clear
Kalau memang membutuhkan config cache untuk production, bisa dilanjutkan:
php artisan config:cache
5. Pastikan File Storage Memang Ada
Sebelum nyalahin cPanel, Laravel, atau semesta, cek dulu file-nya memang ada atau engga wkwk.
Jalankan:
find ~/repositories/employee/storage -type f | grep profile-photos
Contoh output:
/home/USER/repositories/employee/storage/app/public/profile-photos/example.jpg
Kalau file muncul, berarti proses upload sebenarnya sudah berhasil.
Masalahnya tinggal bagaimana file tersebut bisa diakses melalui document root domain.
6. Test Akses File
Sekarang coba buka:
https://employee.example.my.id/storage/profile-photos/example.jpg
Kalau symlink sudah benar dan permission-nya aman, file harusnya sudah bisa tampil di browser.
Kalau Masih Muncul 403
Kalau setelah symlink dibuat masih muncul:
403 Forbidden
berarti masalahnya belum tentu ada di symlink.
Bisa saja masalahnya ada di permission file atau folder.
Coba cek:
ls -la ~/repositories/employee/storage/app/public/
Kemudian:
ls -la ~/repositories/employee/storage/app/public/profile-photos/
Pastikan web server punya permission untuk membaca directory dan file tersebut.
Jadi jangan langsung menyimpulkan:
403 = symlink salah
Karena symlink yang benar pun tetap bisa menghasilkan 403 kalau permission filesystem-nya bermasalah.
Result
Setelah konfigurasi diperbaiki:
- Upload profile photo berhasil.
- File tetap disimpan di
storage/app/public. - Folder storage bisa diakses melalui document root domain.
- URL
/storage/...bisa digunakan untuk mengakses file. - URL yang di-generate Laravel menggunakan domain dan protocol yang benar.
- Upload berikutnya nggak perlu bikin symlink lagi karena konfigurasi document root-nya sudah benar.
Final Structure
Struktur akhirnya kurang lebih seperti ini:
/home/USER/
├── repositories/
│ └── employee/
│ └── storage/
│ └── app/
│ └── public/
│ └── profile-photos/
│ └── example.jpg
│
└── employee.example.my.id/
└── storage -> /home/USER/repositories/employee/storage/app/public
Jadi ketika browser membuka:
https://employee.example.my.id/storage/profile-photos/example.jpg
alur sederhananya:
Browser
│
▼
employee.example.my.id/storage/
│
▼
/home/USER/employee.example.my.id/storage
│
│ symlink
▼
/home/USER/repositories/employee/storage/app/public
│
▼
profile-photos/example.jpg
Dengan begitu Laravel tetap menyimpan file di:
storage/app/public
sedangkan document root domain tetap berada di:
employee.example.my.id
dan keduanya dihubungkan menggunakan symlink.