Aplikasi berjalan lancar di laptop, lalu begitu diunggah ke server muncul halaman putih, error 500, atau lebih buruk lagi: halaman error yang menampilkan password database ke semua pengunjung. Hampir semua insiden seperti ini bukan karena kodenya rusak, melainkan karena ada langkah persiapan yang terlewat.
Artikel ini adalah checklist yang bisa Anda pakai setiap kali deploy source code Laravel, baik aplikasi buatan sendiri maupun source code yang Anda beli. Urutannya mengikuti alur kerja nyata: sebelum upload, saat deploy, dan setelah aplikasi online.
Kenapa Lokal dan Produksi Sering Berbeda
Komputer lokal biasanya punya PHP versi terbaru, semua ekstensi aktif, mode debug menyala, dan Anda login sebagai pemilik semua folder. Server produksi sering kebalikannya: versi PHP bisa berbeda, beberapa ekstensi tidak terpasang, dan web server berjalan sebagai user lain dengan hak akses terbatas. Perbedaan inilah sumber mayoritas masalah.
| Aspek | Lokal (development) | Produksi |
|---|---|---|
| APP_ENV | local | production |
| APP_DEBUG | true | false, wajib |
| Dependency | termasuk paket dev (Pint, Pest, Debugbar) | tanpa paket dev (--no-dev) |
| Cache config/route/view | biasanya tidak dipakai | dipakai agar lebih cepat |
| Error | ditampilkan di browser | dicatat ke log, pengguna melihat halaman umum |
| HTTPS | opsional | wajib |
Tahap 1: Sebelum Upload
Cocokkan versi PHP dan ekstensi
Laravel 11 membutuhkan PHP 8.2 atau lebih baru. Cek juga ekstensi yang umum dibutuhkan: pdo_mysql, mbstring, openssl, tokenizer, xml, ctype, fileinfo, dan bcmath bila aplikasi menghitung uang. Jalankan php -v dan php -m di server (atau lihat menu PHP Selector di cPanel) lalu bandingkan dengan isi composer.json.
Siapkan file .env produksi
Jangan menyalin .env lokal begitu saja. Buat file baru dari .env.example dan isi nilai produksi. Contoh minimal:
APP_NAME="Toko Saya"
APP_ENV=production
APP_DEBUG=false
APP_URL=https://tokosaya.com
LOG_CHANNEL=daily
LOG_LEVEL=warning
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_DATABASE=tokosaya_prod
DB_USERNAME=tokosaya_app
DB_PASSWORD=isi-password-kuat-di-sini
SESSION_DRIVER=database
SESSION_SECURE_COOKIE=true
QUEUE_CONNECTION=database
Alasan tiap baris penting: APP_DEBUG=false mencegah stack trace dan isi variabel environment tampil ke publik. APP_URL yang benar memastikan link di email, redirect, dan asset tidak mengarah ke localhost. SESSION_SECURE_COOKIE=true membuat cookie sesi hanya dikirim lewat HTTPS. Setelah file siap, buat APP_KEY sekali saja dengan php artisan key:generate. Jangan generate ulang di server yang sudah berjalan, karena data terenkripsi dan sesi lama akan tidak terbaca.
Gunakan user database terpisah
Jangan pakai user root untuk aplikasi. Buat user khusus yang hanya punya akses ke satu database. Jika suatu saat ada celah SQL injection, kerusakan terbatas pada database itu saja.
Tahap 2: Saat Deploy
Berikut urutan perintah yang umum untuk server dengan akses SSH. Simpan sebagai skrip agar setiap deploy dilakukan dengan cara yang sama:
#!/bin/bash
set -e
php artisan down --retry=60
git pull origin main
composer install --no-dev --optimize-autoloader --no-interaction
php artisan migrate --force
php artisan config:cache
php artisan route:cache
php artisan view:cache
php artisan event:cache
php artisan storage:link || true
php artisan queue:restart
php artisan up
- php artisan down menampilkan halaman maintenance agar pengguna tidak melihat aplikasi dalam kondisi setengah terpasang.
- composer install --no-dev memasang dependency sesuai
composer.locktanpa paket development. Jangan jalankancomposer updatedi produksi, karena bisa menaikkan versi paket yang belum Anda uji. - migrate --force diperlukan karena Laravel meminta konfirmasi saat migrasi di environment production.
- config:cache dan route:cache menggabungkan konfigurasi dan rute ke satu file sehingga boot aplikasi lebih cepat.
- queue:restart memberi tahu worker untuk memuat kode baru. Tanpa ini, worker lama tetap menjalankan kode versi sebelumnya.
Catatan penting soal config:cache: setelah config di-cache, fungsi env() yang dipanggil di luar folder config/ akan mengembalikan null. Jika source code memanggil env('API_KEY') langsung di controller, pindahkan ke file config lalu panggil dengan config('services.x.key').
Jika Anda memakai shared hosting tanpa SSH, alurnya sedikit berbeda. Langkah lengkapnya dibahas di panduan deploy Laravel ke shared hosting.
Atur permission folder
Hanya storage/ dan bootstrap/cache/ yang perlu bisa ditulis oleh web server. Sisanya cukup dibaca. Contoh di server Linux dengan web server berjalan sebagai www-data:
sudo chown -R deploy:www-data /var/www/tokosaya
sudo find /var/www/tokosaya -type f -exec chmod 644 {} \;
sudo find /var/www/tokosaya -type d -exec chmod 755 {} \;
sudo chmod -R 775 /var/www/tokosaya/storage /var/www/tokosaya/bootstrap/cache
Hindari chmod 777. Itu memang menghilangkan error permission, tetapi juga membuka jalan bagi skrip lain di server untuk menulis ke folder Anda.
Pastikan document root mengarah ke folder public
Web server harus menunjuk ke public/, bukan ke root project. Jika root project yang terbuka, file seperti .env bisa diunduh langsung lewat browser. Uji dengan membuka https://domainanda.com/.env; hasil yang benar adalah 403 atau 404.
Tahap 3: Backup dan Rencana Rollback
Backup dibuat sebelum deploy, bukan setelah ada masalah. Minimal simpan dua hal: dump database dan salinan folder storage/app yang berisi file unggahan pengguna.
mysqldump -u tokosaya_app -p --single-transaction tokosaya_prod | gzip > backup_$(date +%F_%H%M).sql.gz
Rencana rollback cukup ditulis dalam beberapa baris: commit atau tag mana yang dianggap stabil, perintah untuk kembali ke sana, dan apakah migrasi baru bisa dibatalkan. Migrasi yang menghapus kolom tidak bisa dibatalkan tanpa backup, jadi untuk perubahan besar lebih aman memecahnya menjadi beberapa deploy. Pembahasan lebih dalam ada di artikel migrasi database yang aman di Laravel.
Tahap 4: Setelah Aplikasi Online
Jangan langsung membagikan link ke publik. Luangkan 15 sampai 30 menit untuk menguji alur kritis secara manual:
- Registrasi akun baru dan cek apakah email verifikasi terkirim.
- Login, logout, dan reset password.
- Satu transaksi lengkap: tambah ke keranjang, checkout, dan pembayaran (pakai mode sandbox jika ada).
- Upload file atau gambar, lalu pastikan bisa ditampilkan.
- Buka halaman admin dan satu laporan yang paling sering dipakai.
Setelah itu pantau storage/logs selama beberapa jam pertama. Error yang tidak muncul saat pengujian lokal, misalnya timeout ke API pihak ketiga, biasanya baru terlihat saat ada trafik nyata. Jika aplikasi memakai scheduler, pastikan cron sudah terpasang: * * * * * cd /var/www/tokosaya && php artisan schedule:run >> /dev/null 2>&1.
Error Umum dan Cara Memperbaikinya
| Gejala | Penyebab umum | Perbaikan |
|---|---|---|
| Error 500 tanpa pesan | storage tidak writable atau APP_KEY kosong | Perbaiki permission, isi APP_KEY, cek log |
| "No application encryption key" | APP_KEY belum dibuat | php artisan key:generate (hanya sekali) |
| Perubahan .env tidak berpengaruh | config masih ter-cache | php artisan config:clear lalu config:cache |
| CSS/JS tidak muncul | asset belum di-build atau APP_URL salah | npm run build di lokal, upload public/build, cek APP_URL |
| Gambar unggahan 404 | symlink storage belum dibuat | php artisan storage:link |
| Halaman 419 saat submit form | sesi atau cookie bermasalah di HTTPS | cek SESSION_DOMAIN dan SESSION_SECURE_COOKIE |
Checklist Ringkas Siap Cetak
- [ ] Versi PHP dan ekstensi server sesuai kebutuhan aplikasi
- [ ] .env produksi: APP_ENV=production, APP_DEBUG=false, APP_URL benar
- [ ] APP_KEY sudah ada dan tidak diganti
- [ ] User database khusus, bukan root
- [ ] Document root mengarah ke public/, .env tidak bisa diakses
- [ ] HTTPS aktif dan redirect dari HTTP
- [ ] Kredensial default (admin@admin, password demo) sudah diganti
- [ ] composer install --no-dev, lalu cache config/route/view
- [ ] Permission storage dan bootstrap/cache benar, tanpa 777
- [ ] Backup database dan storage/app sebelum migrate
- [ ] Cron scheduler dan queue worker berjalan
- [ ] Alur kritis diuji manual, log dipantau beberapa jam
Untuk pengecekan keamanan yang lebih lengkap, gunakan juga checklist keamanan dasar Laravel. Jika Anda memakai source code dari GudangCode, checklist ini tetap berlaku sama seperti untuk aplikasi Laravel lainnya.